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

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

最佳答案

奈杰尔克所说的是真的。

当您到达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);
         }
     }

}


也许有更好的方法可以做到这一点,但这很简单并且可以工作:)

希望能帮助到你。

干杯

10-08 03:04