Home PC Games Linux Windows Database Network Programming Server Mobile  
           
  Home \ Programming \ Android screen rotation processing and ProgressDialog the best AsyncTask     - System with Windows Remote Desktop to connect Ubuntu 15.04 (Linux)

- Linux memory Cache Analysis (Linux)

- Shell generated using automated configuration script Orabbix (Database)

- Reported too many open files Linux solutions (Server)

- Ubuntu in Vim editor display processing method Chinese garbled (Linux)

- C ++ 11 smart pointers (Programming)

- Redis logging system (Database)

- Java multi-threaded shared communications variables (Programming)

- wget command Walkthrough (Linux)

- mysql_config_editor encryption and decryption of the new features of MySQL realization (Database)

- JDK comes with tools JPS (Linux)

- Linux System Getting Started Tutorial: mounted directly in Linux LVM partition (Linux)

- 11 examples in Linux df command (Linux)

- Linux Workstation Security Checklist - from the Linux Foundation Internal (Linux)

- Encrypted with GnuPG signature to verify the authenticity and integrity of downloaded file (Linux)

- C ++ pointer of the (error-prone model) (Programming)

- RHEL 6.5 KVM analytical use (Server)

- Transfer files to Windows and Linux (Linux)

- Apache Linux firewall reverse proxy configuration (Linux)

- Kubernetes Cluster Setup problems encountered and solutions (Server)

 
         
  Android screen rotation processing and ProgressDialog the best AsyncTask
     
  Add Date : 2018-11-21      
         
         
         
  As we all know, Activity when not explicitly specify the screen orientation and configChanges, rotate the screen when the user restarts. Of course, deal with this situation, Android gives several options:

a, if it is a small amount of data, you can onSaveInstanceState () and onRestoreInstanceState () to save and restore.

Android calls onSaveInstanceState () method in your Activity destruction before, so you can store data about the state of the application in this method. Then you can restore it onCreate () or onRestoreInstanceState () method.

b, if it is a lot of data, use the Fragment holding the object needs to be restored.

c, self-managing configuration changes.

NOTE: getLastNonConfigurationInstance () has been deprecated by the above method two alternatives.

2. Difficulties

Assuming the current Activity onCreate started in an asynchronous thread to a folder in the data, of course, in order to give the user a good experience, there will be a ProgressDialog, when the data load is complete, ProgressDialog disappear settings data.

Here, if the asynchronous data after completion of loading, rotate the screen, using the a, b both methods will not be difficult, simply save data and restore data.

However, if the thread is loaded when the rotation, there will be the following questions:

a) At this point the data has not finished loading, when onCreate restarted, it will start the thread again; but the thread may still be running, and may be updated already nonexistent control, resulting in an error.

b) Close ProgressDialog code thread onPostExecutez, but if you have to kill the thread can not close until ProgressDialog.

Official c) Google does not recommend the use of ProgressDialog, here we will use the official recommended DialogFragment to create my load box, which, in fact, gives us a big problem, DialogFragment it plainly is Fragment, and the current Activity Life Periodic binding occurs, we rotate the screen will cause the destruction of Activity, of course, also affect the DialogFragment.

Here I will use a few examples, respectively, using the above three ways, and how best to solve the above problems.

3. Use onSaveInstanceState () and onRestoreInstanceState () to save and restore data

Code:

package com.example.zhy_handle_runtime_change;

import java.util.ArrayList;
import java.util.Arrays;

import android.app.DialogFragment;
import android.app.ListActivity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
/ **
 * Without considering the load situation rotation, intended to avoid such a situation, the examples that follow will introduce solutions
 *
 * /
public class SavedInstanceStateUsingActivity extends ListActivity
{
 private static final String TAG = "MainActivity";
 private ListAdapter mAdapter;
 private ArrayList < String> mDatas;
 private DialogFragment mLoadingDialog;
 private LoadDataAsyncTask mLoadDataAsyncTask;

 @Override
 public void onCreate (Bundle savedInstanceState)
 {
  super.onCreate (savedInstanceState);
  Log.e (TAG, "onCreate");
  initData (savedInstanceState);
 }

