5

我正在单击一个按钮从我的 UI 线程调用一个异步任务,该按钮执行一些 HTTP-Get 请求。

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

4

5 回答 5

6

有两种方法可以做到这一点。

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

2:在私有类范围内创建 AsyncTask 变量。那么这将永远不会运行超过一次。

于 2012-11-27T08:59:01.640 回答
4

为什么不使用布尔标志并检查它的状态?我在我的永无止境的列表中使用了这个逻辑,它从来没有失败过。

切换标志doInBackground()

@Override
protected Void doInBackground(Void... params) {

    loadingData = true;
}

然后又在onPostExecute()

@Override
protected void onPostExecute(Void result) {

    // CHANGE THE LOADINGMORE STATUS TO PERMIT FETCHING MORE DATA
    loadingData = false;
}

而对于 Button 的点击监听器

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
        }
    }
});
于 2012-11-27T09:11:34.150 回答
2

您可以要求getStatus()AsyncTask检查它是否已经在运行并在这种情况下忽略按钮单击。

为此,您绝对需要保存AsyncTask某处的实例并可以访问它。

于 2012-11-27T08:56:53.403 回答
1

将产生另一个 AsyncTask,这可能会给您带来困难 - 如果您要持久保存数据,则会出现竞争条件等。我建议在接收onClick事件时禁用按钮并显示一些描述的微调器,表明在背景。

我们通过放置在操作栏中的刷新按钮实现了类似的效果。请注意,我们的异步任务app.Service在配置更改期间运行(hasStartedSync重新初始化),我们依赖“isTheSyncServiceRunning”检查。

// on setting the selection buttons up
public void onPrepareOptionsMenu(final Menu menu) {
 super.onPrepareOptionsMenu(menu);
 final MenuItem refreshItem = menu.findItem(id.sync);
  if (isSynchronisationServiceRunning() || hasStartedSync) {
   refreshItem.setEnabled(false);
   if (Build.VERSION.SDK_INT > 10) {
     // Replace the refresh icon with an indeterminate spinner for > 10 API.
     final LayoutInflater inflater = (LayoutInflater)getSherlockActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
     refreshItem.setActionView(inflater.inflate(layout.actionbar_indeterminate_progress, null));
   }
 }  else {
   refreshItem.setEnabled(true);
   refreshItem.setActionView(null);
 }
}


// on selection.
public boolean onOptionsItemSelected(final MenuItem item) {
 boolean isSelected;
 switch (item.getItemId()) {
   case id.sync:
     // Fire request to start GET here.
     hasStartedSync = true;
     invalidateOptionsMenu();
     break;
   ...
于 2012-11-27T09:03:48.780 回答
1

两种方式:

  1. onPreExeccute()AsyncTask 中显示一个 ProgressDialog 及其setCancelable(false). 在ProgressDialog 上onPostExecute()的 AsyncTask 调用中。dismiss()这将显示一个阻止进度对话框。您还可以在此处显示一些消息或进度。

  2. onPreExeccute()AsyncTask 中,调用setEnabled(false)Button。在Button 上onPostExecute()的 AsyncTask 调用中。setEnabled(true)只要任务正在运行,这将禁用该按钮。您还可以在这些点更改按钮文本。或者甚至暂时用进度微调器替换它(如在 ActionBar 中)。

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

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

示例:只需调用此方法即可TextView在单击 some 时将一些文本加载到从服务器中Button

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();
}
于 2012-11-27T09:06:34.503 回答