现在的位置: 首页 > 综合 > 正文

android in practice_Preparing for configuration changes(MyMovies project)

2018年04月13日 ⁄ 综合 ⁄ 共 2857字 ⁄ 字号 评论关闭

Any configuration change will terminate the currently visible Activity and restart it using the new system configuration, so always be prepared for interruptions.

You need to perform tasks asynchronously and want to ensure that a worker thread always sees a valid instance of the Activity that created it, even if that Activity has
been destroyed.

Our idea is as follows: we’ll keep a reference to an Activity in the worker class, but we’ll make sure to reset it whenever that Activity instance changes due to a configuration

the Activity manages the worker instance it’s hosting.the worker manages the activity instace too.

Gracefully managing worker threads across configuration changes:

public class WorkerActivity extends Activity {
	   private Worker worker;
	   @Override
	   public void onCreate(Bundle savedInstanceState) {
	      super.onCreate(savedInstanceState);
	      setContentView(R.layout.activity_main);
	      //check whether a worker object is being passed from a previous instance of this Activity class
	      worker=(Worker)getLastNonConfigurationInstance();
	      //if worker is not retained,create new one
	      if(worker==null){
	    	  worker=new Worker();
	    	  worker.execute();
	      }
	      worker.connectContext(this);//bind current activity
	   }
	   
	   @Override
	   protected void onDestroy() {
	      super.onDestroy();
	      worker.disconnectContext();//unbind current activity
	   }

	   //pass worker to next activity
	   @Override
	   public Object onRetainNonConfigurationInstance() {
	      return worker;
	   }
}

Worker implementation that can (dis)connect its hosting Activity:

/*
 * keep a reference to an Activity, making sure that its
   hosting Activity can bind to the worker B and release itself
 */
public class Worker  extends AsyncTask<Void, Void, String> {
	   private Activity context;
	   //bind new activity instance
	   public void connectContext(Activity context) {
	      this.context = context;
	   }
	   //release current activity instance
	   public void disconnectContext() {
	      this.context = null;
	   }

	@Override
	protected String doInBackground(Void... params) {
		// TODO Auto-generated method stub
		    try {
			  Thread.sleep(3000);
			} catch (InterruptedException e) {
			}
		return "Work done!";
	}
	
	 //Only interact with UI if Activity is valid
	 protected void onPostExecute(String result) {
	      if (context != null) {
	    	  /*
	    	   * in cases where our Activity gets destroyed without being recreated, 
	    	   * as is the case when hitting the back button, or in out-of-memory situations.
	    	   */
	         Toast.makeText(context, result, Toast.LENGTH_LONG).show();
	      }
	   }
}

connect/disconnect pattern.One restriction our solution has is that it only works for activities. The Service class doesn’t define the onRetainNonConfigurationInstance method, so it can’t keep track of task objects it hosts (at least not that way).

Another restriction is that you can’t use the Activity instance in doInBackground because that method doesn’t run on the UI thread, but the task thread, and it’s not
guaranteed that it will always see the correct Activity instance.

If you absolutely can’t live with these restrictions, we have good news as well. The ignition Android application library (http://github.com/kaeppler/ignition) defines an implementation of AsyncTask called IgnitedAsyncTask that allows you to run jobs that
are agnostic to the concrete type of their hosting Context, and which make sure
that in all three callback methods you’ll always see the correct context instance.

抱歉!评论已关闭.