How to handle screen orientation change when progress dialog and background thread active?

前端 未结 28 1761
轮回少年
轮回少年 2020-11-22 07:03

My program does some network activity in a background thread. Before starting, it pops up a progress dialog. The dialog is dismissed on the handler. This all works fine, exc

28条回答
  •  暖寄归人
    2020-11-22 08:06

    I met the same problem. My activity needs to parse some data from a URL and it's slow. So I create a thread to do so, then show a progress dialog. I let the thread post a message back to UI thread via Handler when it's finished. In Handler.handleMessage, I get the data object (ready now) from thread and populate it to UI. So it's very similar to your example.

    After a lot of trial and error it looks like I found a solution. At least now I can rotate screen at any moment, before or after the thread is done. In all tests, the dialog is properly closed and all behaviors are as expected.

    What I did is shown below. The goal is to fill my data model (mDataObject) and then populate it to UI. Should allow screen rotation at any moment without surprise.

    class MyActivity {
    
        private MyDataObject mDataObject = null;
        private static MyThread mParserThread = null; // static, or make it singleton
    
        OnCreate() {
            ...
            Object retained = this.getLastNonConfigurationInstance();
            if(retained != null) {
                // data is already completely obtained before config change
                // by my previous self.
                // no need to create thread or show dialog at all
                mDataObject = (MyDataObject) retained;
                populateUI();
            } else if(mParserThread != null && mParserThread.isAlive()){
                // note: mParserThread is a static member or singleton object.
                // config changed during parsing in previous instance. swap handler
                // then wait for it to finish.
                mParserThread.setHandler(new MyHandler());
            } else {
                // no data and no thread. likely initial run
                // create thread, show dialog
                mParserThread = new MyThread(..., new MyHandler());
                mParserThread.start();
                showDialog(DIALOG_PROGRESS);
            }
        }
    
        // http://android-developers.blogspot.com/2009/02/faster-screen-orientation-change.html
        public Object onRetainNonConfigurationInstance() {
            // my future self can get this without re-downloading
            // if it's already ready.
            return mDataObject;
        }
    
        // use Activity.showDialog instead of ProgressDialog.show
        // so the dialog can be automatically managed across config change
        @Override
        protected Dialog onCreateDialog(int id) {
            // show progress dialog here
        }
    
        // inner class of MyActivity
        private class MyHandler extends Handler {
            public void handleMessage(msg) {
                mDataObject = mParserThread.getDataObject();
                populateUI();
                dismissDialog(DIALOG_PROGRESS);
            }
        }
    }
    
    class MyThread extends Thread {
        Handler mHandler;
        MyDataObject mDataObject;
    
        // constructor with handler param
        public MyHandler(..., Handler h) {
            ...
            mHandler = h;
        }
    
        public void setHandler(Handler h) { mHandler = h; } // for handler swapping after config change
        public MyDataObject getDataObject() { return mDataObject; } // return data object (completed) to caller
    
        public void run() {
            mDataObject = new MyDataObject();
            // do the lengthy task to fill mDataObject with data
            lengthyTask(mDataObject);
            // done. notify activity
            mHandler.sendEmptyMessage(0); // tell activity: i'm ready. come pick up the data.
        }
    }
    

    That's what works for me. I don't know if this is the "correct" method as designed by Android -- they claim this "destroy/recreate activity during screen rotation" actually makes things easier, so I guess it shouldn't be too tricky.

    Let me know if you see a problem in my code. As said above I don't really know if there is any side effect.

提交回复
热议问题