Android更改按钮文字需要很长时间

时间:2015-05-04 22:25:05

标签: android android-button android-vibration

对于我的应用程序,我想禁用/更改按下的特定按钮。

我有一个名为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之前运行?

3 个答案:

答案 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();
}

编辑2

为了将查询检索回主线程(或UI线程),您所要做的就是......什么都没有。

调用onPostExecute()方法时,您处于UI线程中。

但我认为您要将查询检索回 MainActivity 。为此:

  • MyTask 构造函数的参数中传递 MainActivity
  • 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?
    }
  }

}