我的程序在后台线程中执行一些网络活动.在开始之前,它会弹出一个进度对话框.该对话框在处理程序上被关闭.这一切都很好,除非在对话框启动时屏幕方向发生变化(后台线程正在运行).此时,应用程序崩溃或死锁,或进入一个奇怪的阶段,在应用程序完全无法工作之前,直到所有线程都被杀死.
如何优雅地处理屏幕方向变化?
下面的示例代码大致匹配我的真实程序:
public class MyAct extends Activity implements Runnable {
public ProgressDialog mProgress;
// UI has a button that when pressed calls send
public void send() {
mProgress = ProgressDialog.show(this, "Please wait",
"Please wait",
true, true);
Thread thread = new Thread(this);
thread.start();
}
public void run() {
Thread.sleep(10000);
Message msg = new Message();
mHandler.sendMessage(msg);
}
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
mProgress.dismiss();
}
};
}
Run Code Online (Sandbox Code Playgroud)
堆:
E/WindowManager( 244): Activity MyAct has …Run Code Online (Sandbox Code Playgroud) 我在后台线程(我使用AsyncTask)下载了一些来自互联网的数据,并在下载时显示进度对话框.方向更改,Activity重新启动,然后我的AsyncTask完成 - 我想关闭progess对话框并启动一个新的Activity.但是调用dismissDialog有时会抛出一个异常(可能是因为Activity被销毁而且还没有启动新的Activity).
处理此类问题的最佳方法是什么(从后台线程更新UI即使用户更改方向也能正常工作)?谷歌有人提供了一些"官方解决方案"吗?
我读了很多关于如何保存我的实例状态或如何在屏幕旋转期间处理我的活动被破坏的内容.
似乎有很多可能性,但我还没有想出哪一个最适合检索AsyncTask的结果.
我有一些AsyncTasks只是再次启动并调用isFinishing()活动的方法,如果活动正在完成,他们不会更新任何东西.
问题是我有一个任务对Web服务发出请求失败或成功的任务,并且重新启动任务会导致用户的经济损失.
你怎么解决这个问题?可能的解决方案有哪些优点或缺点?
我有疑问让我感到困惑.
想象一下,我想在另一个线程中做一些事情,比如获取GPS /位置内容,这些内容按照SDK文档中的建议,必须使用后台线程.
所以这里有一个问题:两者之间有什么区别
Thread通过AND在后台创建AsyncTask
创建Thread thread1 = new Thread(new Runnable()......并实施run()?
multithreading android runnable android-asynctask android-threading
我目前正在团队中开发一些Android应用程序,我们在过去几个月中使用了两种不同的方法(一种是我个人喜欢的,另一种是另一种开发者喜欢的).
虽然到目前为止结果是一样的,但这让我感到疑惑...我们应该:
Google建议使用哪种方法?
您的经验对此有何看法(优点,缺点,问题)?
我可以知道知道某项活动是否已被销毁的正确方法是什么?目前,我使用以下方式.
private volatile boolean isOnDestroyCalled = false;
@Override
protected void onDestroy() {
super.onDestroy();
isOnDestroyCalled = true;
}
public boolean isOnDestroyCalled() {
return this.isOnDestroyCalled;
}
Run Code Online (Sandbox Code Playgroud)
有没有比上面更好的方法?
阅读了开发者网站上的Android服务的大部分可用文档,并在stackoverflow中,我仍然对在单独任务中运行服务的几个方面感到困惑.希望有人可以让我走上正轨.
假设我们有像trival这样的服务框架
public class HliService extends Service {
@Override
public void onCreate() {
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// If we get killed, after returning from here, restart
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
@Override
public void onDestroy() {
}
}
Run Code Online (Sandbox Code Playgroud)
在清单中,我有
<service android:name=".HliService" android:process=":HLI_Comms"/>
Run Code Online (Sandbox Code Playgroud)
这样服务就可以在自己的线程中运行.
该服务的目的是提供一个后台任务,该任务将使用TCP套接字与设备通信并执行其他操作.有可能忽略电池问题等,基本上我希望它能永远运行.
就像是
// Method that communicates using a TCP socket, and needs to send …Run Code Online (Sandbox Code Playgroud) 在处理AsyncTasks和屏幕旋转时,我仍然试图找到"正确的"设计模式.我读了这篇链接到这段代码的commonsware博文,但现在不推荐使用onRetainNonConfigurationInstance方法.文档中的神奇句子指出"在切换到下一个活动期间没有消息处理的保证简化了对活动对象的使用......"这是关于这个方法做了什么的真正关键部分.我没有看到使用setRetainInstance()能够实现相同目标的建议.
我也看到了这样的帖子,其中第一个答案实际上是一个糟糕的黑客,只覆盖了90%的用例(即如果你的任务正在运行然后打个电话会发生什么,该解决方案不会工作).
有人建议在这里查看AsyncTask示例的代码,但除非我是密集的,否则我看不到它们在应用程序的任何地方使用(在谷歌代码上使用搜索功能时)
这个问题显然已被多次询问,但我没有看到最新的,适当的asnwer.如果存在,请回答并关闭,如果必须,但至少回答!:)
这是另一个链接,它检查相同的,已弃用的方法.
我有一个包含Fragment的片段活动,Fragment启动一个下载一些数据的Asynctask,我在Fragment中实现了一个回调方法,它更新了适配器和listview中的一些值.我遇到的问题如下:这是我的onCreateView方法(重要部分):
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
list=(PullToRefreshListView)v1.findViewById(R.id.listapull);
adapterList=new ListViewAdapter(secciones, mContext);
}
Run Code Online (Sandbox Code Playgroud)
当我在AsyncTask运行时旋转设备时,doInBackground()方法继续运行,然后在执行后它触发侦听器并在我的片段中启动回调方法,此方法具有我的适配器和列表视图的旧引用:

