配置项发生改变时保持程序状态

在我们进行Android项目开发时,经常会遇到一个问题,如何保持程序的一些运行状态。比如当前的Activity正在下载一张图片,突然设备横竖屏切换(Activity会重新create),之前的下载线程可能并没有完成,这时如何来复用之前的下载线程呢,这是就需要把之前的下载线程保存起来

 
     Android SDK对这种功能提供了支持,API 13之前可以通过 getLastNonConfigurationInstance()   获得保存的对象实例通 onRetainNonConfigurationInstance ()   回调方法来保存一个对象实例,但这种机制在API 13被废弃了,下面是一个demo
 
package de.vogella.android.threadslifecycle;

import java.io.IOException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.ImageView;

public class ThreadsLifecycleActivity extends Activity {
  // Static so that the thread access the latest attribute
  private static ProgressDialog dialog;
  private static Bitmap downloadBitmap;
  private static Handler handler;
  private ImageView imageView;
  private Thread downloadThread;

  

/** Called when the activity is first created. */

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    // Create a handler to update the UI
    handler = new Handler() {
      @Override
      public void handleMessage(Message msg) {
        imageView.setImageBitmap(downloadBitmap);
        dialog.dismiss();
      }

    };
    // get the latest imageView after restart of the application
    imageView = (ImageView) findViewById(R.id.imageView1);
    Context context = imageView.getContext();
    System.out.println(context);
    // Did we already download the image?
    if (downloadBitmap != null) {
      imageView.setImageBitmap(downloadBitmap);
    }
    // Check if the thread is already running
    downloadThread = (Thread) getLastNonConfigurationInstance();
    if (downloadThread != null && downloadThread.isAlive()) {
      dialog = ProgressDialog.show(this, "Download", "downloading");
    }
  }

  public void resetPicture(View view) {
    if (downloadBitmap != null) {
      downloadBitmap = null;
    }
    imageView.setImageResource(R.drawable.icon);
  }

  public void downloadPicture(View view) {
    dialog = ProgressDialog.show(this, "Download", "downloading");
    downloadThread = new MyThread();
    downloadThread.start();
  }

  // Save the thread
  @Override
  public Object onRetainNonConfigurationInstance() {
    return downloadThread;
  }

  // dismiss dialog if activity is destroyed
  @Override
  protected void onDestroy() {
    if (dialog != null && dialog.isShowing()) {
      dialog.dismiss();
      dialog = null;
    }
    super.onDestroy();
  }

  // Utiliy method to download image from the internet
  static private Bitmap downloadBitmap(String url) throws IOException {
    HttpUriRequest request = new HttpGet(url);
    HttpClient httpClient = new DefaultHttpClient();
    HttpResponse response = httpClient.execute(request);

    StatusLine statusLine = response.getStatusLine();
    int statusCode = statusLine.getStatusCode();
    if (statusCode == 200) {
      HttpEntity entity = response.getEntity();
      byte[] bytes = EntityUtils.toByteArray(entity);

      Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0,
          bytes.length);
      return bitmap;
    } else {
      throw new IOException("Download failed, HTTP response code "
          + statusCode + " - " + statusLine.getReasonPhrase());
    }
  }

  static public class MyThread extends Thread {
    @Override
    public void run() {
      try {
        // Simulate a slow network
        try {
          new Thread().sleep(5000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        downloadBitmap = downloadBitmap("http://www.devoxx.com/download/attachments/4751369/DV11");
        // Updates the user interface
        handler.sendEmptyMessage(0);
      } catch (IOException e) {
        e.printStackTrace();
      } finally {

      }
    }
  }

} 

在模拟器中可以通过ctrl+11来看效果,以上代码可以在  http://www.vogella.com/articles/AndroidBackgroundProcessing/article.html#fragmentsandbackgroundprocessing  上找到

     API 13 推荐使用Fragment来替代,通过设置 setRetainInstance(   true  );  使Fragment在设备配置改变后(比如横竖屏切换)Activity重新创建时还能够获取到,具体介绍可以去看下Fragment的说明 ,下面是一个简单的实现(代码提取自BitmapFun项目)
package com.activity.lifecycle.threads;

import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.os.Build;
import android.os.Bundle;
import android.widget.TextView;

public class TestActivity extends Activity {

        private static final String TAG = "TestActivity" ;
       
        @TargetApi (Build.VERSION_CODES. HONEYCOMB)
        @Override
        protected void onCreate(Bundle savedInstanceState) {
              super .onCreate(savedInstanceState);
             
             TextView tv = new TextView( this);
             tv.setText( "this is the second activity" );
             setContentView(tv);
             
        // Search for, or create an instance of the non-UI RetainFragment
        final RetainFragment mRetainFragment = findOrCreateRetainFragment(getFragmentManager());

        // See if we already have an ImageCache stored in RetainFragment
        Thread thread = (Thread) mRetainFragment.getObject();

//         No existing ImageCache, create one and store it in RetainFragment
        if (thread == null) {
             thread = new Thread() ;
            mRetainFragment.setObject(thread);
        }
             
        // TODO
       }

    /**
     * Locate an existing instance of this Fragment or if not found, create and
     * add it using FragmentManager.
     *
     * @param fm The FragmentManager manager to use.
     * @return The existing instance of the Fragment or the new instance if just
     *         created.
     */
        @TargetApi (Build.VERSION_CODES. HONEYCOMB)
        private static RetainFragment findOrCreateRetainFragment(FragmentManager fm) {
        // Check to see if we have retained the worker fragment.
        RetainFragment mRetainFragment = (RetainFragment)fm.findFragmentByTag(TAG );

        // If not retained (or first time running), we need to create and add it.
        if (mRetainFragment == null) {
            mRetainFragment = new RetainFragment();
            fm.beginTransaction().add(mRetainFragment, TAG ).commitAllowingStateLoss();
        }

        return mRetainFragment;
    }
   
    /**
     * A simple non - UI Fragment that stores a single Object and is retained over configuration
     * changes. It will be used to retain the ImageCache object.
     */
    public static class RetainFragment extends Fragment {
        private Object mObject ;

        /**
         * Empty constructor as per the Fragment documentation
         */
        public RetainFragment() {}

        @TargetApi (Build.VERSION_CODES. HONEYCOMB)
              @Override
        public void onCreate(Bundle savedInstanceState) {
            super .onCreate(savedInstanceState);

            // Make sure this Fragment is retained over a configuration change
            setRetainInstance( true );
        }

        /**
         * Store a single object in this Fragment.
         *
         * @param object The object to store
         */
        public void setObject(Object object) {
            mObject = object;
        }

        /**
         * Get the stored object.
         *
         * @return The stored object
         */
        public Object getObject() {
            return mObject ;
        }
    }
}

因为API 13才开始提供,所以之前的版本可以使用Android提供的兼容包来支持







 

posted @ 2013-07-09 15:35  坚固66  阅读(281)  评论(0编辑  收藏  举报