 / **
  * Initialization data
  * /
 private void initData (Bundle savedInstanceState)
 {
  if (savedInstanceState! = null)
   mDatas = savedInstanceState.getStringArrayList ( "mDatas");

  if (mDatas == null)
  {
   mLoadingDialog = new LoadingDialog ();
   mLoadingDialog.show (getFragmentManager (), "LoadingDialog");
   mLoadDataAsyncTask = new LoadDataAsyncTask ();
   mLoadDataAsyncTask.execute ();
   
  } Else
  {
   initAdapter ();
  }

 }

 / **
  * Initialize adapter
  * /
 private void initAdapter ()
 {
  mAdapter = new ArrayAdapter < String> (
    SavedInstanceStateUsingActivity.this,
    android.R.layout.simple_list_item_1, mDatas);
  setListAdapter (mAdapter);
 }

 @Override
 protected void onRestoreInstanceState (Bundle state)
 {
  super.onRestoreInstanceState (state);
  Log.e (TAG, "onRestoreInstanceState");
 }

 @Override
 protected void onSaveInstanceState (Bundle outState)
 {
  super.onSaveInstanceState (outState);
  Log.e (TAG, "onSaveInstanceState");
  outState.putSerializable ( "mDatas", mDatas);

 }

 / **
  * Analog consuming operation
  *
  * @return
  * /
 private ArrayList < String> generateTimeConsumingDatas ()
 {
  try
  {
   Thread.sleep (2000);
  } Catch (InterruptedException e)
  {
  }
  return new ArrayList < String> (Arrays.asList ( "save large amounts of data through Fragment"
    "OnSaveInstanceState save data"
    "GetLastNonConfigurationInstance has been abandoned", "RabbitMQ", "Hadoop",
    "Spark"));
 }

 private class LoadDataAsyncTask extends AsyncTask < Void, Void, Void>
 {
  @Override
  protected Void doInBackground (Void ... params)
  {
   mDatas = generateTimeConsumingDatas ();
   return null;
  }

  @Override
  protected void onPostExecute (Void result)
  {
   mLoadingDialog.dismiss ();
   initAdapter ();
  }
 }

 @Override
 protected void onDestroy ()
 {
  Log.e (TAG, "onDestroy");
  super.onDestroy ();
 }

}

Interface to a ListView, onCreate start an asynchronous task to load data used here Thread.sleep simulates a time-consuming operation; when the user rotates the screen to restart occurs, it will onSaveInstanceState for storage of data, the data in onCreate recovery, eliminating unnecessary re-load it again.

The result:

After the data is loaded correctly, the user continues to rotate the screen, log will continue to play: onSaveInstanceState-> onDestroy-> onCreate-> onRestoreInstanceState, verify that we are indeed re-started, but we did not go for data loading again.

If at the time of loading, rotation, an error occurs, abnormal exit (Exit Reason: NullPointException occurs () dialog.dismiss, because with the current dialog FragmentManager bound is null, there are interested can go to Debug, this not critical).

4. Use the Fragment to save the object that is used to recover data

If you restart your Activity recover large amounts of data need to re-establish a network connection, or perform other intensive operations, such as configuration changes completely restart might be a slow user experience. Further, using the system provided onSaveIntanceState () callback, use the Bundle to fully restore the state of your Activity is likely to be impractical (Bundle is not designed to carry large amounts of data (such as bitmap), and the data must be in the Bundle serialized and deserialized), it will consume large amounts of memory and cause configuration changes slowly. In this case, when your Activity because the configuration changes and reboot, you can maintain a Fragment to ease the burden of re-start. The Fragment can contain references to objects you want to maintain a stateful.

When the Android system because configuration changes off your Activity, when your Activity is identified to keep the fragments will not be destroyed. You can add such fragements in your Activity in to save stateful objects.

When the configuration is changed, the state of preservation of the object at run time in Fragment

a) inheritance Fragment, declare a reference point to your stateful objects

b) call setRetainInstance (boolean) is created when the Fragment

c) adding to the Activity in the instance Fragment

d) When the Activity restarts, use FragmentManager recovery of Fragment

Code:

First Fragment:

package com.example.zhy_handle_runtime_change;

import android.app.Fragment;
import android.graphics.Bitmap;
import android.os.Bundle;

public class RetainedFragment extends Fragment
{
 // Data object we want to retain
 private Bitmap 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 (Bitmap data)
 {
  this.data = data;
 }

