如何在 AsyncTask 为 运行 时禁用 Button? (Android)
How to disable Button while AsyncTask is running? (Android)
我正在尝试在执行下载任务时禁用按钮。我尝试过使用 setEnabled、setVisibility 和 setClickable。我想我尝试了这些选项的所有组合。他们都在任务执行时禁用按钮单击事件,但事件仍在以某种方式注册,当我反应按钮时,如果我在按钮被禁用时单击按钮,则会调用处理程序......即使它是隐形或 "gone"! (不知道是不是叫handler,想参考onClick方法)
我还插入了一个计数器和一个日志来验证我上面所说的。代码如下所示。这段代码 if(counter>1) return;
旨在阻止崩溃,但我想删除它,因为我想 re-enable 按钮,而不是永远禁用它。
点击:
public void downloadOnClick(View v) {
counter++;
Log.d(this.getLocalClassName(), "Button was clicked " + counter + " times.");
if(counter>1) return;
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
//mButton.setVisibility(View.GONE);
mButton.setEnabled(false);
//mButton.setClickable(false);
mTextView.setText("Getting html file...");
// if we use simple http, we will need to handle redirect status code
new DownloadWebpageTask().execute("https://www.google.com/");
} else {
mTextView.setText("No network connection available.");
}
}
AsyncTask:
private class DownloadWebpageTask extends AsyncTask<String, Void, String> {
private HttpURLConnection mConnection;
@Override
protected String doInBackground(String... urls) {
try {
URL url = new URL(urls[0]);
mConnection = (HttpURLConnection) url.openConnection();
mConnection.setReadTimeout(10000 /* milliseconds */);
mConnection.setConnectTimeout(15000 /* milliseconds */);
mConnection.setRequestMethod("GET");
mConnection.setDoInput(true);
mConnection.connect();
int statusCode = mConnection.getResponseCode();
if (statusCode != HttpURLConnection.HTTP_OK) {
return "Error: Failed getting update notes";
}
return readTextFromServer(mConnection);
} catch (IOException e) {
return "Error: " + e.getMessage();
}
}
private String readTextFromServer(HttpURLConnection connection) throws IOException {
InputStreamReader stream = null;
try {
stream = new InputStreamReader(connection.getInputStream());
BufferedReader br = new BufferedReader(stream);
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line + "\n");
line = br.readLine();
}
return sb.toString();
} finally {
if (stream != null) {
stream.close();
}
}
}
@Override
protected void onPostExecute(String result) {
mTextView.setText(result);
// Can not reactivate button / cancel (pending?) events....
//mButton.setVisibility(View.VISIBLE);
mButton.setEnabled(true);
//mButton.setClickable(true);
}
}
完整的项目(非常简单,只是一个训练示例)可以在我刚刚创建的这个 repository 中进行测试。
总而言之,根据我所读到的内容,实际上存在一个关于按钮禁用的问题。大多数情况下,这是通过使用标志来解决的,仅当标志为真时才调用 onClick 方法。虽然,这并没有解决 re-enabling 按钮的问题。我也试过 mButton.cancelPendingInputEvents();
但它不起作用(而且我不知道为什么。点击事件尚未注册?或者它们没有挂起?
这个问题有简单的解决方法吗?有任何想法吗?我是否遗漏了一些基本细节?如果没有,我正在考虑尝试以编程方式创建一个新按钮来解决问题。如果我不保留对旧按钮的引用,它们是否会通过垃圾删除?collection?
提前致谢!
[编辑] 澄清:
由于标题在这一点上可能会产生误导,所以我想澄清一下,我能够禁用并且 re-enable 按钮并且所有功能都正常 除非按钮被禁用。请注意,我添加了行 if(counter>1) return;
只是为了测试,但它会阻止按钮按我想要的方式工作(这就是为什么我不使用标志。我不希望这条线在我解决时出现问题!)。日志足以告诉我当按钮 re-enabled 时正在调用该方法,因为我在 禁用时单击了它!
错误在这里:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DOWNLOAD TEXT"
android:id="@+id/button"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:onClick="downloadOnClick" />
您缺少 OnClickListener 的概念!首先,你必须修改上面的xml这样删除onClick属性:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DOWNLOAD TEXT"
android:id="@+id/button"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
您必须修改 Activity onCreate 方法才能在您的按钮上设置 OnClickListener:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.text);
mButton = (Button) findViewById(R.id.button);
mButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
counter++;
Log.d(this.getLocalClassName(), "Button was clicked " + counter + " times.");
if(counter>1) return;
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
mButton.setEnabled(false);
mTextView.setText("Getting html file...");
// if we use simple http, we will need to handle redirect status code
new DownloadWebpageTask().execute("https://www.google.com/");
} else {
mTextView.setText("No network connection available.");
}
}
});
}
这是处理点击的正确方法。
查看更多:
此外:
我认为最好的方法是在 Activity:
上实现 OnClickListener()
public class MyActivity extends Activity implements View.OnClickListener {
}
通过这种方式,您可以为每个需要设置 OnClickListener 的按钮编写:
buttonX.setOnClickListener(this);
buttonY.setOnClickListener(this);
buttonZ.setOnClickListener(this);
在您的 Activity onClick() 中,您必须覆盖 OnClickListener 方法,因此:
@Override
public void onClick(View v) {
if(v.getId() == R.id.ButtonX)){
//do here what u wanna do.
} else if(v.getId() == R.id.ButtonY){
//do here what u wanna do.
} else if(v.getId() == R.id.ButtonZ){
//do here what u wanna do.
}
}
您还可以在 onClick 中使用 view.getId() 获取资源 ID,然后在 switch/case 块中使用它来识别每个按钮并执行相关操作。
我发现在您的示例中,AsyncTask
完成速度非常快,以至于 Button
由于被禁用而在很短的时间内无法点击。所以,这基本上是一个时间问题。
我发现通过将 Button
的重新启用延迟 4 秒,它可以按预期工作。
请注意此更改,从视觉上看,Button
在填充 TextView
后瞬间重新启用。
这是 onPostExecute()
中的代码更改:
@Override
protected void onPostExecute(String result) {
mTextView.setText(result);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
//re-enable the button
mButton.setEnabled(true);
}
}, 4000);
}
请注意,您可以删除计数器逻辑,它现在应该可以正常工作了:
public void downloadOnClick(View v) {
Log.d(this.getLocalClassName(), "Button was clicked");
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
mButton.setEnabled(false);
mTextView.setText("Getting html file...");
// if we use simple http, we will need to handle redirect status code
new DownloadWebpageTask().execute("https://www.google.com/");
} else {
mTextView.setText("No network connection available.");
}
}
我正在尝试在执行下载任务时禁用按钮。我尝试过使用 setEnabled、setVisibility 和 setClickable。我想我尝试了这些选项的所有组合。他们都在任务执行时禁用按钮单击事件,但事件仍在以某种方式注册,当我反应按钮时,如果我在按钮被禁用时单击按钮,则会调用处理程序......即使它是隐形或 "gone"! (不知道是不是叫handler,想参考onClick方法)
我还插入了一个计数器和一个日志来验证我上面所说的。代码如下所示。这段代码 if(counter>1) return;
旨在阻止崩溃,但我想删除它,因为我想 re-enable 按钮,而不是永远禁用它。
点击:
public void downloadOnClick(View v) {
counter++;
Log.d(this.getLocalClassName(), "Button was clicked " + counter + " times.");
if(counter>1) return;
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
//mButton.setVisibility(View.GONE);
mButton.setEnabled(false);
//mButton.setClickable(false);
mTextView.setText("Getting html file...");
// if we use simple http, we will need to handle redirect status code
new DownloadWebpageTask().execute("https://www.google.com/");
} else {
mTextView.setText("No network connection available.");
}
}
AsyncTask:
private class DownloadWebpageTask extends AsyncTask<String, Void, String> {
private HttpURLConnection mConnection;
@Override
protected String doInBackground(String... urls) {
try {
URL url = new URL(urls[0]);
mConnection = (HttpURLConnection) url.openConnection();
mConnection.setReadTimeout(10000 /* milliseconds */);
mConnection.setConnectTimeout(15000 /* milliseconds */);
mConnection.setRequestMethod("GET");
mConnection.setDoInput(true);
mConnection.connect();
int statusCode = mConnection.getResponseCode();
if (statusCode != HttpURLConnection.HTTP_OK) {
return "Error: Failed getting update notes";
}
return readTextFromServer(mConnection);
} catch (IOException e) {
return "Error: " + e.getMessage();
}
}
private String readTextFromServer(HttpURLConnection connection) throws IOException {
InputStreamReader stream = null;
try {
stream = new InputStreamReader(connection.getInputStream());
BufferedReader br = new BufferedReader(stream);
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line + "\n");
line = br.readLine();
}
return sb.toString();
} finally {
if (stream != null) {
stream.close();
}
}
}
@Override
protected void onPostExecute(String result) {
mTextView.setText(result);
// Can not reactivate button / cancel (pending?) events....
//mButton.setVisibility(View.VISIBLE);
mButton.setEnabled(true);
//mButton.setClickable(true);
}
}
完整的项目(非常简单,只是一个训练示例)可以在我刚刚创建的这个 repository 中进行测试。
总而言之,根据我所读到的内容,实际上存在一个关于按钮禁用的问题。大多数情况下,这是通过使用标志来解决的,仅当标志为真时才调用 onClick 方法。虽然,这并没有解决 re-enabling 按钮的问题。我也试过 mButton.cancelPendingInputEvents();
但它不起作用(而且我不知道为什么。点击事件尚未注册?或者它们没有挂起?
这个问题有简单的解决方法吗?有任何想法吗?我是否遗漏了一些基本细节?如果没有,我正在考虑尝试以编程方式创建一个新按钮来解决问题。如果我不保留对旧按钮的引用,它们是否会通过垃圾删除?collection?
提前致谢!
[编辑] 澄清:
由于标题在这一点上可能会产生误导,所以我想澄清一下,我能够禁用并且 re-enable 按钮并且所有功能都正常 除非按钮被禁用。请注意,我添加了行 if(counter>1) return;
只是为了测试,但它会阻止按钮按我想要的方式工作(这就是为什么我不使用标志。我不希望这条线在我解决时出现问题!)。日志足以告诉我当按钮 re-enabled 时正在调用该方法,因为我在 禁用时单击了它!
错误在这里:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DOWNLOAD TEXT"
android:id="@+id/button"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:onClick="downloadOnClick" />
您缺少 OnClickListener 的概念!首先,你必须修改上面的xml这样删除onClick属性:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DOWNLOAD TEXT"
android:id="@+id/button"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
您必须修改 Activity onCreate 方法才能在您的按钮上设置 OnClickListener:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.text);
mButton = (Button) findViewById(R.id.button);
mButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
counter++;
Log.d(this.getLocalClassName(), "Button was clicked " + counter + " times.");
if(counter>1) return;
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
mButton.setEnabled(false);
mTextView.setText("Getting html file...");
// if we use simple http, we will need to handle redirect status code
new DownloadWebpageTask().execute("https://www.google.com/");
} else {
mTextView.setText("No network connection available.");
}
}
});
}
这是处理点击的正确方法。
查看更多:
此外:
我认为最好的方法是在 Activity:
上实现 OnClickListener()public class MyActivity extends Activity implements View.OnClickListener {
}
通过这种方式,您可以为每个需要设置 OnClickListener 的按钮编写:
buttonX.setOnClickListener(this);
buttonY.setOnClickListener(this);
buttonZ.setOnClickListener(this);
在您的 Activity onClick() 中,您必须覆盖 OnClickListener 方法,因此:
@Override
public void onClick(View v) {
if(v.getId() == R.id.ButtonX)){
//do here what u wanna do.
} else if(v.getId() == R.id.ButtonY){
//do here what u wanna do.
} else if(v.getId() == R.id.ButtonZ){
//do here what u wanna do.
}
}
您还可以在 onClick 中使用 view.getId() 获取资源 ID,然后在 switch/case 块中使用它来识别每个按钮并执行相关操作。
我发现在您的示例中,AsyncTask
完成速度非常快,以至于 Button
由于被禁用而在很短的时间内无法点击。所以,这基本上是一个时间问题。
我发现通过将 Button
的重新启用延迟 4 秒,它可以按预期工作。
请注意此更改,从视觉上看,Button
在填充 TextView
后瞬间重新启用。
这是 onPostExecute()
中的代码更改:
@Override
protected void onPostExecute(String result) {
mTextView.setText(result);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
//re-enable the button
mButton.setEnabled(true);
}
}, 4000);
}
请注意,您可以删除计数器逻辑,它现在应该可以正常工作了:
public void downloadOnClick(View v) {
Log.d(this.getLocalClassName(), "Button was clicked");
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
mButton.setEnabled(false);
mTextView.setText("Getting html file...");
// if we use simple http, we will need to handle redirect status code
new DownloadWebpageTask().execute("https://www.google.com/");
} else {
mTextView.setText("No network connection available.");
}
}