当方向发生变化并且这是正确的时,会重新创建片段及其内容,但有没有人知道为什么回调方法保持对适配器和listview的引用,以及在方向更改之前创建的位置?
编辑:
我有一个执行asynctask的按钮,如下所示:
asyncRefresh = new PullRefreshTask(taskContext, mContext, secciones);
asyncRefresh.setUpdatePull2RefreshListener(this);
asyncRefresh.execute();
Run Code Online (Sandbox Code Playgroud)
如果用户按下按钮,asyncTask会将旧的Fragment设置为侦听器,并且当asynctask运行时发生方向更改时,我认为激活的回调方法是新创建的片段方法中的方法,但我不确定了.
编辑2:
我已经解决了我的问题,正如我在第一次编辑中所说的那样,旧的片段正在调用回调方法.所以我所做的是将我的asynctask保存在另一个名为"Info"的类中的变量中,并在创建视图中我这样做:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
list=(PullToRefreshListView)v1.findViewById(R.id.listapull);
adapterList=new ListViewAdapter(secciones, mContext);
PullRefreshTasktask task = Info.getAsyncTask();
asyncRefresh = task;
asyncRefresh.setUpdatePull2RefreshListener(this);
}
Run Code Online (Sandbox Code Playgroud)
这样我就可以在我的片段中设置片段的新引用
setUpdatePull2RefreshListener()
运行asynctask的方法
产生耗时的计算线程是很常见的.之后,我们需要更新Activity或Fragment计算结果.
一直以来,我遵循以下准则.到目前为止,它对我很有用.
setRetainInstance(true)UI片段.setTargetFragment和getTargetFragment技术setRetainInstance(true)UI片段.onAttach和onDetach存储引用Activity.谷歌似乎不鼓励使用getActivity.http://developer.android.com/guide/components/fragments.html但是,从一个类派生的情况怎么样View?我计划AsyncTask从自定义启动View.但是,我怎么能onPostExecute回到View?
我之所以这么说的原因是,在我的自定义视图中,某些触摸事件会触发它使用新的位图重绘自身.生成新位图非常耗时.因此,我计划启动AsyncTask,生成这样的位图,然后传回自定义View.但是,配置更改可能会导致重新创建自定义View.因此,我需要确保我的AsyncTask可以在期间具有正确的View引用onPostExecute.
目前我正在使用异步http库来对我们的服务器执行http请求.然而,这会带来一个问题,即如果在屏幕旋转期间正在进行http调用,我们将在调用结束时引用旧的上下文.我通过保持对onCreate中捕获的最新实例的静态引用来解决这个问题,并使用该引用调用方法(并在onDestroy中将其置空).它运作正常但似乎是一个黑客.我见过有人推荐使用片段来解决这个问题,比如这里:
http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html
这似乎是好主意,但我想我可以通过简单地让我的Activity扩展FragmentActivity并使用AsyncTaskLoader子类来实现这一点,该子类专门用于我正在做的事情.
这是我的想法:使用ApiRequest实现AsyncTaskLoader并返回ApiResponse.但是,我希望能够继承HttpAsyncTask并覆盖一个解析响应的方法,这样我就可以解析响应并将其转换为另一种扩展ApiResponse的对象.我不知道如何指定类型参数来实现这一点.
这是我的代码:
public class HttpAsyncTaskLoader</*not sure what to put here*/> extends AsyncTaskLoader<? not sure ?> {
private ApiClient mClient ;
private ApiRequest mRequest;
private volatile boolean isExecuting = false;
public HttpAsyncTaskLoader(Context context, ApiClient client, ApiRequest request) {
super(context);
mClient = client;
mRequest = request;
}
/**
* Subclasses should override this method to do additional parsing
* @param response
* @return
*/
protected /*subclass of ApiResponse (or ApiResponse itself)*/ onResponse(ApiResponse response)
{
//base implementation just returns the …Run Code Online (Sandbox Code Playgroud)