对于我的应用程序,我想禁用/更改按下的特定按钮。
我有一个名为btnClicked的onclick方法,其简化如下:
Public class MainActivity extends Activity{
Button myBytton;
@Override
protected void onCreate(Bundle savedInstanceState) {
myBytton = (Button)findViewById(R.id.buttonCall);
}
public void btnClicked(View view)
{
myBytton.setText("loading");
myBytton.setEnabled(false);
myBytton.setClickable(false);
// Do a call to an external api
callApi();
}
public void callApi(){
// run querys
if(succesullyCalledApi){
vibrator.vibrate(500);
// I tried commenting out the below part,
// it is than visible that the phone vibrates before it
// has changed the text (atleast a quarter of a second).
myBytton.setText("search");
myBytton.setEnabled(true);
myBytton.setClickable(true);
}
}
}
在callApi方法中是一种振动方法,它在函数得到结果后振动。 此外,如果callApi中有结果,myButton将被启用并且文本更改为搜索。
以下是:
我点击按钮,手机先振动,然后更改文字。
我的问题。
为什么callApi / vibrate在myBytton.setText之前运行?
答案 0 :(得分:1)
这是因为您对API的调用是在UI线程上完成的。即使您对UI进行了更改,屏幕也不会刷新,直到从单击按钮的事件调用的处理完成为止。在新线程上或通过异步任务调用您的API以获得您想要的行为。
答案 1 :(得分:1)
NigelK说的是真的。
当您到达btnClicked
方法时,所有说明都在UI线程上完成。因此,当您要求系统振动时,它将被阻止XX时间,具体取决于您传递给方法vibrator.vibrate(XX);
的时间。
为了避免这种情况"冻结"你需要在另一个线程上进行振动。
以下是它的样子:
Public class MainActivity extends Activity
{
Button myBytton;
@Override
protected void onCreate(Bundle savedInstanceState)
{
myBytton = (Button)findViewById(R.id.buttonCall);
}
public void btnClicked(View view)
{
myBytton.setText("loading");
myBytton.setEnabled(false);
myBytton.setClickable(false);
// Do a call to an external api
callApi();
}
public void callApi()
{
// run querys
if(succesullyCalledApi)
{
// here you create and run the Thread.
// put anything you want to do inside the run method
new Thread(
new Runnable()
{
public void run()
{
// here you start the vibration
vibrator.vibrate(500);
}
}
).start();
// I tried commenting out the below part,
// it is than visible that the phone vibrates before it
// has changed the text (atleast a quarter of a second).
myBytton.setText("search");
myBytton.setEnabled(true);
myBytton.setClickable(true);
}
}
}
就是这样。它将启动另一个将处理振动并且不冻结UI线程的线程。
这是AsyncTask版本:
扩展 AsyncTask 时询问的三个要素是:
doInBackground()
方法onProgressUpdate()
方法中传递的元素的类型。doInBackground()
方法返回的元素类型,也是onPostExecute()
方法的参数。这就是它的样子:
public class MyTask extends AsyncTask<Void, Integer, Boolean>
{
private Button mButton;
public MyTask(Button button)
{
mButton = button;
}
// Here everything will run on a background Thread
protected Boolean doInBackground(Void... voids)
{
boolean succesullyCalledApi = false;
// do your long querys here
// ...
return succesullyCalledApi;
}
// Here everything will run on the UI Thread
protected void onProgressUpdate(Integer... progress) {
// here you can make some update to the UI like updating a
// progress bar
}
// Here everything will run on the UI Thread
protected void onPostExecute(Boolean succesullyCalledApi)
{
if(succesullyCalledApi)
{
mButton.setText("search");
mButton.setEnabled(true);
mButton.setClickable(true);
// here you start the vibration
vibrator.vibrate(500);
}
}
}
在您的callApi()
方法中,您只需要这样:
public void callApi()
{
new MyTask(myButton).execute();
}
为了将查询检索回主线程(或UI线程),您所要做的就是......什么都没有。
调用onPostExecute()
方法时,您处于UI线程中。
但我认为您要将查询检索回 MainActivity 。为此:
processQuery()
(或任何您想要的)的方法,onPostExecute()
方法中调用此方法。以下是一些片段:
Public class MainActivity extends Activity
{
Button myBytton;
...
public void callApi()
{
// add this to the constructor
new MyTask(this, myButton).execute();
}
// I put String here but adapt it to your query Type.
public void processQuery(String query)
{
// process your query here.
}
}
public class MyTask extends AsyncTask<Void, Integer, Boolean>
{
private Button mButton;
private MainActivity mMainActivity;
public MyTask(MainActivity mainActivity, Button button)
{
mButton = button;
mMainActivity = mainActivity;
}
...
// Here everything will run on the UI Thread
protected void onPostExecute(Boolean succesullyCalledApi)
{
if(succesullyCalledApi)
{
// process your query
mMainActivity.processQuery("THE QUERY YOUR WANT TO PROCESS");
mButton.setText("search");
mButton.setEnabled(true);
mButton.setClickable(true);
// here you start the vibration
vibrator.vibrate(500);
}
}
}
可能有更好的方法可以做到这一点,但这个很简单并且有效:)
希望它有所帮助。
干杯
答案 2 :(得分:0)
因为您正在UI线程中执行所有操作。您必须使用here进行长时间运行。
尝试以下实施:
public void callApi() {
MyTask myTask = new MyTask();
myTask.execute();
}
private class MyTask extends AsyncTask<Void, Void, Boolean> {
protected void doInBackground(Void... params) {
// This runs on a separate background thread
boolean succesullyCalledApi = false;
// run querys
// do your long running query here and return its result.
return succesullyCalledApi;
}
protected void onPostExecute(Boolean succesullyCalledApi) {
// this runs on UI Thread
if(succesullyCalledApi){
vibrator.vibrate(500);
myBytton.setText("search");
myBytton.setEnabled(true);
myBytton.setClickable(true);
} else {
// You should better think this part also. what will happen if result is false?
}
}
}