 public Bitmap getData ()
 {
  return data;
 }
}

Relatively simple, only need to declare the need to save the data object, and then provide getter and setter, pay attention, be sure to call setRetainInstance (true) in onCreate;

Then: FragmentRetainDataActivity

package com.example.zhy_handle_runtime_change;

import Android.app.Activity;
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;

import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.toolbox.ImageRequest;
import com.android.volley.toolbox.Volley;

public class FragmentRetainDataActivity extends Activity
{

 private static final String TAG = "FragmentRetainDataActivity";
 private RetainedFragment dataFragment;
 private DialogFragment mLoadingDialog;
 private ImageView mImageView;
 private Bitmap mBitmap;

 @Override
 public void onCreate (Bundle savedInstanceState)
 {
  super.onCreate (savedInstanceState);
  setContentView (R.layout.activity_main);
  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 RetainedFragment ();
   . Fm.beginTransaction () add (dataFragment, "data") commit ().;
  }
  mBitmap = collectMyLoadedData ();
  initData ();

  // The data is available in dataFragment.getData ()
 }

 / **
  * Initialization data
  * /
 private void initData ()
 {
  mImageView = (ImageView) findViewById (R.id.id_imageView);
  if (mBitmap == null)
  {
   mLoadingDialog = new LoadingDialog ();
   mLoadingDialog.show (getFragmentManager (), "LOADING_DIALOG");
   RequestQueue newRequestQueue = Volley
     .newRequestQueue (FragmentRetainDataActivity.this);
   ImageRequest imageRequest = new ImageRequest (
     "Upload / 2015_08 / 150808110773613.jpg",
     new Response.Listener < Bitmap> ()
     {
      @Override
      public void onResponse (Bitmap response)
      {
       mBitmap = response;
       mImageView.setImageBitmap (mBitmap);
       // Load the data from the web
       dataFragment.setData (mBitmap);
       mLoadingDialog.dismiss ();
      }
     }, 0, 0, Config.RGB_565, null);
   newRequestQueue.add (imageRequest);
  } Else
  {
   mImageView.setImageBitmap (mBitmap);
  }

 }

 @Override
 public void onDestroy ()
 {
  Log.e (TAG, "onDestroy");
  super.onDestroy ();
  // Store the data in the fragment
  dataFragment.setData (mBitmap);
 }

 private Bitmap collectMyLoadedData ()
 {
  return dataFragment.getData ();
 }

}

There is always a Volley used to load the onCreate a beautiful picture, and then in the middle of the Bitmap onDestroy storage, or add a recovery in onCreate a Fragment of reference, and then to read and set Bitmap. This method is applicable to large storage and recovery of data.

Note: There is no consideration of rotation of the screen when loading, consistent with the above issues.

5, configuration configChanges, own screen rotation processing changes

The property is set in menifest be:

    < Activity
            android: name = ". ConfigChangesTestActivity"
            android: configChanges = "screenSize | orientation">
        < / Activity>

Low version of the API only need to add orientation, while the high version is necessary to add screenSize.

ConfigChangesTestActivity

package com.example.zhy_handle_runtime_change;

import java.util.ArrayList;
import java.util.Arrays;

import android.app.DialogFragment;
import android.app.ListActivity;
import android.content.res.Configuration;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.Toast;

/ **
 *
 * /
public class ConfigChangesTestActivity extends ListActivity
{
 private static final String TAG = "MainActivity";
 private ListAdapter mAdapter;
 private ArrayList < String> mDatas;
 private DialogFragment mLoadingDialog;
 private LoadDataAsyncTask mLoadDataAsyncTask;

 @Override
 public void onCreate (Bundle savedInstanceState)
 {
  super.onCreate (savedInstanceState);
  Log.e (TAG, "onCreate");
  initData (savedInstanceState);
 }

 / **
  * Initialization data
  * /
 private void initData (Bundle savedInstanceState)
 {

  mLoadingDialog = new LoadingDialog ();
  mLoadingDialog.show (getFragmentManager (), "LoadingDialog");
  mLoadDataAsyncTask = new LoadDataAsyncTask ();
  mLoadDataAsyncTask.execute ();

 }

 / **
  * Initialize adapter
  * /
 private void initAdapter ()
 {
  mAdapter = new ArrayAdapter < String> (ConfigChangesTestActivity.this,
    android.R.layout.simple_list_item_1, mDatas);
  setListAdapter (mAdapter);
 }

