From 59855f362c05752438f810a653afcfbf636481aa Mon Sep 17 00:00:00 2001 From: "Heiko W. Rupp" Date: Sun, 13 Oct 2013 21:22:44 +0200 Subject: [PATCH] Use loader and background service for loading of stuff. --- AndroidManifest.xml | 1 + src/de/bsd/zwitscher/MainActivity.java | 98 +++++++++++++++++++ src/de/bsd/zwitscher/TweetListFragment.java | 80 ++++++++++++--- .../helper/FetchTimelinesService.java | 96 ++++++++++++++++++ .../zwitscher/helper/StatusListLoader.java | 46 +++++++++ 5 files changed, 308 insertions(+), 13 deletions(-) create mode 100644 src/de/bsd/zwitscher/helper/FetchTimelinesService.java create mode 100644 src/de/bsd/zwitscher/helper/StatusListLoader.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index bc985ad..852b531 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -83,6 +83,7 @@ + diff --git a/src/de/bsd/zwitscher/MainActivity.java b/src/de/bsd/zwitscher/MainActivity.java index e3840ce..f91d841 100644 --- a/src/de/bsd/zwitscher/MainActivity.java +++ b/src/de/bsd/zwitscher/MainActivity.java @@ -8,16 +8,23 @@ import android.support.v4.app.ActionBarDrawerToggle; import android.support.v4.widget.DrawerLayout; import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.view.Window; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; +import android.widget.ProgressBar; import android.widget.SpinnerAdapter; import de.bsd.zwitscher.account.Account; import de.bsd.zwitscher.account.AccountHolder; import de.bsd.zwitscher.account.AccountNavigationListener; +import de.bsd.zwitscher.account.AccountStuffActivity; import de.bsd.zwitscher.account.LoginActivity; +import de.bsd.zwitscher.helper.CleanupTask; +import de.bsd.zwitscher.helper.FetchTimelinesService; import java.util.ArrayList; import java.util.List; @@ -35,6 +42,9 @@ public class MainActivity extends Activity { private List accountList; private DrawerLayout mDrawerLayout; private ActionBarDrawerToggle mDrawerToggle; + private ProgressBar progressItem; + private Menu menu; + private int listId; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -149,6 +159,7 @@ private class DrawerItemClickListener implements ListView.OnItemClickListener { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { ZUserList zul = (ZUserList) ((ListView)parent).getAdapter().getItem(position); + listId = zul.listId; selectItem(zul); } } @@ -176,4 +187,91 @@ private void selectItem(ZUserList zul) { mDrawerLayout.closeDrawer(mDrawerList); } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.main_menu, menu); + MenuItem item = menu.findItem(R.id.ProgressBar); + progressItem = (ProgressBar) item.getActionView(); + progressItem.setVisibility(ProgressBar.INVISIBLE); + + this.menu = menu; + + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + Intent i; + // Handle item selection + switch (item.getItemId()) { + case R.id.preferences: + i = new Intent(this, Preferences.class); + startActivity(i); + break; + case R.id.reloadLists: + // syncLists(); +// new SyncSLTask(this).execute(); + break; + case R.id.DevelResetLastRead: +// resetLastRead(); + break; + case R.id.DevelCleanTweets: +// cleanTweetDB(); + break; + case R.id.DevelCleanImages: +// cleanImages(); + break; + case R.id.AccountStuff: + i = new Intent(this, AccountStuffActivity.class); + startActivity(i); + break; + case R.id.helpMenu: + i = new Intent(MainActivity.this, HelpActivity.class); // TODO Fragment + startActivity(i); + break; + case R.id.menu_cleanTweets: + new CleanupTask(this).execute(); + break; + case R.id.DevelDumpAccounts: + TweetDB tmpDb = TweetDB.getInstance(getApplicationContext()); + List allAccounts = tmpDb.getAccountsForSelection(false); + for (Account a : allAccounts) + System.out.println(a); + break; + /// below are Honeycomb ActionBar items + case R.id.refresh: + // forward to the inner list's reload/referesh +// if (listActivity!=null) +// listActivity.reload(null); + Intent fetcher = new Intent(this, FetchTimelinesService.class); + fetcher.putExtra("account",account); + fetcher.putExtra("listIds",new int[] { listId}); + startService(fetcher); + break; + case R.id.send: + i = new Intent(this,NewTweetActivity.class); + startActivity(i); + break; + case R.id.to_top: +// if (listActivity!=null) +// listActivity.scrollToTop(null); + break; + case R.id.menu_feedback: +// send_feedback(); + break; + case R.id.menu_goto_user: +// displayUserInfo(); + break; + case R.id.menu_default_search: + onSearchRequested(); + break; + default: + System.out.println("Unknown option " + item.toString()); + return super.onOptionsItemSelected(item); + } + return true; + } + + } \ No newline at end of file diff --git a/src/de/bsd/zwitscher/TweetListFragment.java b/src/de/bsd/zwitscher/TweetListFragment.java index bd2b497..12387e4 100644 --- a/src/de/bsd/zwitscher/TweetListFragment.java +++ b/src/de/bsd/zwitscher/TweetListFragment.java @@ -2,17 +2,22 @@ import android.app.ListFragment; +import android.app.LoaderManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.Loader; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ListView; import de.bsd.zwitscher.account.Account; -import de.bsd.zwitscher.helper.MetaList; -import twitter4j.Paging; +import de.bsd.zwitscher.helper.StatusListLoader; import twitter4j.Status; import java.util.ArrayList; +import java.util.List; /** * Show the list of tweets. @@ -26,10 +31,14 @@ * * @author Heiko W. Rupp */ -public class TweetListFragment extends ListFragment { +public class TweetListFragment extends ListFragment implements LoaderManager.LoaderCallbacks> { + private static final String LOAD_DONE = "zwitscher.LoadDone"; + private TweetDB tweetDb; + private String tag; private int listId; private Account account; + private UpdateFinishReceiver receiver; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -38,28 +47,73 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa return view; } - void setListId(int listId) { - this.listId = listId; + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + tweetDb = TweetDB.getInstance(getActivity()); } @Override public void onActivityCreated(Bundle savedState) { - super.onActivityCreated(savedState); - ListView lv ; + IntentFilter filter = new IntentFilter(LOAD_DONE); + receiver = new UpdateFinishReceiver(); + getActivity().registerReceiver(receiver,filter); - TwitterHelper th = new TwitterHelper(getActivity(),account); - MetaList statuses = th.getTimeline(new Paging(), listId, true); - setListAdapter(new StatusAdapter(getActivity(), account, R.layout.tweet_list_item, statuses.getList(), 0, new ArrayList())); + // Prepare the loader. Either re-connect with an existing one, + // or start a new one. + Bundle loaderArgs = new Bundle(); + loaderArgs.putInt("listId", listId); + getLoaderManager().initLoader(0, loaderArgs, this); + getListView().setOverscrollHeader(getResources().getDrawable(R.drawable.ic_menu_top)); // TODO what icon? + getListView().setOverscrollFooter(getResources().getDrawable(R.drawable.ic_menu_share)); // TODO what icon? - lv = getListView(); - lv.setItemsCanFocus(false); + } + @Override + public void onDestroyView() { + super.onDestroyView(); + + getActivity().unregisterReceiver(receiver); + } + + @Override + public Loader> onCreateLoader(int id, Bundle args) { + return new StatusListLoader(getActivity(), account, listId); + } + + @Override + public void onLoadFinished(Loader> loader, List data) { + setListAdapter(new StatusAdapter(getActivity(), account,R.layout.tweet_list_item,data,-1,new ArrayList())); + } + + @Override + public void onLoaderReset(Loader> loader) { + // TODO: Customise this generated block } public void setAccount(Account account) { this.account = account; } + + void setListId(int listId) { + this.listId = listId; + } + + + private class UpdateFinishReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + int intentListId = intent.getIntExtra("listId",0); + if (intentListId == listId ) { + Bundle loaderArgs = new Bundle(); + loaderArgs.putInt("listId", listId); + getLoaderManager().restartLoader(0, loaderArgs, TweetListFragment.this); + } + } + } } diff --git a/src/de/bsd/zwitscher/helper/FetchTimelinesService.java b/src/de/bsd/zwitscher/helper/FetchTimelinesService.java new file mode 100644 index 0000000..3f4f461 --- /dev/null +++ b/src/de/bsd/zwitscher/helper/FetchTimelinesService.java @@ -0,0 +1,96 @@ +package de.bsd.zwitscher.helper; + +import android.app.IntentService; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import de.bsd.zwitscher.TweetDB; +import de.bsd.zwitscher.TwitterHelper; +import de.bsd.zwitscher.account.Account; +import twitter4j.Paging; +import twitter4j.Status; +import twitter4j.Twitter; +import twitter4j.TwitterException; + +import java.util.ArrayList; +import java.util.List; + +/** + * Intent service to fetch timeline data from the server and store it in the + * Database + * + * @author Heiko W. Rupp + */ +public class FetchTimelinesService extends IntentService { + + public FetchTimelinesService() { + super("FetchTimelinesService"); + } + + @Override + protected void onHandleIntent(Intent intent) { + + Bundle bundle = intent.getExtras(); + + int[] listIds = bundle.getIntArray("listIds"); + + if (listIds==null) { + Log.e("Fetcher","No listIds passed, returning"); + stopSelf(); + return; + } + Account account = bundle.getParcelable("account"); + int accountId = account.getId(); + + TwitterHelper th = new TwitterHelper(getApplicationContext(),account); + Twitter twitter = th.getTwitter(); + TweetDB tdb = TweetDB.getInstance(getApplicationContext()); + + + for (int listId : listIds ) { + List statuses; + long lastFetchedId = tdb.getLastFetched(accountId, listId); + Paging paging ; + if (lastFetchedId>0) + paging=new Paging(lastFetchedId); + else + paging=new Paging(1,200); + + try { + switch (listId) { + case 0: + statuses = twitter.getHomeTimeline(paging); + break; + case 1: + statuses = twitter.getMentionsTimeline(paging); + break; + case 2: + Log.w("Fetcher","Direct messages are not supported"); + statuses = new ArrayList(1); + break; + case 3: + statuses = twitter.getUserTimeline(paging); + break; + default: + statuses = twitter.getUserListStatuses(listId,paging); + } + if (statuses.size()>0) { + th.persistStatus(statuses, listId); + long newLast=-1; + // Update the 'since' id in the database + if (statuses.size()>0) { + newLast = statuses.get(0).getId(); // assumption is that twitter sends the newest (=highest id) first + tdb.updateOrInsertLastRead(accountId,listId,newLast); + Intent loadDone = new Intent("zwitscher.LoadDone"); + loadDone.putExtra("listId",listId); + sendBroadcast(loadDone); + } + } + } catch (TwitterException e) { + e.printStackTrace(); // TODO: Customise this generated block + } + } + + stopSelf(); + } +} diff --git a/src/de/bsd/zwitscher/helper/StatusListLoader.java b/src/de/bsd/zwitscher/helper/StatusListLoader.java new file mode 100644 index 0000000..07dbcf6 --- /dev/null +++ b/src/de/bsd/zwitscher/helper/StatusListLoader.java @@ -0,0 +1,46 @@ +package de.bsd.zwitscher.helper; + + +import android.content.AsyncTaskLoader; +import android.content.Context; +import de.bsd.zwitscher.TwitterHelper; +import de.bsd.zwitscher.account.Account; +import twitter4j.Status; + +import java.util.List; + +/** + * // TODO: Document this + * + * @author Heiko W. Rupp + */ +public class StatusListLoader extends AsyncTaskLoader> { + + private Account account; + private int listId; + private final TwitterHelper twitterHelper; + + public StatusListLoader(Context context, Account account, int listId) { + super(context); + this.account = account; + this.listId = listId; + twitterHelper = new TwitterHelper(context,account); + } + + + + @Override + public List loadInBackground() { + return twitterHelper.getStatuesFromDb(-1,20,listId); // TODO parametrize + } + + @Override + protected void onStartLoading() { + forceLoad(); + } + + @Override + protected void onStopLoading() { + cancelLoad(); + } +}