Android AsyncTask - 避免多个实例运行

时间:2011-07-11 02:24:47

标签: android

我有AsyncTask处理一些后台HTTP的东西。 AsyncTask按计划运行(警报/服务),有时用户手动执行它。

我处理来自SQLite的记录,我注意到服务器上的双帖,告诉我有时计划任务运行,同时用户手动运行,导致相同的记录从DB读取和处理两次。我在处理后删除了记录,但仍然可以得到它。

我该如何处理?也许组织一些排队?

7 个答案:

答案 0 :(得分:16)

您可以使用executeOnExecutor()

Executor上执行AsyncTask

要确保线程以串行方式运行,请使用:SERIAL_EXECUTOR

其他:How to use an 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 逻辑?这种方法似乎对我们有用。