 / **
  * Analog consuming operation
  *
  * @return
  * /
 private ArrayList < String> generateTimeConsumingDatas ()
 {
  try
  {
   Thread.sleep (2000);
  } Catch (InterruptedException e)
  {
  }
  return new ArrayList < String> (Arrays.asList ( "save large amounts of data through Fragment"
    "OnSaveInstanceState save data"
    "GetLastNonConfigurationInstance has been abandoned", "RabbitMQ", "Hadoop",
    "Spark"));
 }

 / **
  * When the configuration is changed, it will not be restarted Activity. But this will be a callback method, the user to be processed after screen rotation
  * /
 @Override
 public void onConfigurationChanged (Configuration newConfig)
 {
  super.onConfigurationChanged (newConfig);

  if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
  {
   Toast.makeText (this, "landscape", Toast.LENGTH_SHORT) .show ();
  } Else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT)
  {
   Toast.makeText (this, "portrait", Toast.LENGTH_SHORT) .show ();
  }

 }

 private class LoadDataAsyncTask extends AsyncTask < Void, Void, Void>
 {
  @Override
  protected Void doInBackground (Void ... params)
  {
   mDatas = generateTimeConsumingDatas ();
   return null;
  }

  @Override
  protected void onPostExecute (Void result)
  {
   mLoadingDialog.dismiss ();
   initAdapter ();
  }
 }

 @Override
 protected void onDestroy ()
 {
  Log.e (TAG, "onDestroy");
  super.onDestroy ();
 }

}

The first way is the code has been modified to remove the preservation and restoration of the code, rewrote onConfigurationChanged; In this case, whenever the user to rotate the screen will not be restarted Activity, and onConfigurationChanged code can be called. You can see from the renderings, anyway rotation not restart Activity.

6, the best practice of rotating screen

Below to start today's difficulties, is handling the article said at the beginning, when the asynchronous task execution, rotation, if solve the above problems.

First talk about the exploration process:

At first, I think this time the rotation is nothing more than a re-start threads, and will not cause an alarm, even if I just closed on the inside in onDestroy an asynchronous task on it. In fact, if I closed the last time the dialog will always exist; if I do not shut down, but activity will certainly be destroyed, dismiss the dialog box will be abnormal. Really very boring, and even if the dialog box is closed, the task turned off; the user rotates or cause to re-create the task from scratch loading data.

Now we hope to have a solution: Rotate the screen when loading data, does not load the task is interrupted and the user, wait boxes are displayed properly prior to loading is completed:

Fragment Of course, we also use the data to be saved, after all, this is the official recommended:

OtherRetainedFragment

package com.example.zhy_handle_runtime_change;

import Android.app.Fragment;
import android.os.Bundle;

/ **
 * Save the object Fragment
 *
 *
 * /
public class OtherRetainedFragment extends Fragment
{

 // Data object we want to retain
 // Save an asynchronous task
 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;
 }

 
}

And the difference between the above is not the only difference is that it objects to save an asynchronous programming task, I believe to see this, it is known a regular core of the above-mentioned problems, save an asynchronous task, in the restart, to continue the task .

package com.example.zhy_handle_runtime_change;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import android.os.AsyncTask;

public class MyAsyncTask extends AsyncTask < Void, Void, Void>
{
 private FixProblemsActivity activity;
 / **
  * Completion
  * /
 private boolean isCompleted;
 / **
  * Progress box
  * /
 private LoadingDialog mLoadingDialog;
 private List < String> items;

 public MyAsyncTask (FixProblemsActivity activity)
 {
  this.activity = activity;
 }

 / **
  * Initially, shows the loading boxes
  * /
 @Override
 protected void onPreExecute ()
 {
  mLoadingDialog = new LoadingDialog ();
  mLoadingDialog.show (activity.getFragmentManager (), "LOADING");
 }

 / **
  * Loading data
  * /
 @Override
 protected Void doInBackground (Void ... params)
 {
  items = loadingData ();
  return null;
 }

