1、概述

众所周知,Activity在不明确指定屏幕方向和configChanges时,当用户旋转屏幕会重新启动。当然了,应对这种情况,Android给出了几种方案:

a、如果是少量数据,可以通过onSaveInstanceState()和onRestoreInstanceState()进行保存与恢复。

Android会在销毁你的Activity之前调用onSaveInstanceState()方法,于是,你可以在此方法中存储关于应用状态的数据。然后你可以在onCreate()或onRestoreInstanceState()方法中恢复。

b、如果是大量数据,使用Fragment保持需要恢复的对象。

c、自已处理配置变化。

注:getLastNonConfigurationInstance()已经被弃用,被上述方法二替代。

2、难点

假设当前Activity在onCreate中启动一个异步线程去夹在数据,当然为了给用户一个很好的体验,会有一个ProgressDialog,当数据加载完成,ProgressDialog消失,设置数据。

这里,如果在异步数据完成加载之后,旋转屏幕,使用上述a、b两种方法都不会很难,无非是保存数据和恢复数据。

但是,如果正在线程加载的时候,进行旋转,会存在以下问题:

a)此时数据没有完成加载,onCreate重新启动时,会再次启动线程;而上个线程可能还在运行,并且可能会更新已经不存在的控件,造成错误。

b)关闭ProgressDialog的代码在线程的onPostExecutez中,但是上个线程如果已经杀死,无法关闭之前ProgressDialog。

c)谷歌的官方不建议使用ProgressDialog,这里我们会使用官方推荐的DialogFragment来创建我的加载框,如果你不了解:请看Android 官方推荐 : DialogFragment 创建对话框。这样,其实给我们带来一个很大的问题,DialogFragment说白了是Fragment,和当前的Activity的生命周期会发生绑定,我们旋转屏幕会造成Activity的销毁,当然也会对DialogFragment造成影响。

下面我将使用几个例子,分别使用上面的3种方式,和如何最好的解决上述的问题。

3、使用onSaveInstanceState()和onRestoreInstanceState()进行数据保存与恢复

代码:

