我有AsyncTask处理一些后台HTTP的东西。 AsyncTask按计划运行(警报/服务),有时用户手动执行它。
我处理来自SQLite的记录,我注意到服务器上的双帖,告诉我有时计划任务运行,同时用户手动运行,导致相同的记录从DB读取和处理两次。我在处理后删除了记录,但仍然可以得到它。
我该如何处理?也许组织一些排队?
答案 0 :(得分:16)
您可以使用executeOnExecutor()
Executor
上执行AsyncTask
要确保线程以串行方式运行,请使用:SERIAL_EXECUTOR
。
如果有多个活动正在访问您的数据库,为什么不创建一种网关数据库帮助程序并使用synchronized
块来确保只有一个线程可以立即访问它
答案 1 :(得分:10)
或者,您可以尝试此操作以查看任务当前是否正在运行:
if (katitsAsyncTask.getStatus().equals(AsyncTask.Status.FINISHED))
katitsAsyncTask.execute();
else
// wait until it's done.
答案 2 :(得分:6)
将AsyncTask初始化为null。如果为null,则仅创建一个新的。在onPostExecute中,最后再次将其设置为null。如果用户取消此操作,请在onCancelled中执行相同操作。这里有一些未经测试的代码来说明基本思想。
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class FooActivity extends Activity {
private class MyAsyncTask extends AsyncTask<Foo, Foo, Foo> {
@Override
protected void onPostExecute(Foo foo) {
// do stuff
mMyAsyncTask = null;
}
@Override
protected void onCancelled() {
// TODO Auto-generated method stub
mMyAsyncTask = null;
}
@Override
protected Foo doInBackground(Foo... params) {
try {
// dangerous stuff
} catch (Exception e) {
// handle. Now we know we'll hit onPostExecute()
}
return null;
}
}
private MyAsyncTask mMyAsyncTask = null;
@Override
public void onCreate(Bundle bundle) {
Button button = (Button) findViewById(R.id.b2);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (mMyAsyncTask == null) {
mMyAsyncTask = new MyAsyncTask();
mMyAsyncTask.execute(null);
}
}
});
}
}
答案 3 :(得分:1)
我知道这是不久前的事了,你已经解决了问题。但我刚遇到类似的问题。里诺的建议让我走上正轨,但对于那些一直难以填补空白的人来说。以下是我如何克服类似katit的问题。
我希望特定的AsyncTask只在当前没有运行的情况下运行。作为Reno建议的前瞻,已经创建了AsyncTask接口来处理正确处理Android线程的所有细节。这意味着,Executor是内置的。正如blog所暗示的那样:
“当在AsyncTask上调用execute(Object .. params)时,任务在后台线程中执行。根据平台,AsyncTasks可以串行执行(1.6之前,可能再4+),或同时执行(1.6) -3.2)。
为了确保按照您的要求串行或同时运行,从API Level 11开始,您可以使用executeOnExecutor(Executor executor,Object .. params)方法,并提供执行程序。为方便起见,该平台提供了两个执行器,分别可以作为AsyncTask.SERIAL_EXECUTOR和AsyncTask.THREAD_POOL_EXECUTOR访问。 “
因此,考虑到这一点,您可以通过AsyncTask接口进行线程阻塞,它还意味着您可以简单地使用AsyncTasks.getStatus()来处理线程阻塞,正如DeeV在此post上所建议的那样。
在我的代码中,我通过以下方式管理:
创建定义为:
的全局变量private static AsyncTask<String, Integer, String> mTask = null;
在onCreate中,将其初始化为我的AsyncTask实例,名为CalculateSpecAndDraw:
mTask = new CalculateAndDrawSpec();
现在,当我希望调用此AsyncTask时,我用以下内容包围执行:
if(mTask.getStatus() == AsyncTask.Status.FINISHED){
// My AsyncTask is done and onPostExecute was called
mTask = new CalculateAndDrawSpec().execute(Integer.toString(progress));
}else if(mTask.getStatus() == AsyncTask.Status.PENDING){
mTask.execute(Integer.toString(progress));
}else{
Toast.makeText(PlaySpecActivity.this, "Please Wait..", 1000).show();
}
如果它已经完成,则生成一个新线程,或者如果线程状态为PENDING,则线程已定义但尚未启动,我们启动它。但是否则如果线程正在运行,我们不会重新运行它,我们只是告知用户它没有完成,或执行我们希望的任何动作。然后,如果您想安排下一个事件而不是仅阻止它重新运行,请查看有关使用执行程序的this文档。
答案 4 :(得分:0)
尝试让一些实例布尔值在asynctask的preexecute上设置为“true”,然后在postexecute上设置为“false”。然后可能在doinbackground中检查该布尔值是否为真。如果是,则在该特定重复任务上调用cancel。
答案 5 :(得分:0)
您可以将任务状态保留在共享首选项中。在开始任务之前检查值(可能是布尔值)。在onPostExecute中将状态设置为finished(true?),在onPreExecute或构造函数中设置为false
答案 6 :(得分:0)
如何在synchronized
方法中包装 check-to-to-send 和 send-it 逻辑?这种方法似乎对我们有用。