Android 防止多次执行异步任务

Android 防止多次执行异步任务,android,android-asynctask,Android,Android Asynctask,我在单击按钮时从UI线程调用asynctask,该按钮执行一些HTTP Get请求 如果用户在当前任务完成之前再次单击按钮,会发生什么情况?这是由asynctask内部处理的,还是我需要自己处理?您可以在asynctask上调用getStatus()来检查它是否已经运行,在这种情况下单击“忽略”按钮 要做到这一点,您必须将AsyncTask的一个实例保存到某个地方并访问它。有两种方法 1:显示进度对话框并阻止用户进一步输入 2:在类作用域私有中创建AsyncTask变量。然后,此任务将不会运行超

我在单击按钮时从UI线程调用asynctask,该按钮执行一些HTTP Get请求


如果用户在当前任务完成之前再次单击按钮,会发生什么情况?这是由asynctask内部处理的,还是我需要自己处理?

您可以在
asynctask
上调用
getStatus()
来检查它是否已经运行,在这种情况下单击“忽略”按钮


要做到这一点,您必须将
AsyncTask
的一个实例保存到某个地方并访问它。

有两种方法

1:显示进度对话框并阻止用户进一步输入


2:在类作用域私有中创建AsyncTask变量。然后,此任务将不会运行超过一次。

另一个异步任务将生成,这可能会给您带来困难-保存数据时的竞争条件(如果您正在持久化数据),等等。我建议在接收
onClick
事件时禁用按钮,并显示一个说明如下的微调器:后台正在发生一些事情

我们在操作栏中放置了一个刷新按钮,实现了类似的功能。请注意,我们的异步任务在
app.Service
下运行,因此在配置更改期间(其中
hasStartedSync
获取重新初始化),我们依赖于“isTheSyncServiceRunning”检查

两种方式:

  • 在AsyncTask的
    onPreExeccute()
    中,显示一个带有
    setCancelable(false)
    的ProgressDialog。在AsyncTask调用的
    onPostExecute()
    OnProgressDialog()中。这将显示一个阻塞进度对话框。您也可以在此处显示一些消息或进度

  • 在AsyncTask的
    onPreExeccute()
    中,调用
    setEnabled(false)
    on按钮。在AsyncTask调用的
    onPostExecute()
    setEnabled(true)
    on按钮。这将在任务运行时禁用该按钮。也可以在这些点更改按钮文本。甚至可以临时用进度微调器(如ActionBar中的)替换它

  • 此外,您还可以在“运行”和“取消”行为之间切换按钮,就像现代web浏览器中的刷新按钮一样。这将为用户提供更多的控制

    注意事项:将
    onDoInBackground()
    中的所有内容包装在一个
    try catch
    中,以便AsyncTask始终正常退出,并且始终调用
    onPostExecute()
    。您可以从
    onPostExecute(result)
    的result参数判断HTTP请求是否得到了任何东西

    示例:只需调用此方法,单击一些
    按钮,即可从服务器将一些文本加载到
    TextView

    public static void runHTTP(final TextView targetView, final Button triggerBtn){
    
        //---new task----
        AsyncTask<Void,Void,String> task = new AsyncTask<Void, Void, String>(){
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
    
                //----disable button---
                triggerBtn.setEnabled(false);
    
                //---show message----
                targetView.setText("Loading...");
            }
    
            @Override
            protected void onPostExecute(String result) {
                super.onPostExecute(result);
    
                //----update result---
                targetView.setText(result);
    
                //----re-enable button---
                triggerBtn.setEnabled(true);
            }
    
            @Override
            protected String doInBackground(Void... voids) {
    
                //---default value--
                String result = "No Data";
    
                //--for safety--
                try{
    
                //-----do time consuming stuff here ---
    
                }catch (Exception e){
    
                    //---error value--
                    result = "Error fetching data";
                }
    
                return result;
            }
        };
    
        //----run task----
        task.execute();
    }
    
    publicstaticvoidrunhttp(最终文本视图targetView,最终按钮triggerBtn){
    //---新任务----
    AsyncTask任务=新建AsyncTask(){
    @凌驾
    受保护的void onPreExecute(){
    super.onPreExecute();
    //----禁用按钮---
    triggerBtn.setEnabled(false);
    //---显示消息----
    setText(“加载…”);
    }
    @凌驾
    受保护的void onPostExecute(字符串结果){
    super.onPostExecute(结果);
    //----更新结果---
    targetView.setText(结果);
    //----重新启用按钮---
    triggerBtn.setEnabled(真);
    }
    @凌驾
    受保护的字符串背景(无效…无效){
    //---默认值--
    String result=“无数据”;
    //--为了安全--
    试一试{
    //-----在这里做耗时的事情---
    }捕获(例外e){
    //---误差值--
    result=“获取数据时出错”;
    }
    返回结果;
    }
    };
    //----运行任务----
    task.execute();
    }
    
    为什么不使用布尔标志并检查其状态?我在我的永无止境的清单中使用了这种逻辑,它从未失败过

    doInBackground()中切换标志

    然后再次在
    onPostExecute()

    对于按钮的“单击侦听器”

    your_btn.setOnClickListener(new OnClickListener() {
    
        @Override
        public void onClick(View v) {
    
            if (loadingData == false)    {
                // RUN THE ASYNCTASK AGAIN
            } else if (loadingData == true) {
                // SHOW A TOAST THAT YOU ARE ALREADY FETCHING DATA
            }
        }
    });
    

    asynctask的实例不能执行多次。@njzk2但每次单击按钮都会创建一个新实例。然后由您决定。我建议在单击时停用该按钮,并仅在asynctask完成时(最有可能在onPostExecute中)重新激活该按钮。您也可以只有一个asynctask实例。好的,但是如果它已经在运行,而我再次按下它,会发生什么呢?它似乎没有抛出任何异常。你可以为每个按钮或类似的东西保留一个异步任务,如果它已经在运行,只需忽略按钮单击。我明白了。关于您的第二个选项:我是否应该在我的
    onCreate'方法上设置asynctask,并在我的按钮中设置它?@Johan如果这样做,您将无法再次运行它。有一个asynctask成员,因此您可以检查其状态,如果它已完成,您可以创建一个新的asynctask并分配给同一成员。是的,您可以这样做。并检查已经运行的异常。强制用户查看进度对话框是一个坏主意(您在google+或gmail应用程序中看到进度对话框了吗?)。。。用户应该能够在等待数据时执行其他操作(如关闭应用程序、更改设置…@lenik您有关于如何“拥有asynctask成员”的示例吗?thanksprogress对话框糟透了。。。你在google+或gmail应用程序中看到进度对话框了吗。。。更好的模式是将不确定的进度放在某个地方,并禁用不需要的UI(如此按钮),所以-1表示对话框,+1表示禁用button@Selvin选项是一个选项:)。此外,谷歌还创建了
    ProgressDialog
    ,这样至少在某些情况下会有一些用处。@Selvin就像当你的手机关机时,他们不能冒险让你
    @Override
    protected Void doInBackground(Void... params) {
    
        loadingData = true;
    }
    
    @Override
    protected void onPostExecute(Void result) {
    
        // CHANGE THE LOADINGMORE STATUS TO PERMIT FETCHING MORE DATA
        loadingData = false;
    }
    
    your_btn.setOnClickListener(new OnClickListener() {
    
        @Override
        public void onClick(View v) {
    
            if (loadingData == false)    {
                // RUN THE ASYNCTASK AGAIN
            } else if (loadingData == true) {
                // SHOW A TOAST THAT YOU ARE ALREADY FETCHING DATA
            }
        }
    });