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

前端 未结 28 1201
轮回少年
轮回少年 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 07:53

    i have found and easier solution to handle threads when orientation change. You can just keep an static reference to your activity/fragment and verify if its null before acting on the ui. I suggest using a try catch too:

     public class DashListFragment extends Fragment {
         private static DashListFragment ACTIVE_INSTANCE;
    
         @Override
         public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            ACTIVE_INSTANCE = this;
    
            new Handler().postDelayed(new Runnable() {
                public void run() {
                    try {
                            if (ACTIVE_INSTANCE != null) {
                                setAdapter(); // this method do something on ui or use context
                            }
                    }
                    catch (Exception e) {}
    
    
                }
            }, 1500l);
    
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
    
            ACTIVE_INSTANCE = null;
        }
    
    
    }
    
    0 讨论(0)
  • 2020-11-22 07:56

    When you switch orientations, Android will create a new View. You're probably getting crashes because your background thread is trying to change the state on the old one. (It may also be having trouble because your background thread isn't on the UI thread)

    I'd suggest making that mHandler volatile and updating it when the orientation changes.

    0 讨论(0)
  • 2020-11-22 07:56

    The trick is to show/dismiss the dialog within AsyncTask during onPreExecute/onPostExecute as usual, though in case of orientation-change create/show a new instance of the dialog in the activity and pass its reference to the task.

    public class MainActivity extends Activity {
        private Button mButton;
        private MyTask mTask = null;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            MyTask task = (MyTask) getLastNonConfigurationInstance();
            if(task != null){
                mTask = task;
                mTask.mContext = this;
                mTask.mDialog = ProgressDialog.show(this, "", "", true);        
            }
    
            mButton = (Button) findViewById(R.id.button1);
            mButton.setOnClickListener(new View.OnClickListener(){
                public void onClick(View v){
                    mTask = new MyTask(MainActivity.this);
                    mTask.execute();
                }
            });
        }
    
    
        @Override
        public Object onRetainNonConfigurationInstance() {
            String str = "null";
            if(mTask != null){
                str = mTask.toString();
                mTask.mDialog.dismiss();
            }
            Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
            return mTask;
        }
    
    
    
        private class MyTask extends AsyncTask<Void, Void, Void>{
            private ProgressDialog mDialog;
            private MainActivity mContext;
    
    
            public MyTask(MainActivity context){
                super();
                mContext = context;
            }
    
    
            protected void onPreExecute() {
                mDialog = ProgressDialog.show(MainActivity.this, "", "", true);
            }
    
            protected void onPostExecute(Void result) {
                mContext.mTask = null;
                mDialog.dismiss();
            }
    
    
            @Override
            protected Void doInBackground(Void... params) {
                SystemClock.sleep(5000);
                return null;
            }       
        }
    }
    
    0 讨论(0)
  • 2020-11-22 07:58

    I have an implementation which allows the activity to be destroyed on a screen orientation change, but still destroys the dialog in the recreated activity successfully. I use ...NonConfigurationInstance to attach the background task to the recreated activity. The normal Android framework handles recreating the dialog itself, nothing is changed there.

    I subclassed AsyncTask adding a field for the 'owning' activity, and a method to update this owner.

    class MyBackgroundTask extends AsyncTask<...> {
      MyBackgroundTask (Activity a, ...) {
        super();
        this.ownerActivity = a;
      }
    
      public void attach(Activity a) {
        ownerActivity = a;
      }
    
      protected void onPostExecute(Integer result) {
        super.onPostExecute(result);
        ownerActivity.dismissDialog(DIALOG_PROGRESS);
      }
    
      ...
    }
    

    In my activity class I added a field backgroundTask referring to the 'owned' backgroundtask, and I update this field using onRetainNonConfigurationInstance and getLastNonConfigurationInstance.

    class MyActivity extends Activity {
      public void onCreate(Bundle savedInstanceState) {
        ...
        if (getLastNonConfigurationInstance() != null) {
          backgroundTask = (MyBackgroundTask) getLastNonConfigurationInstance();
          backgroundTask.attach(this);
        }
      }
    
      void startBackgroundTask() {
        backgroundTask = new MyBackgroundTask(this, ...);
        showDialog(DIALOG_PROGRESS);
        backgroundTask.execute(...);
      }
    
      public Object onRetainNonConfigurationInstance() {
        if (backgroundTask != null && backgroundTask.getStatus() != Status.FINISHED)
          return backgroundTask;
        return null;
      }
      ...
    }
    

    Suggestions for further improvement:

    • Clear the backgroundTask reference in the activity after the task is finished to release any memory or other resources associated with it.
    • Clear the ownerActivity reference in the backgroundtask before the activity is destroyed in case it will not be recreated immediately.
    • Create a BackgroundTask interface and/or collection to allow different types of tasks to run from the same owning activity.
    0 讨论(0)
  • 2020-11-22 07:59

    When you change orientations , Android kill that activity and created new activity . I suggest to use retrofit with Rx java . which handle crashes automatically .

    Use these method when retrofit call.

    .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread())

    0 讨论(0)
  • 2020-11-22 08:00

    I am a fresher in android and I tried this and it's worked.

    public class loadTotalMemberByBranch extends AsyncTask<Void, Void,Void> {
            ProgressDialog progressDialog = new ProgressDialog(Login.this);
            int ranSucess=0;
            @Override
            protected void onPreExecute() {
                // TODO Auto-generated method stub
                super.onPreExecute();
                progressDialog.setTitle("");    
                progressDialog.isIndeterminate();
                progressDialog.setCancelable(false);
                progressDialog.show();
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
    
            }
            @Override
            protected Void doInBackground(Void... params) {
                // TODO Auto-generated method stub
    
                return null;
            }
            @Override
            protected void onPostExecute(Void result) {
                // TODO Auto-generated method stub
                super.onPostExecute(result);
                progressDialog.dismiss();
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
            }
    }
    
    0 讨论(0)
提交回复
热议问题