[java] view plain copy
  1. packagecom.example.zhy_handle_runtime_change;
  2. importjava.util.ArrayList;
  3. importjava.util.Arrays;
  4. importandroid.app.DialogFragment;
  5. importandroid.app.ListActivity;
  6. importandroid.os.AsyncTask;
  7. importandroid.os.Bundle;
  8. importandroid.util.Log;
  9. importandroid.widget.ArrayAdapter;
  10. importandroid.widget.ListAdapter;
  11. /**
  12. *不考虑加载时,进行旋转的情况,有意的避开这种情况,后面例子会介绍解决方案
  13. *@authorzhy
  14. *
  15. */
  16. publicclassSavedInstanceStateUsingActivityextendsListActivity
  17. {
  18. privatestaticfinalStringTAG="MainActivity";
  19. privateListAdaptermAdapter;
  20. privateArrayList<String>mDatas;
  21. privateDialogFragmentmLoadingDialog;
  22. privateLoadDataAsyncTaskmLoadDataAsyncTask;
  23. @Override
  24. publicvoidonCreate(BundlesavedInstanceState)
  25. {
  26. super.onCreate(savedInstanceState);
  27. Log.e(TAG,"onCreate");
  28. initData(savedInstanceState);
  29. }
  30. /**
  31. *初始化数据
  32. */
  33. privatevoidinitData(BundlesavedInstanceState)
  34. {
  35. if(savedInstanceState!=null)
  36. mDatas=savedInstanceState.getStringArrayList("mDatas");
  37. if(mDatas==null)
  38. {
  39. mLoadingDialog=newLoadingDialog();
  40. mLoadingDialog.show(getFragmentManager(),"LoadingDialog");
  41. mLoadDataAsyncTask=newLoadDataAsyncTask();
  42. mLoadDataAsyncTask.execute();
  43. }else
  44. {
  45. initAdapter();
  46. }
  47. }
  48. /**
  49. *初始化适配器
  50. */
  51. privatevoidinitAdapter()
  52. {
  53. mAdapter=newArrayAdapter<String>(
  54. SavedInstanceStateUsingActivity.this,
  55. android.R.layout.simple_list_item_1,mDatas);
  56. setListAdapter(mAdapter);
  57. }
  58. @Override
  59. protectedvoidonRestoreInstanceState(Bundlestate)
  60. {
  61. super.onRestoreInstanceState(state);
  62. Log.e(TAG,"onRestoreInstanceState");
  63. }
  64. @Override
  65. protectedvoidonSaveInstanceState(BundleoutState)
  66. {
  67. super.onSaveInstanceState(outState);
  68. Log.e(TAG,"onSaveInstanceState");
  69. outState.putSerializable("mDatas",mDatas);
  70. }
  71. /**
  72. *模拟耗时操作
  73. *
  74. *@return
  75. */
  76. privateArrayList<String>generateTimeConsumingDatas()
  77. {
  78. try
  79. {
  80. Thread.sleep(2000);
  81. }catch(InterruptedExceptione)
  82. {
  83. }
  84. returnnewArrayList<String>(Arrays.asList("通过Fragment保存大量数据",
  85. "onSaveInstanceState保存数据",
  86. "getLastNonConfigurationInstance已经被弃用","RabbitMQ","Hadoop",
  87. "Spark"));
  88. }
  89. privateclassLoadDataAsyncTaskextendsAsyncTask<Void,Void,Void>
  90. {
  91. @Override
  92. protectedVoiddoInBackground(Void...params)
  93. {
  94. mDatas=generateTimeConsumingDatas();
  95. returnnull;
  96. }
  97. @Override
  98. protectedvoidonPostExecute(Voidresult)
  99. {
  100. mLoadingDialog.dismiss();
  101. initAdapter();
  102. }
  103. }
  104. @Override
  105. protectedvoidonDestroy()
  106. {
  107. Log.e(TAG,"onDestroy");
  108. super.onDestroy();
  109. }
  110. }


界面为一个ListView,onCreate中启动一个异步任务去加载数据,这里使用Thread.sleep模拟了一个耗时操作;当用户旋转屏幕发生重新启动时,会onSaveInstanceState中进行数据的存储,在onCreate中对数据进行恢复,免去了不必要的再加载一遍。

运行结果:

当正常加载数据完成之后,用户不断进行旋转屏幕,log会不断打出:onSaveInstanceState->onDestroy->onCreate->onRestoreInstanceState,验证我们的确是重新启动了,但是我们没有再次去进行数据加载。

如果在加载的时候,进行旋转,则会发生错误,异常退出(退出原因:dialog.dismiss()时发生NullPointException,因为与当前对话框绑定的FragmentManager为null,又有兴趣的可以去Debug,这个不是关键)。

效果图:




4、使用Fragment来保存对象,用于恢复数据

如果重新启动你的Activity需要恢复大量的数据,重新建立网络连接,或者执行其他的密集型操作,这样因为配置发生变化而完全重新启动可能会是一个慢的用户体验。并且,使用系统提供的onSaveIntanceState()的回调中,使用Bundle来完全恢复你Activity的状态是可能是不现实的(Bundle不是设计用来携带大量数据的(例如bitmap),并且Bundle中的数据必须能够被序列化和反序列化),这样会消耗大量的内存和导致配置变化缓慢。在这样的情况下,当你的Activity因为配置发生改变而重启,你可以通过保持一个Fragment来缓解重新启动带来的负担。这个Fragment可以包含你想要保持的有状态的对象的引用。

当Android系统因为配置变化关闭你的Activity的时候,你的Activity中被标识保持的fragments不会被销毁。你可以在你的Activity中添加这样的fragements来保存有状态的对象。

在运行时配置发生变化时,在Fragment中保存有状态的对象
a) 继承Fragment,声明引用指向你的有状态的对象
b) 当Fragment创建时调用setRetainInstance(boolean)
c) 把Fragment实例添加到Activity中
d) 当Activity重新启动后,使用FragmentManager对Fragment进行恢复
代码:

首先是Fragment:

[java] view plain copy
  1. packagecom.example.zhy_handle_runtime_change;
  2. importandroid.app.Fragment;
  3. importandroid.graphics.Bitmap;
  4. importandroid.os.Bundle;
  5. publicclassRetainedFragmentextendsFragment
  6. {
  7. //dataobjectwewanttoretain
  8. privateBitmapdata;
  9. //thismethodisonlycalledonceforthisfragment
  10. @Override
  11. publicvoidonCreate(BundlesavedInstanceState)
  12. {
  13. super.onCreate(savedInstanceState);
  14. //retainthisfragment
  15. setRetainInstance(true);
  16. }
  17. publicvoidsetData(Bitmapdata)
  18. {
  19. this.data=data;
  20. }
  21. publicBitmapgetData()
  22. {
  23. returndata;
  24. }
  25. }

比较简单,只需要声明需要保存的数据对象,然后提供getter和setter,注意,一定要在onCreate调用setRetainInstance(true);

然后是:FragmentRetainDataActivity

[java] view plain copy
  1. packagecom.example.zhy_handle_runtime_change;
  2. importandroid.app.Activity;
  3. importandroid.app.DialogFragment;
  4. importandroid.app.FragmentManager;
  5. importandroid.graphics.Bitmap;
  6. importandroid.graphics.Bitmap.Config;
  7. importandroid.os.Bundle;
  8. importandroid.util.Log;
  9. importandroid.widget.ImageView;
  10. importcom.android.volley.RequestQueue;
  11. importcom.android.volley.Response;
  12. importcom.android.volley.toolbox.ImageRequest;
  13. importcom.android.volley.toolbox.Volley;
  14. publicclassFragmentRetainDataActivityextendsActivity
  15. {
  16. privatestaticfinalStringTAG="FragmentRetainDataActivity";
  17. privateRetainedFragmentdataFragment;
  18. privateDialogFragmentmLoadingDialog;
  19. privateImageViewmImageView;
  20. privateBitmapmBitmap;
  21. @Override
  22. publicvoidonCreate(BundlesavedInstanceState)
  23. {
  24. super.onCreate(savedInstanceState);
  25. setContentView(R.layout.activity_main);
  26. Log.e(TAG,"onCreate");
  27. //findtheretainedfragmentonactivityrestarts
  28. FragmentManagerfm=getFragmentManager();
  29. dataFragment=(RetainedFragment)fm.findFragmentByTag("data");
  30. //createthefragmentanddatathefirsttime
  31. if(dataFragment==null)
  32. {
  33. //addthefragment
  34. dataFragment=newRetainedFragment();
  35. fm.beginTransaction().add(dataFragment,"data").commit();
  36. }
  37. mBitmap=collectMyLoadedData();
  38. initData();
  39. //thedataisavailableindataFragment.getData()
  40. }
  41. /**
  42. *初始化数据
  43. */
  44. privatevoidinitData()
  45. {
  46. mImageView=(ImageView)findViewById(R.id.id_imageView);
  47. if(mBitmap==null)
  48. {
  49. mLoadingDialog=newLoadingDialog();
  50. mLoadingDialog.show(getFragmentManager(),"LOADING_DIALOG");
  51. RequestQueuenewRequestQueue=Volley
  52. .newRequestQueue(FragmentRetainDataActivity.this);
  53. ImageRequestimageRequest=newImageRequest(
  54. "http://img.my.csdn.net/uploads/201407/18/1405652589_5125.jpg",
  55. newResponse.Listener<Bitmap>()
  56. {
  57. @Override
  58. publicvoidonResponse(Bitmapresponse)
  59. {
  60. mBitmap=response;
  61. mImageView.setImageBitmap(mBitmap);
  62. //loadthedatafromtheweb
  63. dataFragment.setData(mBitmap);
  64. mLoadingDialog.dismiss();
  65. }
  66. },0,0,Config.RGB_565,null);
  67. newRequestQueue.add(imageRequest);
  68. }else
  69. {
  70. mImageView.setImageBitmap(mBitmap);
  71. }
  72. }
  73. @Override
  74. publicvoidonDestroy()
  75. {
  76. Log.e(TAG,"onDestroy");
  77. super.onDestroy();
  78. //storethedatainthefragment
  79. dataFragment.setData(mBitmap);
  80. }
  81. privateBitmapcollectMyLoadedData()
  82. {
  83. returndataFragment.getData();
  84. }
  85. }