 / **
  * Loading completion callback Current 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 (5000);
  } Catch (InterruptedException e)
  {
  }
  return new ArrayList < String> (Arrays.asList ( "save large amounts of data through Fragment"
    "OnSaveInstanceState save data"
    "GetLastNonConfigurationInstance has been abandoned", "RabbitMQ", "Hadoop",
    "Spark"));
 }

 / **
  * Set Activity, Activity will always change because
  *
  * @param Activity
  * /
 public void setActivity (FixProblemsActivity activity)
 {
  // If the destruction of a Activity, Activity will be on a binding DialogFragment destruction
  if (activity == null)
  {
   mLoadingDialog.dismiss ();
  }
  // Set to the current Activity
  this.activity = activity;
  // Open a box and wait for the current Activity bound
  if (activity! = null &&! isCompleted)
  {
   mLoadingDialog = new LoadingDialog ();
   mLoadingDialog.show (activity.getFragmentManager (), "LOADING");
  }
  // If completed, the notification Activity
  if (isCompleted)
  {
   notifyActivityTaskCompleted ();
  }
 }

 private void notifyActivityTaskCompleted ()
 {
  if (null! = activity)
  {
   activity.onTaskCompleted ();
  }
 }

}

Asynchronous tasks, manage a dialog when the download before the start, progress box shows the progress of the download ends box disappears, and provide a callback for the Activity. Of course, running Activity constantly reboot, we also provide setActivity method, when onDestory, will setActivity (null) prevent memory leaks, and we will close the load box the bound; when the incoming new Activity onCreate we will open again in a loaded box, of course, because the rotation of the screen does not affect the loading of data, all the data continues in the background loading. It is not perfect ~

Main Activity:

package com.example.zhy_handle_runtime_change;

import java.util.List;

import android.app.FragmentManager;
import android.app.ListActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;

public class FixProblemsActivity extends ListActivity
{
 private static final String TAG = "MainActivity";
 private ListAdapter mAdapter;
 private List < String> mDatas;
 private OtherRetainedFragment 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 = (OtherRetainedFragment) 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)
  {
   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 ();

 }
 / **
  * Callback
  * /
 public void onTaskCompleted ()
 {
  mDatas = mMyTask.getItems ();
  mAdapter = new ArrayAdapter < String> (FixProblemsActivity.this,
    android.R.layout.simple_list_item_1, mDatas);
  setListAdapter (mAdapter);
 }

}

In onCreate, if the task is not turned on (first entered), open the task; if you have opened the call setActivity (this);

Add to the current task in onSaveInstanceState Fragment

I set the wait five seconds, enough to rotate back and forth three or four of the ~ ~ ~ ~ can see that although constantly restart, but did not affect the task of loading data loading operation and display box ~ ~ ~ ~

I can see the loading screen is rotated three heart mad ~ ~ but did not affect the results show that with the task of loading ~~

Finally, explain, in fact, not only is the screen rotation need to save the data, when users use your app, suddenly received a call, for a long time did not return to your app interface will cause the destruction and reconstruction of Activity, it is a behavior good App, it is necessary to have the ability to recover data ~.
     
         
         
         
  More:      
 
- Linux file system management partition, format, mount - label mount (Linux)
- Unable to start the network after restart clone a virtual machine (Linux)
- Linux serial debugging tools xgcom install (Linux)
- MongoDB start under Linux (Database)
- Nine artifact control disk partition under Linux (Linux)
- How to limit network bandwidth usage in Linux (Linux)
- First start with Kali Linux 2.0 (Linux)
- Java loop list to solve the problem of Joseph ring (Programming)
- Java JDK has been able to compile without warning (Programming)
- DataGuard add temporary data files bug (Database)
- Install Ruby on Rails in Ubuntu 15.04 in (Linux)
- Kali Linux resolve GPG error KEYEXPIRED 1425567400 (Linux)
- Installation Atom text editor on Mint Ubuntu / Linux (Linux)
- Ubuntu 14.04 compile, install, configure, the latest development version GoldenDict (Linux)
- Linux C programming and Shell Programming in the development of practical tools similarities summary (Programming)
- Using shell users or virtual users to login to pureftpd (Linux)
- MongoDB slice simple example (Database)
- About Linux iptables firewall interview questions and answers (Linux)
- PHP security Programming Advice (Programming)
- How screenshots from the Linux command line (Linux)
     
           
     
  CopyRight 2002-2020 newfreesoft.com, All Rights Reserved.