2012-05-29 52 views
2

我发现在我的任何应用程序中都有一个常见问题,即用户可能会意外地在同一个按钮上执行多次点击,导致多次执行onClick侦听器逻辑。通常,这些onClickListeners的业务逻辑通常包括启动执行HTTP请求的重进程AsynTask,并稍后修改UI。在按钮上处理多次按下的最佳做法

我的方法来防止asyntask的多次执行是无法在侦听器方法的开始按钮,并再次启用它作为onPostExecute的第一条语句。这对我来说一般是有效的,或者至少我没有收到关于这种情况的任何问题。

最近,一位同事指出了这种无法启用按钮方法的潜在问题。如下面的由两个按钮'+'和' - '组成的代码所示,对这些按钮的快速和备用按压会导致应用程序由ArrayOutOfIndex异常导致崩溃。

这个事实让我想到了管理onClickListener事件并发性的方法,如果真的有可能在第一个asyntask完成之前启动第二个asyntask,方法。

你有什么建议来处理这种情况?

对于那些建议应用某些逻辑来拒绝asyntask的第二次启动,直到完成第一个asyntask,是否真的值得通常将该逻辑用于通用应用程序,其中按钮执行http请求?。

CrashActivity.java

public class CrashActivity extends Activity { 

private int mNumbers[] = { 1, 2, 3, 4, 5 }; 
private int position = 0; 

/** Called when the activity is first created. */ 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    final TextView result = (TextView) findViewById(R.id.resultTextView); 

    final Button minusBtn = (Button) findViewById(R.id.minus_button); 
    final Button plusBtn = (Button) findViewById(R.id.plus_button); 

    minusBtn.setOnClickListener(new View.OnClickListener() { 
     public void onClick(View v) { 
      minusBtn.setEnabled(false); 
      plusBtn.setEnabled(true); 

      result.setText("" + mNumbers[--position]); 

      try { 
       Thread.sleep(1000); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 

      minusBtn.setEnabled((position > 0)); 
     } 
    }); 

    plusBtn.setOnClickListener(new View.OnClickListener() { 
     public void onClick(View v) { 
      plusBtn.setEnabled(false); 
      minusBtn.setEnabled(true); 

      result.setText("" + mNumbers[position++]); 

      try { 
       Thread.sleep(1000); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
      plusBtn.setEnabled((position <= 4)); 
     } 
    }); 

    minusBtn.setEnabled(false); 
} 
} 

main.xml中

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="fill_parent" 
android:layout_height="fill_parent" 
android:orientation="vertical" > 

<Button 
    android:id="@+id/minus_button" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="-" /> 

<Button 
    android:id="@+id/plus_button" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="+" /> 

<TextView 
    android:id="@+id/resultTextView" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="hello stackoverflow!" /> 

</LinearLayout> 

回答

1

问题,保证两种方法不要试图在同一时间将是更新UI溶液同步UI更新代码。您可以创建一个同步方法或一个充当代码块锁定的Object。例如:

public synchronized void updateUI() { 
    // ... 
} 

private Object mLock = new Object(); 

public void updateUI() { 
    // ... 
    synchronized (mLock) { 
     // Critical code here. 
    } 
    // ... 
} 

扩大这确保任务的任务2前1次完成,任务3,等完成之前,你需要以某种方式跟踪哪个先开始。注意:在本例中,同步发生在UI线程上。

private List<AsyncTask> mRunningTasks = new ArrayList<AsyncTask>(); 

public void onClick(View v) { 
    v.setEnabled(false); 
    if (v == task1View) { 
     Task1 task = new Task1(); 
     mRunningTasks.add(task); 
     task.execute(); 
    } 
    else if (v == task2View) { 
     Task2 task = new Task2(); 
     mRunningTasks.add(task); 
     task.execute(); 
    } 
    // ... 
} 

// Copy and paste for each necessary task. 
private Task1 extends AsyncTask<Void, Void, Void> { 
    protected Void doInBackground(Void... v) { 
     // Run task 1 code here. 
     while (this != mRunningTasks.get(0)) { 
      wait(1000); 
     } 
     return v[0]; 
    } 

    protected void onPostExecute(Void v) { 
     updateUI(); 
     mRunningTasks.remove(0); 
     task1View.setEnabled(true); 
    } 
} 

public void updateUI() { 
    // UI update code here. 
}