这里在onCreate总使用了Volley去加载 了一张美女照片,然后在onDestroy中对Bitmap进行存储,在onCreate添加一个或者恢复一个Fragment的引用,然后对Bitmap进行读取和设置。这种方式适用于比较大的数据的存储与恢复。

注:这里也没有考虑加载时旋转屏幕,问题与上面的一致。

效果图:


5、配置configChanges,自己对屏幕旋转的变化进行处理

在menifest中进行属性设置:

[html] view plain copy
  1. <activity
  2. android:name=".ConfigChangesTestActivity"
  3. android:configChanges="screenSize|orientation">
  4. </activity>
低版本的API只需要加入orientation,而高版本的则需要加入screenSize。

ConfigChangesTestActivity

[java] view plain copy
  1. packagecom.example.zhy_handle_runtime_change;
  2. importjava.util.ArrayList;
  3. importjava.util.Arrays;
  4. importandroid.app.DialogFragment;
  5. importandroid.app.ListActivity;
  6. importandroid.content.res.Configuration;
  7. importandroid.os.AsyncTask;
  8. importandroid.os.Bundle;
  9. importandroid.util.Log;
  10. importandroid.widget.ArrayAdapter;
  11. importandroid.widget.ListAdapter;
  12. importandroid.widget.Toast;
  13. /**
  14. *@authorzhy
  15. *
  16. */
  17. publicclassConfigChangesTestActivityextendsListActivity
  18. {
  19. privatestaticfinalStringTAG="MainActivity";
  20. privateListAdaptermAdapter;
  21. privateArrayList<String>mDatas;
  22. privateDialogFragmentmLoadingDialog;
  23. privateLoadDataAsyncTaskmLoadDataAsyncTask;
  24. @Override
  25. publicvoidonCreate(BundlesavedInstanceState)
  26. {
  27. super.onCreate(savedInstanceState);
  28. Log.e(TAG,"onCreate");
  29. initData(savedInstanceState);
  30. }
  31. /**
  32. *初始化数据
  33. */
  34. privatevoidinitData(BundlesavedInstanceState)
  35. {
  36. mLoadingDialog=newLoadingDialog();
  37. mLoadingDialog.show(getFragmentManager(),"LoadingDialog");
  38. mLoadDataAsyncTask=newLoadDataAsyncTask();
  39. mLoadDataAsyncTask.execute();
  40. }
  41. /**
  42. *初始化适配器
  43. */
  44. privatevoidinitAdapter()
  45. {
  46. mAdapter=newArrayAdapter<String>(ConfigChangesTestActivity.this,
  47. android.R.layout.simple_list_item_1,mDatas);
  48. setListAdapter(mAdapter);
  49. }
  50. /**
  51. *模拟耗时操作
  52. *
  53. *@return
  54. */
  55. privateArrayList<String>generateTimeConsumingDatas()
  56. {
  57. try
  58. {
  59. Thread.sleep(2000);
  60. }catch(InterruptedExceptione)
  61. {
  62. }
  63. returnnewArrayList<String>(Arrays.asList("通过Fragment保存大量数据",
  64. "onSaveInstanceState保存数据",
  65. "getLastNonConfigurationInstance已经被弃用","RabbitMQ","Hadoop",
  66. "Spark"));
  67. }
  68. /**
  69. *当配置发生变化时,不会重新启动Activity。但是会回调此方法,用户自行进行对屏幕旋转后进行处理
  70. */
  71. @Override
  72. publicvoidonConfigurationChanged(ConfigurationnewConfig)
  73. {
  74. super.onConfigurationChanged(newConfig);
  75. if(newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE)
  76. {
  77. Toast.makeText(this,"landscape",Toast.LENGTH_SHORT).show();
  78. }elseif(newConfig.orientation==Configuration.ORIENTATION_PORTRAIT)
  79. {
  80. Toast.makeText(this,"portrait",Toast.LENGTH_SHORT).show();
  81. }
  82. }
  83. privateclassLoadDataAsyncTaskextendsAsyncTask<Void,Void,Void>
  84. {
  85. @Override
  86. protectedVoiddoInBackground(Void...params)
  87. {
  88. mDatas=generateTimeConsumingDatas();
  89. returnnull;
  90. }
  91. @Override
  92. protectedvoidonPostExecute(Voidresult)
  93. {
  94. mLoadingDialog.dismiss();
  95. initAdapter();
  96. }
  97. }
  98. @Override
  99. protectedvoidonDestroy()
  100. {
  101. Log.e(TAG,"onDestroy");
  102. super.onDestroy();
  103. }
  104. }

