android执行耗时操作,屏幕旋转怎么办

【声明:】本文是作者(蘑菇v5)原创,版权归作者 蘑菇v5所有,侵权必究。本文首发在简书。如若转发,请注明作者和来源地址!未经授权,严禁私自转载!

解决方案:

线程在异步加载数据时,屏幕旋转不会中断任务线程,等待加载框在加载完成之前一直正常显示,并且使用Fragment进行数据保存,因为这是官方推荐的,适用于比较大的数据的存储与恢复(如 bitmap)。

RetainedFragment:

/** 
 * 保存对象的Fragment 
 *  
 * @author zsnlh 
 *  
 */  
public class RetainedFragment extends Fragment {  
  
    // data object we want to retain  
    // 保存一个异步的任务  
    private MyAsyncTask data;  
    // this method is only called once for this fragment  
    @Override  
    public void onCreate(Bundle savedInstanceState)  {  
        super.onCreate(savedInstanceState);  
        // retain this fragment  
        setRetainInstance(true);  
    }  
    public void setData(MyAsyncTask data) {  
        this.data = data;  
    }  
    public MyAsyncTask getData()   {  
        return data;  
    }        
}  

关键思想:保存一个异步任务,在重启时,继续这个任务。

MyAsyncTask:

/**
*  MyAsyncTask
* @author zsnlh 
*/
public class MyAsyncTask extends AsyncTask<Void, Void, Void> {  
 //保存外部activity的弱引用
 private WeakReference<Context> weakReference;
 public MyAsyncTask(Context context) {
 weakReference = new WeakReference<>(context);
 }
    private FixProblemsActivity activity;  
    /** 
     * 是否完成 
     */  
    private boolean isCompleted;  
    /** 
     * 进度框 
     */  
    private LoadingDialog mLoadingDialog;  
    private List<String> items;  
  
    public MyAsyncTask(FixProblemsActivity activity) {  
        this.activity = activity;  
    }  
  
    /** 
     * 开始时,显示加载框 
     */  
    @Override  
    protected void onPreExecute() {  
        mLoadingDialog = new LoadingDialog();  
        activity = (FixProblemsActivity) weakReference.get();
if(activity != null){
        mLoadingDialog.show(activity.getFragmentManager(), "LOADING");  
  }
}  
  
    /** 
     * 加载数据 
     */  
    @Override  
    protected Void doInBackground(Void... params)  {  
        items = loadingData();  
        return null;  
    }  
  
    /** 
     * 加载完成回调当前的Activity 
     */  
    @Override  
    protected void onPostExecute(Void unused) {  
        isCompleted = true;  
        notifyActivityTaskCompleted();  
        if (mLoadingDialog != null)  
            mLoadingDialog.dismiss();  
    }  
  
    public List<String> getItems() {  
        return items;  
    }  
  
    private List<String> loadingData()  {  
        try {  
            Thread.sleep(3000);  
        } catch (InterruptedException e) {  
        }  
        return new ArrayList<String>(Arrays.asList("通过Fragment保存大量数据",  
                "onSaveInstanceState保存数据",  
                "getLastNonConfigurationInstance已经被弃用", "穿越火线", "英雄联盟",  
                "王者荣耀"));  
    }  
  
    /** 
     * 设置Activity,因为Activity会一直变化 
     *  
     * @param activity 
     */  
    public void setActivity(FixProblemsActivity activity)  { 
        weakReference = new WeakReference<>(activity);
        // 设置为当前的Activity
         this.activity = (FixProblemsActivity) activity; 
        // 如果上一个Activity销毁,将与上一个Activity绑定的DialogFragment销毁  
        if (activity == null) {  
           dialogDismiss(); 
        } 
        // 开启一个与当前Activity绑定的等待框  
        if (activity != null && !isCompleted)  {  
            mLoadingDialog = new LoadingDialog();  
            mLoadingDialog.show(activity.getFragmentManager(), "LOADING");  
        }  
        // 如果完成,通知Activity  
        if (isCompleted) {  
            notifyActivityTaskCompleted();  
        }  
    }  
  
