AsyncTask
在另一个线程中运行复杂任务是件好事。
但是当AsyncTask
仍在运行时,如果方向更改或其他配置发生更改,则会销毁并重新启动当前的Activity
。当AsyncTask
的实例与该活动相关联时,它会失败并导致“强制关闭”消息窗口。
所以,我正在寻找某种“最佳实践”来避免这些错误,并防止AsyncTask失败。
到目前为止我看到的是:
onRetainNonConfigurationInstance
Activity
被销毁时取消该任务,并在再次创建Activity
时重新启动该任务。一些代码示例:
Android AsyncTasks during a screen rotation, Part I和Part II
您能帮助我找到最佳解决方案并且易于实施的最佳方法吗?代码本身也很重要,因为我不知道如何正确解决这个问题。
答案 0 :(得分:131)
不使用android:configChanges
来解决此问题。这是非常糟糕的做法。
不也使用Activity#onRetainNonConfigurationInstance()
。这种模块化程度较低,不适合基于Fragment
的应用程序。
您可以read my article描述如何使用保留的Fragment
来处理配置更改。它解决了在旋转变化中很好地保留AsyncTask
的问题。您基本上需要在AsyncTask
内托管Fragment
,在setRetainInstance(true)
上致电Fragment
,并将AsyncTask
的进度/结果报告给Activity
{1}}通过保留的Fragment
。
答案 1 :(得分:33)
我通常通过让我的AsyncTasks在.onPostExecute()回调中触发广播Intent来解决这个问题,因此他们不会修改直接启动它们的Activity。活动使用动态BroadcastReceivers监听这些广播,并采取相应措施。
这样AsyncTasks就不必关心处理结果的特定Activity实例了。他们只是在他们完成时“大喊”,如果一个活动在那个时间(活跃且专注/处于恢复状态),这对任务的结果感兴趣,那么它将被处理。
这需要更多的开销,因为运行时需要处理广播,但我通常不介意。我认为使用LocalBroadcastManager而不是默认的系统范围可以加快速度。
答案 2 :(得分:24)
这是AsyncTask的另一个示例,它使用Fragment
来处理运行时配置更改(如用户旋转屏幕时)setRetainInstance(true)
。还演示了确定(定期更新)的进度条。
该示例部分基于官方文档Retaining an Object During a Configuration Change。
在此示例中,需要后台线程的工作仅仅是将图像从Internet加载到UI中。
Alex Lockwood似乎是正确的,当使用AsyncTasks使用"保留片段"处理运行时配置更改时。是最好的做法。在Android Studio中的Lint中不推荐使用onRetainNonConfigurationInstance()
。官方文档警告我们使用android:configChanges
,Handling the Configuration Change Yourself,...
自行处理配置更改会使使用备用资源变得更加困难,因为系统不会自动为您应用这些资源。当您必须避免因配置更改而重新启动时,此技术应被视为最后的手段,并且不建议用于大多数应用程序。
然后存在一个问题,即是否应该使用AsyncTask作为后台线程。
official reference for AsyncTask发出警告......
理想情况下,AsyncTasks应该用于短操作(最多几秒钟。)如果需要保持线程长时间运行,强烈建议您使用java.util.concurrent提供的各种API。 pacakge,如Executor,ThreadPoolExecutor和FutureTask。
或者,可以使用服务,加载器(使用CursorLoader或AsyncTaskLoader)或内容提供程序来执行异步操作。
我将帖子的其余部分分成:
从一个基本的AsyncTask开始,作为一个活动的内部类(它不需要是一个内部类,但它可能很方便)。在此阶段,AsyncTask不处理运行时配置更改。
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");
}
}
添加一个嵌套类RetainedFragment,它扩展了Fragement类,并且没有自己的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> {
....
在最外层的Activity类的onCreate()处理RetainedFragment:如果它已经存在则引用它(如果Activity正在重启);如果它不存在,则创建并添加它;然后,如果它已经存在,则从RetainedFragment获取数据并使用该数据设置UI。
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());
}
}
从UI启动AsyncTask
public void getPicture(View view) {
new LoadImageFromNetworkAsyncTask().execute(
"http://i.imgur.com/SikTbWe.jpg");
}
添加并编码确定的进度条:
活动布局。
<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>
Activity with:子类化AsyncTask内部类;子类化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>
答案 3 :(得分:3)
最近,我找到了一个很好的解决方案here。它基于通过RetainConfiguration保存任务对象。就我而言,解决方案非常优雅,对我来说,我已经开始使用它了。你只需要从basetask嵌套你的asynctask就可以了。
答案 4 :(得分:3)
基于@Alex Lockwood的回答和@William&amp; @quickdraw mcgraw在这篇文章中回答:How to handle Handler messages when activity/fragment is paused,我写了一个通用解决方案。
这样处理旋转,如果在异步任务执行期间活动进入后台,活动将在恢复后收到回调(onPreExecute,onProgressUpdate,onPostExecute&amp; onCancelled),因此不会抛出IllegalStateException(请参阅How to handle Handler messages when activity/fragment is paused)。
拥有相同但通用的参数类型会很棒,比如AsyncTask(例如:AsyncTaskFragment&lt; Params,Progress,Result&gt;),但我没有设法快速完成并且暂时没有时间。如果有人想要改进,请随意!
代码:
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 i.e. 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;
}
}
}
}
答案 5 :(得分:3)
您可以使用装载程序。在这里查看Doc
答案 6 :(得分:2)
对于那些想要躲避片段的人,可以使用onRetainCustomNonConfigurationInstance()和一些连线保留AsirectionTask在方向更改上运行。
(请注意,此方法可替代已弃用的onRetainNonConfigurationInstance())。
似乎这种解决方案并不经常被提及。 我写了一个简单的运行示例来说明。
干杯!
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();
}
}
答案 7 :(得分:1)
我已经实现了library,可以在执行任务时解决活动暂停和重新创建的问题。
您应该实施AsmykPleaseWaitTask
和AsmykBasicPleaseWaitActivity
。您的活动和后台任务将正常工作,即使您将旋转屏幕并在应用程序之间切换
答案 8 :(得分:-9)
要避免Activity销毁并创建自己,请在清单文件中声明您的活动: 的机器人:configChanges =“取向| keyboardHidden |屏幕尺寸强>
<activity
android:name=".ui.activity.MyActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/app_name">
正如docs
中提到的那样屏幕方向已更改 - 用户已旋转设备。
注意:如果您的应用程序的目标是API等级13或更高(如声明的那样) 通过minSdkVersion和targetSdkVersion属性),那么你应该 还声明了“screenSize”配置,因为它也会发生变化 当设备在纵向和横向之间切换时。