对第一种方式的代码进行了修改,去掉了保存与恢复的代码,重写了onConfigurationChanged;此时,无论用户何时旋转屏幕都不会重新启动Activity,并且onConfigurationChanged中的代码可以得到调用。从效果图可以看到,无论如何旋转不会重启Activity.

效果图:


6、旋转屏幕的最佳实践

下面要开始今天的难点了,就是处理文章开始时所说的,当异步任务在执行时,进行旋转,如果解决上面的问题。

首先说一下探索过程:

起初,我认为此时旋转无非是再启动一次线程,并不会造成异常,我只要即使的在onDestroy里面关闭上一个异步任务就可以了。事实上,如果我关闭了,上一次的对话框会一直存在;如果我不关闭,但是activity是一定会被销毁的,对话框的dismiss也会出异常。真心很蛋疼,并且即使对话框关闭了,任务关闭了;用户旋转还是会造成重新创建任务,从头开始加载数据。

下面我们希望有一种解决方案:在加载数据时旋转屏幕,不会对加载任务进行中断,且对用户而言,等待框在加载完成之前都正常显示:

当然我们还使用Fragment进行数据保存,毕竟这是官方推荐的:

OtherRetainedFragment

[java] view plain copy
  1. packagecom.example.zhy_handle_runtime_change;
  2. importandroid.app.Fragment;
  3. importandroid.os.Bundle;
  4. /**
  5. *保存对象的Fragment
  6. *
  7. *@authorzhy
  8. *
  9. */
  10. publicclassOtherRetainedFragmentextendsFragment
  11. {
  12. //dataobjectwewanttoretain
  13. //保存一个异步的任务
  14. privateMyAsyncTaskdata;
  15. //thismethodisonlycalledonceforthisfragment
  16. @Override
  17. publicvoidonCreate(BundlesavedInstanceState)
  18. {
  19. super.onCreate(savedInstanceState);
  20. //retainthisfragment
  21. setRetainInstance(true);
  22. }
  23. publicvoidsetData(MyAsyncTaskdata)
  24. {
  25. this.data=data;
  26. }
  27. publicMyAsyncTaskgetData()
  28. {
  29. returndata;
  30. }
  31. }

和上面的差别不大,唯一不同的就是它要保存的对象编程一个异步的任务了,相信看到这,已经知道经常上述问题的一个核心了,保存一个异步任务,在重启时,继续这个任务。

