package com.octo.android.robospice.motivations.loader; import java.util.ArrayList; import java.util.List; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONTokener; import roboguice.inject.ContentView; import roboguice.inject.InjectView; import android.app.ActivityManager; import android.app.ActivityManager.MemoryInfo; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.Loader; import android.util.Log; import android.view.View; import android.view.Window; import android.webkit.WebView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import com.actionbarsherlock.view.Menu; import com.octo.android.robospice.motivations.R; import com.octo.android.robospice.motivations.common.BaseActivity; /** * A simple ListActivity that display Tweets that contain the word Android in them. * * @author Neil Goodman * */ @ContentView(R.layout.activity_tweet_demo) public class TwitterLoaderActivity extends BaseActivity implements LoaderCallbacks< RestLoader.RESTResponse > { private final static String BUNDLE_KEY_INDETERMINATE_PROGRESS_VISIBLE = "BUNDLE_KEY_INDETERMINATE_PROGRESS_VISIBLE"; private static final String TAG = TwitterLoaderActivity.class.getName(); private static final int LOADER_TWITTER_SEARCH = 0x1; private static final String ARGS_URI = "net.neilgoodman.android.restloadertutorial.ARGS_URI"; private static final String ARGS_PARAMS = "net.neilgoodman.android.restloadertutorial.ARGS_PARAMS"; private static final int SIZE_OF_BUFFER_SO_SIMULATE_OUT_OF_MEMORY = 1000000; private byte[] bufferToFillMemoryFaster = new byte[ SIZE_OF_BUFFER_SO_SIMULATE_OUT_OF_MEMORY ]; private ArrayAdapter< String > mAdapter; @InjectView(R.id.listView_tweets) private ListView listView; @InjectView(R.id.webView_explanation) protected WebView webViewExplanation; @InjectView(R.id.button_start) protected Button buttonStart; @InjectView(R.id.button_cancel) protected Button buttonCancel; @InjectView(R.id.textView_memory) protected TextView textViewMemory; @InjectView(R.id.checkbox_delay) private CheckBox checkBoxDelay; private static final int REQUEST_DELAY = 10 * 1000; private boolean taskProgressVisibility; @Override public void onCreate( Bundle savedInstanceState ) { requestWindowFeature( Window.FEATURE_INDETERMINATE_PROGRESS ); super.onCreate( savedInstanceState ); getSupportLoaderManager(); mAdapter = new ArrayAdapter< String >( this, R.layout.view_item_white ); // Let's set our list adapter to a simple ArrayAdapter. listView.setAdapter( mAdapter ); getSupportActionBar().setTitle( getDemoTitle() ); getSupportActionBar().setSubtitle( getDemoSubtitle() ); webViewExplanation.loadUrl( "file:///android_asset/" + getDemoExplanation() ); setTaskProgressVisible( savedInstanceState != null && savedInstanceState.getBoolean( BUNDLE_KEY_INDETERMINATE_PROGRESS_VISIBLE, false ) ); ActivityManager activityManager = (ActivityManager) getSystemService( ACTIVITY_SERVICE ); MemoryInfo mi = new MemoryInfo(); activityManager.getMemoryInfo( mi ); bufferToFillMemoryFaster = new byte[ (int) Math.max( mi.availMem / 100, SIZE_OF_BUFFER_SO_SIMULATE_OUT_OF_MEMORY ) ]; Log.v( getClass().getSimpleName(), "Keeping buffer in memory, size= " + bufferToFillMemoryFaster.length ); textViewMemory.setText( getString( R.string.text_available_memory, mi.availMem / 1024 ) ); startDemo(); } @Override protected void onSaveInstanceState( Bundle outState ) { outState.putBoolean( BUNDLE_KEY_INDETERMINATE_PROGRESS_VISIBLE, this.taskProgressVisibility ); super.onSaveInstanceState( outState ); } public void setTaskProgressVisible( boolean visible ) { setProgressBarIndeterminateVisibility( visible ); taskProgressVisibility = visible; } @Override public Loader< RestLoader.RESTResponse > onCreateLoader( int id, Bundle args ) { if ( args != null && args.containsKey( ARGS_URI ) && args.containsKey( ARGS_PARAMS ) ) { Uri action = args.getParcelable( ARGS_URI ); Bundle params = args.getParcelable( ARGS_PARAMS ); long delay = checkBoxDelay.isChecked() ? REQUEST_DELAY : 0; RestLoader loader = new RestLoader( this, RestLoader.HTTPVerb.GET, action, params ); loader.setDelay( delay ); setTaskProgressVisible( true ); return loader; } return null; } @Override public void onLoadFinished( Loader< RestLoader.RESTResponse > loader, RestLoader.RESTResponse data ) { setTaskProgressVisible( false ); int code = data.getCode(); String json = data.getData(); // Check to see if we got an HTTP 200 code and have some data. if ( code == 200 && !json.equals( "" ) ) { // For really complicated JSON decoding I usually do my heavy lifting // Gson and proper model classes, but for now let's keep it simple // and use a utility method that relies on some of the built in // JSON utilities on Android. List< String > tweets = getTweetsFromJson( json ); // Load our list adapter with our Tweets. mAdapter.clear(); for ( String tweet : tweets ) { mAdapter.add( tweet ); } } else { Toast.makeText( this, "Failed to load Twitter data. Check your internet settings.", Toast.LENGTH_SHORT ).show(); } } @Override public void onLoaderReset( Loader< RestLoader.RESTResponse > loader ) { setTaskProgressVisible( false ); } private static List< String > getTweetsFromJson( String json ) { ArrayList< String > tweetList = new ArrayList< String >(); try { JSONObject tweetsWrapper = (JSONObject) new JSONTokener( json ).nextValue(); JSONArray tweets = tweetsWrapper.getJSONArray( "results" ); for ( int i = 0; i < tweets.length(); i++ ) { JSONObject tweet = tweets.getJSONObject( i ); tweetList.add( tweet.getString( "text" ) ); } } catch ( JSONException e ) { Log.e( TAG, "Failed to parse JSON.", e ); } return tweetList; } @Override public boolean onCreateOptionsMenu( Menu menu ) { getSupportMenuInflater().inflate( R.menu.activity_demo, menu ); return true; } @Override public void onStartButtonClick( View v ) { startDemo(); } @Override public void onCancelButtonClick( View v ) { stopDemo(); } @Override public void startDemo() { // This is our REST action. Uri twitterSearchUri = Uri.parse( "http://search.twitter.com/search.json" ); // Here we are going to place our REST call parameters. Note that // we could have just used Uri.Builder and appendQueryParameter() // here, but I wanted to illustrate how to use the Bundle params. Bundle params = new Bundle(); params.putString( "q", "android" ); // These are the loader arguments. They are stored in a Bundle because // LoaderManager will maintain the state of our Loaders for us and // reload the Loader if necessary. This is the whole reason why // we have even bothered to implement RestLoader. Bundle args = new Bundle(); args.putParcelable( ARGS_URI, twitterSearchUri ); args.putParcelable( ARGS_PARAMS, params ); // Initialize the Loader. getSupportLoaderManager().initLoader( LOADER_TWITTER_SEARCH, args, this ); } @Override public void stopDemo() { getSupportLoaderManager().destroyLoader( LOADER_TWITTER_SEARCH ); } @Override public String getDemoTitle() { return getString( R.string.text_networking_example ); } @Override public String getDemoSubtitle() { return getString( R.string.text_loader_rest_name ); } @Override public String getDemoExplanation() { return "loader_rest.html"; } }