I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Commit c42dc725 authored by str4d's avatar str4d
Browse files

Migrated LogFragment to use loader

parent 83ab1d09
No related branches found
No related tags found
No related merge requests found
package net.i2p.android.router.adapter;
import java.util.List;
import net.i2p.android.router.R;
import android.content.Context;
import android.widget.ArrayAdapter;
public class LogAdapter extends ArrayAdapter<String> {
public LogAdapter(Context context) {
super(context, R.layout.logs_list_item);
}
public void setData(List<String> entries) {
clear();
if (entries != null) {
for (String entry : entries) {
add(entry);
}
}
}
}
package net.i2p.android.router.fragment;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.ListFragment;
import android.widget.ArrayAdapter;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
import java.util.Collections;
import java.util.List;
import net.i2p.I2PAppContext;
import net.i2p.android.router.R;
import net.i2p.android.router.adapter.LogAdapter;
import net.i2p.android.router.loader.LogLoader;
public class LogFragment extends ListFragment {
public class LogFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<List<String>> {
public static final String LOG_LEVEL = "log_level";
/**
* The serialization (saved instance state) Bundle key representing the
* activated item position. Only used on tablets.
*/
private static final String STATE_ACTIVATED_POSITION = "activated_position";
String _logLevel;
private Handler _handler;
private Runnable _updater;
private ArrayAdapter<String> _adap;
private TextView _headerView;
private static final int LEVEL_ERROR = 1;
private static final int LEVEL_ALL = 2;
public static final String LOG_LEVEL = "log_level";
private static final int MAX = 250;
private LogAdapter mAdapter;
private TextView mHeaderView;
private String mLogLevel;
/**
* The current activated item position. Only used on tablets.
*/
private int mActivatedPosition = ListView.INVALID_POSITION;
private boolean mActivateOnItemClick = false;
public static LogFragment newInstance(String level) {
LogFragment f = new LogFragment();
......@@ -30,107 +42,75 @@ public class LogFragment extends ListFragment {
return f;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Restore the previously serialized activated item position.
if (savedInstanceState != null
&& savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
setActivatedPosition(savedInstanceState
.getInt(STATE_ACTIVATED_POSITION));
}
// When setting CHOICE_MODE_SINGLE, ListView will automatically
// give items the 'activated' state when touched.
getListView().setChoiceMode(
mActivateOnItemClick ? ListView.CHOICE_MODE_SINGLE
: ListView.CHOICE_MODE_NONE);
}
@Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
mAdapter = new LogAdapter(getActivity());
mLogLevel = getArguments().getString(LOG_LEVEL);
// set the header
mHeaderView = (TextView) getActivity().getLayoutInflater().inflate(R.layout.logs_header, null);
getListView().addHeaderView(mHeaderView, "", false);
setListAdapter(mAdapter);
// Grab context if router has started, otherwise create new
// FIXME dup contexts, locking, ...
List<String> msgs;
String header;
I2PAppContext ctx = I2PAppContext.getCurrentContext();
if (ctx != null) {
Bundle args = getArguments();
_logLevel = args.getString(LOG_LEVEL);
if ("ERROR".equals(_logLevel)) {
msgs = ctx.logManager().getBuffer().getMostRecentCriticalMessages();
} else {
msgs = ctx.logManager().getBuffer().getMostRecentMessages();
}
int sz = msgs.size();
header = getHeader(sz, ("ERROR".equals(_logLevel)));
if (sz > 1) {
Collections.reverse(msgs);
}
} else {
//msgs = Collections.EMPTY_LIST;
msgs = Collections.emptyList();
header = "No messages, router has not started yet.";
}
// set the header
_headerView = (TextView) getActivity().getLayoutInflater().inflate(R.layout.logs_header, null);
_headerView.setText(header);
ListView lv = getListView();
lv.addHeaderView(_headerView, "", false);
_adap = new ArrayAdapter<String>(getActivity(), R.layout.logs_list_item, msgs);
setListAdapter(_adap);
/***
// set the callback
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView parent, View view, int pos, long id) {
// make it bigger or something
}
});
***/
setEmptyText("ERROR".equals(mLogLevel) ?
"No error messages" : "No messages");
_handler = new Handler();
_updater = new Updater();
setListShown(false);
getLoaderManager().initLoader("ERROR".equals(mLogLevel) ?
LEVEL_ERROR : LEVEL_ALL, null, this);
} else
setEmptyText(getResources().getString(
R.string.router_not_running));
}
@Override
public void onStart() {
super.onStart();
_handler.removeCallbacks(_updater);
_handler.postDelayed(_updater, 10*1000);
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mActivatedPosition != ListView.INVALID_POSITION) {
// Serialize and persist the activated item position.
outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
}
}
@Override
public void onStop() {
super.onStop();
_handler.removeCallbacks(_updater);
/**
* Turns on activate-on-click mode. When this mode is on, list items will be
* given the 'activated' state when touched.
*/
public void setActivateOnItemClick(boolean activateOnItemClick) {
mActivateOnItemClick = activateOnItemClick;
}
private class Updater implements Runnable {
public void run() {
I2PAppContext ctx = I2PAppContext.getCurrentContext();
if (ctx != null) {
List<String> msgs;
if ("ERROR".equals(_logLevel)) {
msgs = ctx.logManager().getBuffer().getMostRecentCriticalMessages();
} else {
msgs = ctx.logManager().getBuffer().getMostRecentMessages();
}
int sz = msgs.size();
if (sz > 0) {
Collections.reverse(msgs);
String oldNewest = _adap.getCount() > 0 ? _adap.getItem(0) : null;
boolean changed = false;
for (int i = 0; i < sz; i++) {
String newItem = msgs.get(i);
if (newItem.equals(oldNewest))
break;
_adap.insert(newItem, i);
changed = true;
}
int newSz = _adap.getCount();
for (int i = newSz - 1; i > MAX; i--) {
_adap.remove(_adap.getItem(i));
}
if (changed) {
// fixme update header
newSz = _adap.getCount();
String header = getHeader(newSz, (_logLevel == "ERROR"));
_headerView.setText(header);
_adap.notifyDataSetChanged();
}
}
}
// LogWriter only processes queue every 10 seconds
_handler.postDelayed(this, 10*1000);
private void setActivatedPosition(int position) {
if (position == ListView.INVALID_POSITION) {
getListView().setItemChecked(mActivatedPosition, false);
} else {
getListView().setItemChecked(position, true);
}
mActivatedPosition = position;
}
/** fixme plurals */
......@@ -148,4 +128,34 @@ public class LogFragment extends ListFragment {
return "1 message";
return sz + " messages, newest first";
}
// LoaderManager.LoaderCallbacks<List<String>>
public Loader<List<String>> onCreateLoader(int id, Bundle args) {
return new LogLoader(getActivity(),
I2PAppContext.getCurrentContext(), mLogLevel);
}
public void onLoadFinished(Loader<List<String>> loader,
List<String> data) {
if (loader.getId() == ("ERROR".equals(mLogLevel) ?
LEVEL_ERROR : LEVEL_ALL)) {
mAdapter.setData(data);
String header = getHeader(data.size(), (mLogLevel == "ERROR"));
mHeaderView.setText(header);
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
}
public void onLoaderReset(Loader<List<String>> loader) {
if (loader.getId() == ("ERROR".equals(mLogLevel) ?
LEVEL_ERROR : LEVEL_ALL)) {
mAdapter.setData(null);
}
}
}
package net.i2p.android.router.loader;
import java.util.Collections;
import java.util.List;
import net.i2p.I2PAppContext;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
public class LogLoader extends AsyncTaskLoader<List<String>> {
private I2PAppContext mCtx;
private String mLogLevel;
private List<String> mData;
private static final int MAX_LOG_LENGTH = 250;
public LogLoader(Context context, I2PAppContext ctx, String logLevel) {
super(context);
mCtx = ctx;
mLogLevel = logLevel;
}
@Override
public List<String> loadInBackground() {
List<String> msgs;
if ("ERROR".equals(mLogLevel)) {
msgs = mCtx.logManager().getBuffer().getMostRecentCriticalMessages();
} else {
msgs = mCtx.logManager().getBuffer().getMostRecentMessages();
}
int sz = msgs.size();
if (sz > 1)
Collections.reverse(msgs);
if (sz > 0 && mData != null) {
String oldNewest = mData.size() > 0 ? mData.get(0) : null;
for (int i = 0; i < sz; i++) {
String newItem = msgs.get(i);
if (newItem.equals(oldNewest))
break;
mData.add(i, newItem);
}
int newSz = mData.size();
for (int i = newSz - 1; i > MAX_LOG_LENGTH; i--) {
mData.remove(i);
}
}
return msgs;
}
@Override
public void deliverResult(List<String> data) {
if (isReset()) {
// The Loader has been reset; ignore the result and invalidate the data.
if (data != null) {
releaseResources(data);
return;
}
}
// Hold a reference to the old data so it doesn't get garbage collected.
// We must protect it until the new data has been delivered.
List<String> oldData = mData;
mData = data;
if (isStarted()) {
// If the Loader is in a started state, have the superclass deliver the
// results to the client.
super.deliverResult(data);
}
// Invalidate the old data as we don't need it any more.
if (oldData != null && oldData != data) {
releaseResources(oldData);
}
}
@Override
protected void onStartLoading() {
if (mData != null) {
// Deliver any previously loaded data immediately.
deliverResult(mData);
}
if (takeContentChanged() || mData == null) {
// When the observer detects a change, it should call onContentChanged()
// on the Loader, which will cause the next call to takeContentChanged()
// to return true. If this is ever the case (or if the current data is
// null), we force a new load.
forceLoad();
}
}
@Override
protected void onStopLoading() {
// The Loader is in a stopped state, so we should attempt to cancel the
// current load (if there is one).
cancelLoad();
// Note that we leave the observer as is. Loaders in a stopped state
// should still monitor the data source for changes so that the Loader
// will know to force a new load if it is ever started again.
}
@Override
protected void onReset() {
// Ensure the loader has been stopped.
onStopLoading();
// At this point we can release the resources associated with 'mData'.
if (mData != null) {
releaseResources(mData);
mData = null;
}
}
@Override
public void onCanceled(List<String> data) {
// Attempt to cancel the current asynchronous load.
super.onCanceled(data);
// The load has been canceled, so we should release the resources
// associated with 'data'.
releaseResources(data);
}
private void releaseResources(List<String> data) {
// For a simple List, there is nothing to do. For something like a Cursor, we
// would close it in this method. All resources associated with the Loader
// should be released here.
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment