我在后台线程(我使用AsyncTask)下载了一些来自互联网的数据,并在下载时显示进度对话框.方向更改,Activity重新启动,然后我的AsyncTask完成 - 我想关闭progess对话框并启动一个新的Activity.但是调用dismissDialog有时会抛出一个异常(可能是因为Activity被销毁而且还没有启动新的Activity).
处理此类问题的最佳方法是什么(从后台线程更新UI即使用户更改方向也能正常工作)?谷歌有人提供了一些"官方解决方案"吗?
我很困惑何时会在Handler上选择AsyncTask.假设我有一些代码,我想每n秒运行一次,这将更新UI.为什么我会选择一个而不是另一个?
我有一个AsyncTask对象,它在创建活动时开始执行,并在后台执行操作(下载最多100个图像).一切都很好,但有一种我不能理解的特殊行为.
例如:当Android屏幕的方向发生变化时,活动将被销毁并再次创建.所以我重写onRetainNonConfigurationInstance()方法并保存在AsyncTask中执行的所有下载数据.我这样做的目的是每次在方向更改期间销毁活动时都不会运行AsyncTask,但正如我在日志中可以看到的,之前的AsyncTask仍然在执行.(虽然数据保存正确)
我甚至尝试在活动的onDestroy()方法中取消AsyncTask,但日志仍然显示AsyncTask正在运行.
这是非常奇怪的行为,如果有人能告诉我停止/取消AsyncTask的正确程序,真的很感激.
谢谢
我对android中这种简单的常见情况有疑问.
我们有一个主要的活动,我们调用AsyncTask以及mainactivity的引用,以便AsyncTask可以更新MainActivity上的视图.
我将把事件分解为几步
上面的解决方案是按照"Pro Android 4"一书的建议在AsyncTask中保留WeakReference.
WeakReference<Activity> weakActivity;
in method onPostExecute
Activity activity = weakActivity.get();
if (activity != null) {
// do your stuff with activity here
}
Run Code Online (Sandbox Code Playgroud)
这是如何解决这种情况的?
我的问题是,如果我的asynctask正在下载10个文件,并且在完成5后重新启动活动(因为方向改变),那么我的FileDownloadingTask会再次被调用吗?
最初调用的先前AsyncTask会发生什么?
谢谢,我为问题的长度道歉.
我已经看过很多例子,他们似乎都以不同的方式解决了这个问题.基本上我只想要最简单的方法来做出不会锁定主线程并且可以取消的请求.
我们(至少)有两个HTTP库可供选择,java.net.*(例如HttpURLConnection)和org.apache.http.*也没有帮助.
关于最佳实践是什么,是否有任何共识?
尝试在Android上以可靠的方式执行异步操作是不必要的错综复杂的,即AsyncTask在概念上是否真的有缺陷,或者我只是缺少某些东西?
现在,这是在引入Fragments之前的全部内容.随着Fragments的引入,onRetainNonConfigurationInstance()已被弃用.因此,最新的Google宽恕黑客是使用持久的非UI片段,当发生配置更改时(即旋转屏幕,更改语言设置等),它会从您的Activity中附加/分离.
示例:https: //code.google.com/p/android/issues/detail?id = 23096#c4
从理论上讲,上面的黑客可以让你绕过可怕的:
IllegalStateException - "Can not perform this action after onSaveInstanceState"
Run Code Online (Sandbox Code Playgroud)
因为持久的非UI片段将接收onViewStateRestored()(或者onResume)和onSaveInstanceState()(或者onPause)的回调.因此,您可以判断实例状态何时被保存/恢复.这是一个很简单的代码,但是利用这些知识,您可以排队异步回调,直到活动的FragmentManager在执行它们之前将其mStateSaved变量设置为false.
mStateSaved是最终负责触发此异常的变量.
private void checkStateLoss() {
if (mStateSaved) {
throw new IllegalStateException(
"Can not perform this action after onSaveInstanceState");
}
if (mNoTransactionsBecause != null) {
throw new IllegalStateException(
"Can not perform this action inside of " + mNoTransactionsBecause);
}
}
Run Code Online (Sandbox Code Playgroud)
所以从理论上讲,现在你知道什么时候执行片段事务是安全的,因此你可以避免可怕的IllegalStateException.
错误!
上面的解决方案仅适用于Activity的FragmentManager.片段本身也有一个子片段管理器,用于嵌套片段.遗憾的是,子片段管理器根本不与Activity的片段管理器保持同步.因此,虽然活动的片段管理器是最新的,并且始终具有正确的mStateSaved; 儿童片段不这么认为,并且会在不适当的时候愉快地抛出可怕的IllegalStateException.
现在,如果您查看了支持库中的Fragment.java和FragmentManager.java,您将不会感到惊讶的是,所有与片段有关的内容都容易出错.设计和代码质量是......啊,有问题.你喜欢布尔吗?
mHasMenu = false
mHidden = false
mInLayout = …Run Code Online (Sandbox Code Playgroud) 我的应用运行正常,直到我在安装后的第一次启动中断初始化过程,只要初始化过程尚未完成,退出并启动应用程序几次.处理逻辑和AsyncTask可以很好地处理这个问题,所以我没有遇到任何不一致,但我的堆有问题.当我在应用程序设置中执行此令人不安的退出和启动时,它会越来越多,这将导致OutOfMemory错误.我已经通过MAT分析堆已经发现了泄漏,但我仍然有另一个泄漏,我无法隔离.
有关背景信息:我将应用程序上下文,列表和时间戳存储在静态类中,以便能够从应用程序中的任何位置访问它,而无需使用构造函数的繁琐的传递引用.无论如何,这个静态类(ApplicationContext)肯定有问题,因为它会因区域列表而导致内存泄漏.区域对象处理GeoJSON数据.这是这个类的样子:
public class ApplicationContext extends Application {
private static Context context;
private static String timestamp;
private static List<Zone> zones = new ArrayList<Zone>();
public void onCreate() {
super.onCreate();
ApplicationContext.context = getApplicationContext();
}
public static Context getAppContext() {
return ApplicationContext.context;
}
public static List<Zone> getZones() {
return zones;
}
public static void setData(String timestamp, List<Zone> zones) {
ApplicationContext.timestamp = timestamp;
ApplicationContext.zones = zones;
}
public static String getTimestamp() {
return timestamp;
}
}
Run Code Online (Sandbox Code Playgroud)
我已经尝试像这样存储区域
ApplicationContext.zones = new ArrayList(zones);
但它没有效果.我已经尝试将zones属性放入另一个静态类,因为ApplicationContext在所有其他类之前加载(由于AndroidManifest中的条目),这可能导致这种行为,但这也不是问题.
setData在我的"ProcessController"中调用两次.一旦进入doUpdateFromStorage,就进入doUpdateFromUrl(String).这个类看起来像这样:
public …Run Code Online (Sandbox Code Playgroud) 在我见过的许多例子中,AsyncTask扩展了,构造函数被覆盖,并且没有调用super().例如,在hackbod的这个答案中:
static class Worker extends AsyncTask<URL, Integer, Long> {
MyActivity mActivity;
Worker(MyActivity activity) {
mActivity = activity;
}
[...]
}
Run Code Online (Sandbox Code Playgroud)
新构造函数不会回调父的构造函数.
CommonsWare 在这个示例项目中有类似的代码.
这是正确的吗?或者应该super()真的被称为?
这是一个让我有点失踪的示例代码:
package com.leak;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
public class WindowLeakActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new LeakThread().execute();
}
class LeakThread extends AsyncTask<Void, Void,Void>{
ProgressDialog dialog;
@Override
protected void onPreExecute() {
dialog=new ProgressDialog(WindowLeakActivity.this);
dialog.show();
}
@Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(2000);
finish();
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void result) {
//that would be ok
if(WindowLeakActivity.this!=null && !WindowLeakActivity.this.isFinishing())
dialog.dismiss();
}
}} …Run Code Online (Sandbox Code Playgroud) java android garbage-collection android-asynctask android-activity
由于不建议Context在任务中保留对a的强引用(当任务仍在运行时上下文可能会被破坏,但是由任务保存在内存中),我想知道这些是否同样适用于Fragments?
片段管理其活动参考,并支持通过保留setRetainInstance.我可以假设,例如在片段中创建非静态内部AsyncTask是否安全,不会泄漏$this?