我在 UI 线程上点击按钮调用一个异步任务,该任务执行一些 HTTP-Get 请求。
如果用户在当前任务完成之前再次单击按钮,会发生什么?这是否由异步任务内部处理,还是我需要自行处理?
我在 UI 线程上点击按钮调用一个异步任务,该任务执行一些 HTTP-Get 请求。
如果用户在当前任务完成之前再次单击按钮,会发生什么?这是否由异步任务内部处理,还是我需要自行处理?
有两种方法可以做到这一点。
1:显示进度对话框并阻止用户进行进一步的输入。
2:在类范围内私有创建你的AsyncTask变量。这样它将永远不会再次运行。
onCreate
方法中设置异步任务,并在按钮中执行execute()
吗? - Johan@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;
}
对于按钮的点击监听器
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
}
}
});
cancel
取消了一个 AsyncTask
,那么您还需要在 onCancelled
中切换标志,因为 onPostExecute
不会被调用。 - dave.c如果您想检查AsyncTask
是否已在运行并希望忽略按钮点击,则可以在其上调用getStatus()
。
要实现这一点,您需要在某处保存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的onPreExecute()
中使用ProgressDialog,并使用setCancelable(false)
设置为不可取消。在AsyncTask的onPostExecute()
中调用ProgressDialog的dismiss()
方法。这将显示一个阻塞进度对话框。您还可以在此处显示一些消息或进度。
在AsyncTask的onPreExecute()
中,调用Button的setEnabled(false)
方法。在AsyncTask的onPostExecute()
中,调用Button的setEnabled(true)
方法。这将在任务运行时禁用按钮。您还可以在这些点上更改按钮文本。甚至可以暂时将其替换为进度旋转器(如ActionBar中的)。
此外,您可以在“运行”和“取消”之间切换按钮,就像现代Web浏览器中的刷新按钮一样。这将给用户更多控制权。
注意事项:将onDoInBackground()
中的所有内容都包裹在try-catch
中,以便AsyncTask始终正常退出,并且onPostExecute()
始终被调用。您可以从onPostExecute(result)
的结果参数判断HTTP请求是否有任何返回。
示例:只需在单击某个Button
时调用此方法,即可将一些文本从服务器加载到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();
}
ProgressDialog
,所以至少在某些情况下应该有一些用处。 - S.D.