【Android】メインスレッドに素早く切り替えてUIを更新する方法

11478 ワード

これは最近ネットを見て、サブスレッドでUIを更新する方法で、多くの説がありますが、あまり全面的ではありません.ここで私は総括の全面的ないくつかをやり遂げることを努力して、后で自分に対して、みんなに対してすべていくつか助けがあることを望みます.
方法1:view.post(Runnable action)
このメソッドがサブスレッドにある場合
textView.post(new Runnable() {
        @Override
        public void run() {
            textView.setText("  textView");
            //          
            imageView.setBackgroundResource(R.drawable.update);
        }
    });

これはviewが持参した方法で、比較的簡単で、もしあなたのサブスレッドの中で更新するviewを得ることができるならば、この方法で更新することができます.
もう一つの方法があるpostDelayed(Runnable action,long delayMillis)は、送信を遅延させるために使用される.
方法2:activity.runOnUiThread(Runnable action)
このメソッドがサブスレッドにある場合
注意:contextオブジェクトがメインスレッドのMainActivityの場合、このように強く回転することができます.
public void updateUI(final Context context) {
        ((MainActivity) context).runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //        ,    UI 
            }
        });
    }

コンテキストがない場合は、次の方法を試してみます.1.用view.getContext()はコンテキストを得ることができます.2.contextをスキップしてnew Activity()をそのまま使用する.runOnUIThread(Runnable action)を使用して、プライマリ・スレッドに切り替えます.
方法3:Handlerメカニズム
まずメインスレッドでHandler,Handler mainHandler=new Handler()を定義する.(メインスレッドを操作するには、メインスレッドで定義する必要があります.他の場所で宣言を定義する場合は、このようにHandler mainHandler=new Handler(Looper.getMainLooper()と書き、メインスレッドのLooperとQueueを取得します)
Handlerを手に入れると簡単です.handlerを使います.Post(Runnable)メソッドは、handlerに依存するメッセージキュー(すなわち、プライマリスレッドメッセージキュー)にメッセージ処理を配置する.
(1):このメソッドがサブスレッドにある場合
    Handler mainHandler = new Handler(Looper.getMainLooper());
    mainHandler.post(new Runnable() {
        @Override
        public void run() {
            //      ,    UI
        }
    });

Handlerには次の方法があります.1.postAtTime(Runnable r, long uptimeMillis);//ある時点でメッセージ2を送信.postAtDelayed(Runnable r, long delayMillis);//遅延delayMillisミリ秒再送信メッセージ
(2):メインスレッドで
    Handler myHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what) {
                case 0:
                    //  UI 
                    break;
                case 1:
                     //  UI 
                    break;
                default:
                    break;
            }
        }
    }

その後mainHandlerをパラメータとして各クラス間に渡すことができ,UIを更新する必要がある場合,sendMessageの一連のメソッドを呼び出してhandleMessageでの操作を実行することができる.
サブスレッドにいるとします
    /**
      *    ,   obtainMessage()  ,      ,       。
      *    Messenger msg=new Messenger()    ,          ,        !
      *           ,           。(        )
      */
    Message msg = myHandler.obtainMessage();
    msg.what = 0; //    
    myHandler.sendMessage(msg); //    

上記のコードは、メッセージIDを送信しただけで、他のパラメータは送信されません.パラメータを渡すには、次のようにします.
      msg.what = 1;  //    
      msg.arg1=2;   //      ,        ,    arg1 arg2, Bundle     。
      msg.arg2=3;   //      
      Bundle bundle=new Bundle();
      bundle.putString("dd","adfasd");
      bundle.putInt("love",5);
      msg.setData(bundle);
      msg.obj=bundle;   //    Object       
      myHandler.sendMessage(msg); //                

まとめ:msg.objの機能は比較的に強く、Bundleを利用してデータを転送すると、効率が高く、メモリを節約できます.個人的には,伝達データの複雑さから,単純から複雑の順に用い,arg 1,setData(),objと考えられる.もっといいです.
もちろん、不要なコードを減らすために、簡略化された方法sendEmptyMessage(int what)を使用することができます.
 myHandler.sendEmptyMessage(0); //             

メッセージを送信する他の方法は、次のとおりです.
endEmptyMessageAtTime(int what, long uptimeMillis); //       
sendEmptyMessageDelayed(int what, long delayMillis); //       
sendMessageAtTime(Message msg, long uptimeMillis); //      
sendMessageDelayed(Message msg, long delayMillis); //      
sendMessageAtFrontOfQueue(Message msg); //      (  )

方法4:AsyncTaskの使用
/**
  *              :onPreExecute, doInBackground, onPostExecute
  */
    private class MyAsyncTask extends AsyncTask<String, Integer, String> {
        /**
         *       
         *  execute()        
         *              UI     
         */
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            System.out.println("MyAsyncTask.onPreExecute");
        }

        /**
         *       ,        ,    
         *           publishProgress(Progress... values)       。
         */
        @Override
        protected String doInBackground(String... params) {
            System.out.println("MyAsyncTask.doInBackground");
            //         
            int count = 0;
            for (int i = 0; i < 10; i++) {
                try {
                    count++;
                    publishProgress((count % 100) * 10);
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // publishProgress((int) ((count / (float) total) * 100));
            return "        ";
        }

        /**
         *       
         *    publishProgress(Progress... values) ,      ,          UI   
         */
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            progressBar.setProgress(values[0]);
            textView.setText("loading..." + values[0] + "%");
            System.out.println("MyAsyncTask.onProgressUpdate");
        }

        /**
         *      ,        ,        
         *                 ,        UI   。
         */
        @Override
        protected void onPostExecute(String aVoid) {
            super.onPostExecute(aVoid);
            System.out.println("MyAsyncTask.onPostExecute aVoid=" + aVoid);
            textView.setText(aVoid);
        }


        /**
         *       
         *          ,      。         UI
         */
        @Override
        protected void onCancelled() {
            super.onCancelled();
            System.out.println("MyAsyncTask.onCancelled");
            progressBar.setProgress(0);
            textView.setText("0");
        }

        @Override
        protected void onCancelled(String s) {
            super.onCancelled(s);
        }
    }

注意:doInBackgroundメソッドはサブスレッドにあるので、このメソッドでは時間のかかる操作を実行します.同時に、その戻り結果がonPostExecuteメソッドに渡されるため、onPostExecuteメソッドはUIスレッドで動作し、このメソッドでuiを更新し、uiを非同期で更新する目的を達成します.
Androidの非同期ロードデータとuiの更新については、AsyncTaskの非同期タスクだけでなく、多くのオープンソースのネットワークフレームワークを選択することができます.例えば、クリックしてより多くのxUtils 3、AsyncHttpClient、Okhttp、Volley、....これらの優れたネットワークフレームワークは、uiを非同期で更新することを非常に簡単にし、効率と性能も非常に高いです.もちろん、これらのネットワークフレームワークは決してこのような機能だけではありません.UIを非同期で更新するのは彼らの氷山の一角にすぎません.
androidネットワークフレームワークの詳細はこちらをクリックしてください