2012-05-29 56 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. 
}