我在點擊一個按鈕時從我的UI線程調用一個asynctask,該按鈕執行一些HTTP-Get請求。防止多次執行asynctask
如果用戶在當前任務完成之前再次單擊該按鈕,會發生什麼情況?這是由asynctask內部處理,還是我需要自己照顧它?
我在點擊一個按鈕時從我的UI線程調用一個asynctask,該按鈕執行一些HTTP-Get請求。防止多次執行asynctask
如果用戶在當前任務完成之前再次單擊該按鈕,會發生什麼情況?這是由asynctask內部處理,還是我需要自己照顧它?
將產生另一個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;
...
兩種方式:
在的AsyncTask的onPreExeccute()
顯示ProgressDialog其setCancelable(false)
。 AsyncTask的在ProgressDialog上調用dismiss()
。這將顯示阻止進度對話框。您也可以在此處顯示一些消息或進度。
在AsyncTask的onPreExeccute()
中,在Button上調用setEnabled(false)
。 AsyncTask的在Button上調用setEnabled(true)
。只要任務正在運行,這將禁用按鈕。您也可以在這些位置更改按鈕文字。甚至暫時用進度微調代替它(如在ActionBar中)。
此外,您可以在「運行」和「取消」行爲之間切換按鈕,就像現代Web瀏覽器中的刷新按鈕一樣。這將給用戶更多的控制權。
一個值得注意的:在try-catch
包裹內onDoInBackground()
一切,這樣的AsyncTask始終正常退出,並onPostExecute()
總是被調用。你可以根據onPostExecute(result)
的結果參數判斷HTTP請求是否有任何東西。
例子:只需調用此方法來從服務器加載一些文本到TextView
上的一些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();
}
進度對話很糟糕...你有沒有在google +或gmail應用程序中看到進度對話框? ...更好的模式是在某處放置未確定的未確定進度並禁用不需要的UI(如此按鈕),所以-1代表對話框,+1代表禁用按鈕 – Selvin
@Selvin選項是一個選項:)。另外,Google創建了'ProgressDialog',因此至少在某些情況下最好有一些用處。 –
@Selvin就像您的手機關機時一樣,他們無法冒險讓您對UI執行其他任何操作。 –
爲什麼不使用布爾標誌,並檢查它的狀態呢?我在永無止境的名單中使用這個邏輯,並且從未失敗過。
在onPostExecute()
@Override
protected void onPostExecute(Void result) {
// CHANGE THE LOADINGMORE STATUS TO PERMIT FETCHING MORE DATA
loadingData = false;
}
而且按鈕的點擊收聽
切換在doInBackground()
@Override
protected Void doInBackground(Void... params) {
loadingData = true;
}
的標誌,然後再
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'(通過調用'cancel'),那麼你還需要切換'onCancelled'中的標誌,因爲'onPostExecute'不會被調用。 –
@ dave.c:的確如此。但在這個問題的背景下,我覺得答案就足夠了。 –
我不認爲這會起作用。由於您正在調用新的'AsyncTask',因此您在不同的線程中更改'loadingData'值。 –
的AsyncTask的實例可以永遠不會被執行不止一次。 – njzk2
@ njzk2儘管每個按鈕點擊都會創建一個新實例。 – Johan
那麼它取決於你。我建議在單擊時停用按鈕,並且僅在完成asynctask時重新激活它(最有可能在onPostExecute中)。你也可以只有一個asynctask實例。 – njzk2