我在点击按钮时从我的UI线程调用asynctask,它执行一些HTTP-Get请求。
如果用户在当前任务完成之前再次单击该按钮会发生什么?这是由asynctask在内部处理,还是我需要自己处理它?</ p>
答案 0 :(得分:6)
有两种方法可以做到这一点。
1:显示进度对话框并阻止用户进一步输入。
2:在类范围private中创建AsyncTask变量。然后这将永远不会运行一次。
答案 1 :(得分: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
}
}
});
答案 2 :(得分:2)
您可以在getStatus()
上致电AsyncTask
以检查它是否已在运行,并在这种情况下忽略按钮点击。
要做到这一点,你绝对需要在某处保存AsyncTask
的实例并且可以访问它。
答案 3 :(得分: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;
...
答案 4 :(得分:1)
两种方式:
在AsyncTask的onPreExeccute()
中显示一个ProgressDialog及其setCancelable(false)
。在onPostExecute()
的AsyncTask中,在ProgressDialog上调用dismiss()
。这将显示阻止进度对话框。您还可以在此处显示一些消息或进度。
在AsyncTask的onPreExeccute()
中,在Button上调用setEnabled(false)
。在onPostExecute()
的AsyncTask中,在Button上调用setEnabled(true)
。只要任务正在运行,这将禁用该按钮。您还可以在这些点更改按钮文本。或者甚至用进度微调器暂时替换它(比如在ActionBar中)。
此外,您可以在“运行”和“取消”行为之间切换按钮,就像现代Web浏览器中的刷新按钮一样。这将为用户提供更多控制。
注意事项:将onDoInBackground()
内的所有内容包裹在try-catch
中,以便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();
}