[java] view plain copy
  1. packagecom.example.zhy_handle_runtime_change;
  2. importjava.util.ArrayList;
  3. importjava.util.Arrays;
  4. importjava.util.List;
  5. importandroid.os.AsyncTask;
  6. publicclassMyAsyncTaskextendsAsyncTask<Void,Void,Void>
  7. {
  8. privateFixProblemsActivityactivity;
  9. /**
  10. *是否完成
  11. */
  12. privatebooleanisCompleted;
  13. /**
  14. *进度框
  15. */
  16. privateLoadingDialogmLoadingDialog;
  17. privateList<String>items;
  18. publicMyAsyncTask(FixProblemsActivityactivity)
  19. {
  20. this.activity=activity;
  21. }
  22. /**
  23. *开始时,显示加载框
  24. */
  25. @Override
  26. protectedvoidonPreExecute()
  27. {
  28. mLoadingDialog=newLoadingDialog();
  29. mLoadingDialog.show(activity.getFragmentManager(),"LOADING");
  30. }
  31. /**
  32. *加载数据
  33. */
  34. @Override
  35. protectedVoiddoInBackground(Void...params)
  36. {
  37. items=loadingData();
  38. returnnull;
  39. }
  40. /**
  41. *加载完成回调当前的Activity
  42. */
  43. @Override
  44. protectedvoidonPostExecute(Voidunused)
  45. {
  46. isCompleted=true;
  47. notifyActivityTaskCompleted();
  48. if(mLoadingDialog!=null)
  49. mLoadingDialog.dismiss();
  50. }
  51. publicList<String>getItems()
  52. {
  53. returnitems;
  54. }
  55. privateList<String>loadingData()
  56. {
  57. try
  58. {
  59. Thread.sleep(5000);
  60. }catch(InterruptedExceptione)
  61. {
  62. }
  63. returnnewArrayList<String>(Arrays.asList("通过Fragment保存大量数据",
  64. "onSaveInstanceState保存数据",
  65. "getLastNonConfigurationInstance已经被弃用","RabbitMQ","Hadoop",
  66. "Spark"));
  67. }
  68. /**
  69. *设置Activity,因为Activity会一直变化
  70. *
  71. *@paramactivity
  72. */
  73. publicvoidsetActivity(FixProblemsActivityactivity)
  74. {
  75. //如果上一个Activity销毁,将与上一个Activity绑定的DialogFragment销毁
  76. if(activity==null)
  77. {
  78. mLoadingDialog.dismiss();
  79. }
  80. //设置为当前的Activity
  81. this.activity=activity;
  82. //开启一个与当前Activity绑定的等待框
  83. if(activity!=null&&!isCompleted)
  84. {
  85. mLoadingDialog=newLoadingDialog();
  86. mLoadingDialog.show(activity.getFragmentManager(),"LOADING");
  87. }
  88. //如果完成,通知Activity
  89. if(isCompleted)
  90. {
  91. notifyActivityTaskCompleted();
  92. }
  93. }
  94. privatevoidnotifyActivityTaskCompleted()
  95. {
  96. if(null!=activity)
  97. {
  98. activity.onTaskCompleted();
  99. }
  100. }
  101. }

异步任务中,管理一个对话框,当开始下载前,进度框显示,下载结束进度框消失,并为Activity提供回调。当然了,运行过程中Activity不断的重启,我们也提供了setActivity方法,onDestory时,会setActivity(null)防止内存泄漏,同时我们也会关闭与其绑定的加载框;当onCreate传入新的Activity时,我们会在再次打开一个加载框,当然了因为屏幕的旋转并不影响加载的数据,所有后台的数据一直继续在加载。是不是很完美~~

主Activity:

[java] view plain copy
  1. packagecom.example.zhy_handle_runtime_change;
  2. importjava.util.List;
  3. importandroid.app.FragmentManager;
  4. importandroid.app.ListActivity;
  5. importandroid.os.Bundle;
  6. importandroid.util.Log;
  7. importandroid.widget.ArrayAdapter;
  8. importandroid.widget.ListAdapter;
  9. publicclassFixProblemsActivityextendsListActivity
  10. {
  11. privatestaticfinalStringTAG="MainActivity";
  12. privateListAdaptermAdapter;
  13. privateList<String>mDatas;
  14. privateOtherRetainedFragmentdataFragment;
  15. privateMyAsyncTaskmMyTask;
  16. @Override
  17. publicvoidonCreate(BundlesavedInstanceState)
  18. {
  19. super.onCreate(savedInstanceState);
  20. Log.e(TAG,"onCreate");
  21. //findtheretainedfragmentonactivityrestarts
  22. FragmentManagerfm=getFragmentManager();
  23. dataFragment=(OtherRetainedFragment)fm.findFragmentByTag("data");
  24. //createthefragmentanddatathefirsttime
  25. if(dataFragment==null)
  26. {
  27. //addthefragment
  28. dataFragment=newOtherRetainedFragment();
  29. fm.beginTransaction().add(dataFragment,"data").commit();
  30. }
  31. mMyTask=dataFragment.getData();
  32. if(mMyTask!=null)
  33. {
  34. mMyTask.setActivity(this);
  35. }else
  36. {
  37. mMyTask=newMyAsyncTask(this);
  38. dataFragment.setData(mMyTask);
  39. mMyTask.execute();
  40. }
  41. //thedataisavailableindataFragment.getData()
  42. }
  43. @Override
  44. protectedvoidonRestoreInstanceState(Bundlestate)
  45. {
  46. super.onRestoreInstanceState(state);
  47. Log.e(TAG,"onRestoreInstanceState");
  48. }
  49. @Override
  50. protectedvoidonSaveInstanceState(BundleoutState)
  51. {
  52. mMyTask.setActivity(null);
  53. super.onSaveInstanceState(outState);
  54. Log.e(TAG,"onSaveInstanceState");
  55. }
  56. @Override
  57. protectedvoidonDestroy()
  58. {
  59. Log.e(TAG,"onDestroy");
  60. super.onDestroy();
  61. }
  62. /**
  63. *回调
  64. */
  65. publicvoidonTaskCompleted()
  66. {
  67. mDatas=mMyTask.getItems();
  68. mAdapter=newArrayAdapter<String>(FixProblemsActivity.this,
  69. android.R.layout.simple_list_item_1,mDatas);
  70. setListAdapter(mAdapter);
  71. }
  72. }

在onCreate中,如果没有开启任务(第一次进入),开启任务;如果已经开启了,调用setActivity(this);

在onSaveInstanceState把当前任务加入Fragment

我设置了等待5秒,足够旋转三四个来回了~~~~可以看到虽然在不断的重启,但是丝毫不影响加载数据任务的运行和加载框的显示~~~~

效果图:


可以看到我在加载的时候就三心病狂的旋转屏幕~~但是丝毫不影响显示效果与任务的加载~~


最后,说明一下,其实不仅是屏幕旋转需要保存数据,当用户在使用你的app时,忽然接到一个来电,长时间没有回到你的app界面也会造成Activity的销毁与重建,所以一个行为良好的App,是有必要拥有恢复数据的能力的~~。


查阅资料时的一些参考文档:

http://developer.android.com/guide/topics/resources/runtime-changes.html

http://blog.doityourselfandroid.com/2010/11/14/handling-progress-dialogs-and-screen-orientation-changes/

转载自:http://blog.csdn.net/lmj623565791/article/details/37936275

更多相关文章

  1. mybatisplus的坑 insert标签insert into select无参数问题的解决
  2. python起点网月票榜字体反爬案例
  3. android中使用sqlite、复制assets下的数据库到SD卡、支持大于1M
  4. Android青翼蝠王之ContentProvider
  5. Android(安卓)异步加载解决方案
  6. 关于Android连接远程数据库(mysql、oracle)
  7. Android(安卓)Contact分析(一):Data, RawContact, Contact之间的关
  8. Android(安卓)camera 默认显示黑白的问题
  9. 在Android中查看和管理sqlite数据库

随机推荐

  1. Android(安卓)进度条功能实现
  2. Android(安卓)DNS之DNS参数设置
  3. android 绘图
  4. android 模拟器手机如何添加文件到sd卡
  5. Android(安卓)Handler 异步消息处理机制
  6. Android(安卓)使用SVG
  7. android SDK包引用了java SDK哪些包
  8. android UI进阶之弹窗的使用
  9. Android(安卓)中需要掌握的高级技巧
  10. Android百度地图——定位SDK(版本v3.1)(二)