最佳实践:定位更改期间的AsyncTask

AsyncTask在另一个线程中运行复杂的任务是一件好事。

但是,当AsyncTask仍在运行时,如果有方向更改或其他configuration更改,则当前的Activity被销毁并重新启动。 而AsyncTask的实例连接到该活动,它失败,并导致“强制closures”消息窗口。

所以,我正在寻找某种“最佳实践”来避免这些错误,并防止AsyncTask失败。

我目前看到的是:

  • 禁用方向更改(当然不是你应该处理的方式)。
  • 让任务生存并通过onRetainNonConfigurationInstance通过新的活动实例进行onRetainNonConfigurationInstance
  • 只要在Activity被销毁时取消任务,并在Activity重新创build时重新启动它。
  • 将任务绑定到应用程序类而不是活动实例。
  • 在“货架”项目中使用的一些方法(通过onRestoreInstanceState)

一些代码示例:

屏幕旋转期间的Android AsyncTasks,第I 部分和第II部分

ShelvesActivity.java

你能帮我find最好的解决问题的办法,并且容易实施吗? 代码本身也很重要,因为我不知道如何正确解决这个问题。

不要使用android:configChanges来解决这个问题。 这是非常糟糕的做法。

不要使用Activity#onRetainNonConfigurationInstance() 。 这是模块化程度较低,不适合基于Fragment的应用程序。

您可以阅读我的文章,描述如何使用保留的Fragment处理configuration更改。 它很好地解决了旋转更改中保留AsyncTask的问题。 你基本上需要将你的AsyncTask托pipe在Fragment ,在Fragment调用setRetainInstance(true) ,并通过保留的FragmentAsyncTask的进度/结果报告给它的Activity

我通常通过让我的AsyncTasks在.onPostExecute()callback中激发广播意图来解决这个问题,所以他们不会直接修改启动它们的Activity。 活动使用dynamicBroadcastReceivers监听这些广播,并采取相应措施。

这样AsyncTasks不必关心处理结果的特定的Activity实例。 当他们完成时,他们只是“喊”,如果一个活动在那个对任务的结果感兴趣的时间(活跃并聚焦/处于恢复状态),那么将被处理。

这需要更多的开销,因为运行时需要处理广播,但我通常不介意。 我认为使用LocalBroadcastManager而不是默认的系统宽度加速了一点。