    private void notifyActivityTaskCompleted() {  
        if (null != activity)  {  
            activity.onTaskCompleted();  
        }  
    } 
/**
 * 在Activity不可见时,关闭dialog
 */
 public void dialogDismiss(){
 if(mLoadingDialog != null){
 mLoadingDialog.dismiss();
   }
 }  
}  

和之前一样保留Activity的虚引用,防止内存泄漏。
setActivity()方法用于任务未完成时,重启activity相应的创建一个新的dialog
dialogDismiss用于在在Activity不可见时,关闭dialog,防止以前的dialog造成内存泄漏。
当任务完成时,调用activity的回调方法onTaskCompleted更新UI
异步任务中,管理一个对话框,当开始下载前,进度框显示,下载结束进度框消失,并为Activity提供回调。当然了,运行过程中Activity不断的重启,我们也提供了setActivity方法,onDestory时,会setActivity(null)防止内存泄漏,同时我们也会关闭与其绑定的加载框;当onCreate传入新的Activity时,我们会在再次打开一个加载框,当然了因为屏幕的旋转并不影响加载的数据,所有后台的数据一直继续在加载。

Activity:

public class FixProblemsActivity extends ListActivity {  
    private static final String TAG = "MainActivity";  
    private ListAdapter mAdapter;  
    private List<String> mDatas;  
    private RetainedFragment dataFragment;  
    private MyAsyncTask mMyTask;  
  
    @Override  
    public void onCreate(Bundle savedInstanceState)  {  
        super.onCreate(savedInstanceState);  
        Log.e(TAG, "onCreate");  
        // find the retained fragment on activity restarts  
        FragmentManager fm = getFragmentManager();  
        dataFragment = (RetainedFragment) fm.findFragmentByTag("data");  
        // create the fragment and data the first time  
        if (dataFragment == null)  {  
            // add the fragment  
            dataFragment = new OtherRetainedFragment();  
            fm.beginTransaction().add(dataFragment, "data").commit();  
        }  
        mMyTask = dataFragment.getData();  
        if (mMyTask != null) {  
            //与新的Activity进行绑定
            mMyTask.setActivity(this);  
        } else {  
            //启动一个新的任务
            mMyTask = new MyAsyncTask(this);  
            dataFragment.setData(mMyTask);  
            mMyTask.execute();  
        }  
        // the data is available in dataFragment.getData()  
    }  
    @Override  
    protected void onRestoreInstanceState(Bundle state)  {  
        super.onRestoreInstanceState(state);  
        Log.e(TAG, "onRestoreInstanceState");  
    }  
    @Override  
    protected void onSaveInstanceState(Bundle outState)  {  
        mMyTask.setActivity(null);  
        super.onSaveInstanceState(outState);  
        Log.e(TAG, "onSaveInstanceState");  
    }    
    @Override  
    protected void onDestroy() {  
        Log.e(TAG, "onDestroy");  
        super.onDestroy();    
    }  
     @Override
 //在这里关闭Dialog,否则容易造成内存泄漏
 protected void onPause() {
 super.onPause();
 mMyTask.dialogDismiss();
 }
 /**
 * 回调方法,更新UI
 * 这里如果在加载的过程中按下返回键返回主Activity时,会出现异常,
*setAdapter on a null object reference。因为activity被销毁,
 * 要解决这个问题,可以监听返回键事件做相应处理。
 */ 
    public void onTaskCompleted()  {  
        mDatas = mMyTask.getItems();  
        mAdapter = new ArrayAdapter<String>(FixProblemsActivity.this,  android.R.layout.simple_list_item_1, mDatas);  
        setListAdapter(mAdapter);  
    }   
}  

onCreate中,如果没有开启任务(第一次进入),开启任务;如果已经开启了,调用setActivity(this);在onSaveInstanceState把当前任务加入Fragment,我设置了等待5秒,足够旋转三四个来回了,可以看到虽然在不断的重启,但是丝毫不影响加载数据任务的运行和加载框的显示

效果图:

效果图.gif

可以看到我在加载的时候就丧心病狂的旋转屏幕,但是丝毫不影响显示效果与任务的加载。
  最后,说明一下,其实不仅是屏幕旋转需要保存数据,当用户在使用你的app时,忽然接到一个来电,长时间没有回到你的app界面也会造成Activity的销毁与重建,所以一个行为良好的App,是有必要拥有恢复数据的能力的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容