这里是AsyncTask的另一个例子,它用setRetainInstance(true)使用Fragment来处理运行时configuration更改(当用户旋转屏幕时setRetainInstance(true) 。 还确定了(定期更新的)进度条。

该示例部分基于官方文档, 在configuration更改期间保留对象 。

在这个例子中,需要一个后台线程的工作只是将来自互联网的图像加载到UI中。

亚历克斯·洛克伍德似乎是正确的,当涉及到处理运行时configuration更改与AsyncTasks使用“保留片段”是最佳实践。 onRetainNonConfigurationInstance()在Android Studio中的Lint中被弃用。 官方文档警告我们使用android:configChanges ,从处理configuration改变你自己 ,…

处理configuration更改可能使其使用替代资源变得更加困难,因为系统不会自动为您应用它们。 当您必须避免由于configuration更改而重新启动并且不推荐用于大多数应用程序时,应将此技术视为最后一招。

那么是否应该为后台线程使用AsyncTask是个问题。

AsyncTask的官方参考警告…

理想情况下,AsyncTasks应该用于短操作(最多几秒钟)。如果需要保持线程长时间运行,强烈build议您使用java.util.concurrent pacakge提供的各种API,例如执行器,ThreadPoolExecutor和FutureTask。

或者,可以使用服务,加载器(使用CursorLoader或AsyncTaskLoader)或内容提供者来执行asynchronous操作。

我把其余的post分解成:

  • 步骤; 和
  • 上述程序的所有代码。

步骤

  1. 从一个基本的AsyncTask开始,作为一个活动的内部类(它不需要是一个内部类,但它可能会很方便)。 在这个阶段,AsyncTask不处理运行时configuration更改。

     public class ThreadsActivity extends ActionBarActivity { private ImageView mPictureImageView; private class LoadImageFromNetworkAsyncTask extends AsyncTask<String, Void, Bitmap> { @Override protected Bitmap doInBackground(String... urls) { return loadImageFromNetwork(urls[0]); } @Override protected void onPostExecute(Bitmap bitmap) { mPictureImageView.setImageBitmap(bitmap); } } /** * Requires in AndroidManifext.xml * <uses-permission android:name="android.permission.INTERNET" /> */ private Bitmap loadImageFromNetwork(String url) { Bitmap bitmap = null; try { bitmap = BitmapFactory.decodeStream((InputStream) new URL(url).getContent()); } catch (Exception e) { e.printStackTrace(); } return bitmap; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_threads); mPictureImageView = (ImageView) findViewById(R.id.imageView_picture); } public void getPicture(View view) { new LoadImageFromNetworkAsyncTask() .execute("http://i.imgur.com/SikTbWe.jpg"); } } 
  2. 添加一个扩展了Fragement类的嵌套类RetainedFragment,并没有自己的UI。 将setRetainInstance(true)添加到此Fragment的onCreate事件中。 提供程序来设置和获取您的数据。

     public class ThreadsActivity extends Activity { private ImageView mPictureImageView; private RetainedFragment mRetainedFragment = null; ... public static class RetainedFragment extends Fragment { private Bitmap mBitmap; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // The key to making data survive // runtime configuration changes. setRetainInstance(true); } public Bitmap getData() { return this.mBitmap; } public void setData(Bitmap bitmapToRetain) { this.mBitmap = bitmapToRetain; } } private class LoadImageFromNetworkAsyncTask extends AsyncTask<String, Integer,Bitmap> { .... 
  3. 在最外面的Activity类的onCreate()处理RetainedFragment:引用它,如果它已经存在(如果活动正在重新启动); 创build并添加它,如果它不存在; 然后,如果它已经存在,从RetainedFragment获取数据,并设置您的用户界面的数据。

     public class ThreadsActivity extends Activity { ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_threads); final String retainedFragmentTag = "RetainedFragmentTag"; mPictureImageView = (ImageView) findViewById(R.id.imageView_picture); mLoadingProgressBar = (ProgressBar) findViewById(R.id.progressBar_loading); // Find the RetainedFragment on Activity restarts FragmentManager fm = getFragmentManager(); // The RetainedFragment has no UI so we must // reference it with a tag. mRetainedFragment = (RetainedFragment) fm.findFragmentByTag(retainedFragmentTag); // if Retained Fragment doesn't exist create and add it. if (mRetainedFragment == null) { // Add the fragment mRetainedFragment = new RetainedFragment(); fm.beginTransaction() .add(mRetainedFragment, retainedFragmentTag).commit(); // The Retained Fragment exists } else { mPictureImageView .setImageBitmap(mRetainedFragment.getData()); } } 
  4. 从UI启动AsyncTask

     public void getPicture(View view) { new LoadImageFromNetworkAsyncTask().execute( "http://i.imgur.com/SikTbWe.jpg"); } 
  5. 添加并编写确定的进度条:

    • 添加一个进度条到UI布局;
    • 在Activity oncreate()中获取对它的引用。
    • 在过程的开始和结束时使其可见和不可见;
    • 定义向onProgressUpdate中的UI报告的进度。
    • 将AsyncTask 2nd Generic参数从Void更改为可处理进度更新的types(例如Integer)。
    • 在doInBackground()中定期发布publishProgress。

上述程序的所有代码

活动布局。

 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.mysecondapp.ThreadsActivity"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin"> <ImageView android:id="@+id/imageView_picture" android:layout_width="300dp" android:layout_height="300dp" android:background="@android:color/black" /> <Button android:id="@+id/button_get_picture" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_below="@id/imageView_picture" android:onClick="getPicture" android:text="Get Picture" /> <Button android:id="@+id/button_clear_picture" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@id/button_get_picture" android:layout_toEndOf="@id/button_get_picture" android:layout_toRightOf="@id/button_get_picture" android:onClick="clearPicture" android:text="Clear Picture" /> <ProgressBar android:id="@+id/progressBar_loading" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/button_get_picture" android:progress="0" android:indeterminateOnly="false" android:visibility="invisible" /> </RelativeLayout> </ScrollView> 

活动与:子类AsyncTask内部类; 用于处理运行时configuration更改的子类RetainedFragment内部类(例如,当用户旋转屏幕时); 并定期更新确定的进度栏。 …

 public class ThreadsActivity extends Activity { private ImageView mPictureImageView; private RetainedFragment mRetainedFragment = null; private ProgressBar mLoadingProgressBar; public static class RetainedFragment extends Fragment { private Bitmap mBitmap; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // The key to making data survive runtime configuration changes. setRetainInstance(true); } public Bitmap getData() { return this.mBitmap; } public void setData(Bitmap bitmapToRetain) { this.mBitmap = bitmapToRetain; } } private class LoadImageFromNetworkAsyncTask extends AsyncTask<String, Integer, Bitmap> { @Override protected Bitmap doInBackground(String... urls) { // Simulate a burdensome load. int sleepSeconds = 4; for (int i = 1; i <= sleepSeconds; i++) { SystemClock.sleep(1000); // milliseconds publishProgress(i * 20); // Adjust for a scale to 100 } return com.example.standardapplibrary.android.Network .loadImageFromNetwork( urls[0]); } @Override protected void onProgressUpdate(Integer... progress) { mLoadingProgressBar.setProgress(progress[0]); } @Override protected void onPostExecute(Bitmap bitmap) { publishProgress(100); mRetainedFragment.setData(bitmap); mPictureImageView.setImageBitmap(bitmap); mLoadingProgressBar.setVisibility(View.INVISIBLE); publishProgress(0); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_threads); final String retainedFragmentTag = "RetainedFragmentTag"; mPictureImageView = (ImageView) findViewById(R.id.imageView_picture); mLoadingProgressBar = (ProgressBar) findViewById(R.id.progressBar_loading); // Find the RetainedFragment on Activity restarts FragmentManager fm = getFragmentManager(); // The RetainedFragment has no UI so we must reference it with a tag. mRetainedFragment = (RetainedFragment) fm.findFragmentByTag( retainedFragmentTag); // if Retained Fragment doesn't exist create and add it. if (mRetainedFragment == null) { // Add the fragment mRetainedFragment = new RetainedFragment(); fm.beginTransaction().add(mRetainedFragment, retainedFragmentTag).commit(); // The Retained Fragment exists } else { mPictureImageView.setImageBitmap(mRetainedFragment.getData()); } } public void getPicture(View view) { mLoadingProgressBar.setVisibility(View.VISIBLE); new LoadImageFromNetworkAsyncTask().execute( "http://i.imgur.com/SikTbWe.jpg"); } public void clearPicture(View view) { mRetainedFragment.setData(null); mPictureImageView.setImageBitmap(null); } } 

在这个例子中,库函数(引用上面的显式包前缀com.example.standardapplibrary.android.Network)做了真正的工作…

 public static Bitmap loadImageFromNetwork(String url) { Bitmap bitmap = null; try { bitmap = BitmapFactory.decodeStream((InputStream) new URL(url) .getContent()); } catch (Exception e) { e.printStackTrace(); } return bitmap; } 

将后台任务需要的权限添加到AndroidManifest.xml中

 <manifest> ... <uses-permission android:name="android.permission.INTERNET" /> 

将您的活动添加到AndroidManifest.xml …

 <manifest> ... <application> <activity android:name=".ThreadsActivity" android:label="@string/title_activity_threads" android:parentActivityName=".MainActivity"> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value="com.example.mysecondapp.MainActivity" /> </activity> 

最近,我在这里find了一个很好的解决scheme。 它基于通过RetainConfiguration保存任务对象。 就我而言,解决scheme非常优雅,而我已经开始使用它了。 你只需要把你的asynctask从基础任务中embedded就可以了。

基于@Alex Lockwood的答案和@William&@quickdraw mcgraw在这篇文章的答案: 如何处理处理器消息,当活动/片段暂停时 ,我写了一个通用的解决scheme。

这样处理循环,如果活动在asynchronous任务执行期间进入后台,则活动一旦恢复就会收到callback(onPreExecute,onProgressUpdate,onPostExecute和onCancelled),所以不会抛出IllegalStateException(请参阅如何处理Handler活动/片段暂停时的消息 )。

用AsyncTask(例如:AsyncTaskFragment <Params,Progress,Result>)来获得相同的generics参数将会非常好,但是我没有做到这一点,也没有时间。 如果有人想要改进,请随时免费!

代码:

 import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.os.Message; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v7.app.AppCompatActivity; public class AsyncTaskFragment extends Fragment { /* ------------------------------------------------------------------------------------------ */ // region Classes & Interfaces public static abstract class Task extends AsyncTask<Object, Object, Object> { private AsyncTaskFragment _fragment; private void setFragment(AsyncTaskFragment fragment) { _fragment = fragment; } @Override protected final void onPreExecute() { // Save the state : _fragment.setRunning(true); // Send a message : sendMessage(ON_PRE_EXECUTE_MESSAGE, null); } @Override protected final void onPostExecute(Object result) { // Save the state : _fragment.setRunning(false); // Send a message : sendMessage(ON_POST_EXECUTE_MESSAGE, result); } @Override protected final void onProgressUpdate(Object... values) { // Send a message : sendMessage(ON_PROGRESS_UPDATE_MESSAGE, values); } @Override protected final void onCancelled() { // Save the state : _fragment.setRunning(false); // Send a message : sendMessage(ON_CANCELLED_MESSAGE, null); } private void sendMessage(int what, Object obj) { Message message = new Message(); message.what = what; message.obj = obj; Bundle data = new Bundle(1); data.putString(EXTRA_FRAGMENT_TAG, _fragment.getTag()); message.setData(data); _fragment.handler.sendMessage(message); } } public interface AsyncTaskFragmentListener { void onPreExecute(String fragmentTag); void onProgressUpdate(String fragmentTag, Object... progress); void onCancelled(String fragmentTag); void onPostExecute(String fragmentTag, Object result); } private static class AsyncTaskFragmentPauseHandler extends PauseHandler { @Override final protected void processMessage(Activity activity, Message message) { switch (message.what) { case ON_PRE_EXECUTE_MESSAGE : { ((AsyncTaskFragmentListener)activity).onPreExecute(message.getData().getString(EXTRA_FRAGMENT_TAG)); break; } case ON_POST_EXECUTE_MESSAGE : { ((AsyncTaskFragmentListener)activity).onPostExecute(message.getData().getString(EXTRA_FRAGMENT_TAG), message.obj); break; } case ON_PROGRESS_UPDATE_MESSAGE : { ((AsyncTaskFragmentListener)activity).onProgressUpdate(message.getData().getString(EXTRA_FRAGMENT_TAG), ((Object[])message.obj)); break; } case ON_CANCELLED_MESSAGE : { ((AsyncTaskFragmentListener)activity).onCancelled(message.getData().getString(EXTRA_FRAGMENT_TAG)); break; } } } } // endregion /* ------------------------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------------------------ */ // region Attributes private Task _task; private AsyncTaskFragmentListener _listener; private boolean _running = false; private static final String EXTRA_FRAGMENT_TAG = "EXTRA_FRAGMENT_TAG"; private static final int ON_PRE_EXECUTE_MESSAGE = 0; private static final int ON_POST_EXECUTE_MESSAGE = 1; private static final int ON_PROGRESS_UPDATE_MESSAGE = 2; private static final int ON_CANCELLED_MESSAGE = 3; private AsyncTaskFragmentPauseHandler handler = new AsyncTaskFragmentPauseHandler(); // endregion /* ------------------------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------------------------ */ // region Getters public AsyncTaskFragmentListener getListener() { return _listener; } public boolean isRunning() { return _running; } // endregion /* ------------------------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------------------------ */ // region Setters public void setTask(Task task) { _task = task; _task.setFragment(this); } public void setListener(AsyncTaskFragmentListener listener) { _listener = listener; } private void setRunning(boolean running) { _running = running; } // endregion /* ------------------------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------------------------ */ // region Fragment lifecycle @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); } @Override public void onResume() { super.onResume(); handler.resume(getActivity()); } @Override public void onPause() { super.onPause(); handler.pause(); } @Override public void onAttach(Activity activity) { super.onAttach(activity); _listener = (AsyncTaskFragmentListener) activity; } @Override public void onDetach() { super.onDetach(); _listener = null; } // endregion /* ------------------------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------------------------ */ // region Utils public void execute(Object... params) { _task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params); } public void cancel(boolean mayInterruptIfRunning) { _task.cancel(mayInterruptIfRunning); } public static AsyncTaskFragment getRetainedOrNewFragment(AppCompatActivity activity, String fragmentTag) { FragmentManager fm = activity.getSupportFragmentManager(); AsyncTaskFragment fragment = (AsyncTaskFragment) fm.findFragmentByTag(fragmentTag); if (fragment == null) { fragment = new AsyncTaskFragment(); fragment.setListener( (AsyncTaskFragmentListener) activity); fm.beginTransaction().add(fragment, fragmentTag).commit(); } return fragment; } // endregion /* ------------------------------------------------------------------------------------------ */ } 

你需要PauseHandler:

 import android.app.Activity; import android.os.Handler; import android.os.Message; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Message Handler class that supports buffering up of messages when the activity is paused ie in the background. * * https://stackoverflow.com/questions/8040280/how-to-handle-handler-messages-when-activity-fragment-is-paused */ public abstract class PauseHandler extends Handler { /** * Message Queue Buffer */ private final List<Message> messageQueueBuffer = Collections.synchronizedList(new ArrayList<Message>()); /** * Flag indicating the pause state */ private Activity activity; /** * Resume the handler. */ public final synchronized void resume(Activity activity) { this.activity = activity; while (messageQueueBuffer.size() > 0) { final Message msg = messageQueueBuffer.get(0); messageQueueBuffer.remove(0); sendMessage(msg); } } /** * Pause the handler. */ public final synchronized void pause() { activity = null; } /** * Store the message if we have been paused, otherwise handle it now. * * @param msg Message to handle. */ @Override public final synchronized void handleMessage(Message msg) { if (activity == null) { final Message msgCopy = new Message(); msgCopy.copyFrom(msg); messageQueueBuffer.add(msgCopy); } else { processMessage(activity, msg); } } /** * Notification message to be processed. This will either be directly from * handleMessage or played back from a saved message when the activity was * paused. * * @param activity Activity owning this Handler that isn't currently paused. * @param message Message to be handled */ protected abstract void processMessage(Activity activity, Message message); } 

示例用法:

 public class TestActivity extends AppCompatActivity implements AsyncTaskFragmentListener { private final static String ASYNC_TASK_FRAGMENT_A = "ASYNC_TASK_FRAGMENT_A"; private final static String ASYNC_TASK_FRAGMENT_B = "ASYNC_TASK_FRAGMENT_B"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Button testButton = (Button) findViewById(R.id.test_button); final AsyncTaskFragment fragment = AsyncTaskFragment.getRetainedOrNewFragment(TestActivity.this, ASYNC_TASK_FRAGMENT_A); testButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if(!fragment.isRunning()) { fragment.setTask(new Task() { @Override protected Object doInBackground(Object... objects) { // Do your async stuff return null; } }); fragment.execute(); } } }); } @Override public void onPreExecute(String fragmentTag) {} @Override public void onProgressUpdate(String fragmentTag, Float percent) {} @Override public void onCancelled(String fragmentTag) {} @Override public void onPostExecute(String fragmentTag, Object result) { switch (fragmentTag) { case ASYNC_TASK_FRAGMENT_A: { // Handle ASYNC_TASK_FRAGMENT_A break; } case ASYNC_TASK_FRAGMENT_B: { // Handle ASYNC_TASK_FRAGMENT_B break; } } } } 

对于那些想要闪避碎片的人,可以使用onRetainCustomNonConfigurationInstance()和一些布线保留在方向更改上运行的AsyncTask。

(请注意,此方法是不推荐使用的onRetainNonConfigurationInstance()的替代方法)。

似乎这个解决scheme并不经常被提及。 我写了一个简单的例子来说明。

干杯!

 public class MainActivity extends AppCompatActivity { private TextView result; private Button run; private AsyncTaskHolder asyncTaskHolder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); result = (TextView) findViewById(R.id.textView_result); run = (Button) findViewById(R.id.button_run); asyncTaskHolder = getAsyncTaskHolder(); run.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { asyncTaskHolder.execute(); } }); } private AsyncTaskHolder getAsyncTaskHolder() { if (this.asyncTaskHolder != null) { return asyncTaskHolder; } //Not deprecated. Get the same instance back. Object instance = getLastCustomNonConfigurationInstance(); if (instance == null) { instance = new AsyncTaskHolder(); } if (!(instance instanceof ActivityDependant)) { Log.e("", instance.getClass().getName() + " must implement ActivityDependant"); } return (AsyncTaskHolder) instance; } @Override //Not deprecated. Save the object containing the running task. public Object onRetainCustomNonConfigurationInstance() { return asyncTaskHolder; } @Override protected void onStart() { super.onStart(); if (asyncTaskHolder != null) { asyncTaskHolder.attach(this); } } @Override protected void onStop() { super.onStop(); if (asyncTaskHolder != null) { asyncTaskHolder.detach(); } } void updateUI(String value) { this.result.setText(value); } interface ActivityDependant { void attach(Activity activity); void detach(); } class AsyncTaskHolder implements ActivityDependant { private Activity parentActivity; private boolean isRunning; private boolean isUpdateOnAttach; @Override public synchronized void attach(Activity activity) { this.parentActivity = activity; if (isUpdateOnAttach) { ((MainActivity) parentActivity).updateUI("done"); isUpdateOnAttach = false; } } @Override public synchronized void detach() { this.parentActivity = null; } public synchronized void execute() { if (isRunning) { Toast.makeText(parentActivity, "Already running", Toast.LENGTH_SHORT).show(); return; } isRunning = true; new AsyncTask<Void, Integer, Void>() { @Override protected Void doInBackground(Void... params) { for (int i = 0; i < 100; i += 10) { try { Thread.sleep(500); publishProgress(i); } catch (InterruptedException e) { e.printStackTrace(); } } return null; } @Override protected void onProgressUpdate(Integer... values) { if (parentActivity != null) { ((MainActivity) parentActivity).updateUI(String.valueOf(values[0])); } } @Override protected synchronized void onPostExecute(Void aVoid) { if (parentActivity != null) { ((MainActivity) parentActivity).updateUI("done"); } else { isUpdateOnAttach = true; } isRunning = false; } }.execute(); } } 

我已经实现了库 ,可以解决您的任务正在执行时的活动暂停和娱乐的问题。

你应该实现AsmykPleaseWaitTaskAsmykBasicPleaseWaitActivity 。 即使您将旋转屏幕并在应用程序之间切换,您的活动和后台任务仍可正常工作

你可以使用这个Loaders。 检查文件在这里

快速解决方法(不推荐)

为了避免一个Activity破坏并创build自己,就是在manifest文件中声明你的activity: android:configChanges =“orientation | keyboardHidden | screenSize

  <activity android:name=".ui.activity.MyActivity" android:configChanges="orientation|keyboardHidden|screenSize" android:label="@string/app_name"> 

正如它在文档中提到的

屏幕方向已更改 – 用户旋转了设备。

注意:如果您的应用程序的目标API级别为13或更高(由minSdkVersion和targetSdkVersion属性声明),则还应该声明“screenSize”configuration,因为当设备在纵向和横向之间切换时,configuration也会更改。