Android面接問題002 androidのHandlerメカニズム

4986 ワード

UIスレッドとは?
アプリケーションのメインUIスレッドの概念とその重要性は、Android開発者一人一人が理解しなければならないことです.アプリケーションが起動すると、アプリケーションのメインスレッド「main」が作成されます.このプライマリ・スレッド(すなわちUIプライマリ・スレッド)は、主に適切なviewまたはwidgetにイベントを配布する責任を負うため、非常に重要です.それはあなたのアプリケーションとアプリケーションのUIのインタラクティブなスレッドでもあります.たとえば、画面上のボタンをクリックすると、UIスレッドはビュー処理にクリック時間を渡し、ビューがイベントを受信するとpressed状態を設定し、イベントキューにinvalidateリクエストを送信します.UIスレッドはキューを順番に読み取り、viewに自分を再描画するように伝えます.
なぜAndroidのUI操作はスレッドが安全ではないのか
AndroidのUI操作はスレッドが安全ではないため、よく耳にする言葉です.だからハンドラーが現れた.
この言葉を理解するには、まずスレッドのセキュリティとは何かを知る必要があります.スレッドが安全ではないのは何ですか?
スレッドのセキュリティ:
複数のスレッドがアクセスする場合、ロックメカニズムを採用し、1つのスレッドがクラスのデータにアクセスすると、保護され、他のスレッドはスレッドが読み取り終わるまでアクセスできず、他のスレッドは使用できません.データの不一致やデータ汚染は発生しません.
スレッドが安全ではありません:
すなわち,ロックメカニズムを採用しない,すなわちデータアクセス保護を提供せず,複数のスレッドを同時にアクセスできる.これにより、複数のスレッドが前後してデータを変更し、得られたデータが汚いデータになる可能性がある.
したがってAndroidでは,複数のスレッドが同時にUIを変更すると,インタフェースが混乱する.ロックメカニズムを使用すると、実行効率が低下します.だからAndroidはスレッドが安全ではないが性能が良いという方法を選んだ.つまり、Androidはパフォーマンスを考慮してUIスレッドが安全ではないという話をよく耳にします.したがってAndroidはメインスレッドMainThreadを単一スレッドモデルとして設計し,メインスレッドでのみUI要素を変更できることを規定している.
マスタスレッドMainThreadは単一スレッドモデルであるため、マスタスレッドを時間をかけて操作することはできません.これによりuiスレッドがブロックされ、ページカートンが発生します.UIスレッドが5秒以上ブロックされている場合、ユーザーは「プログラム未応答」(ANR)のプロンプトダイアログボックスを受け取り、強制的に終了します.
ネットワーク要求、画像処理、データベース操作などの時間を費やし、ネットワーク要求、画像処理、データベース操作などのサブスレッド処理に置かなければならない.これらの操作の後、結果をユーザーにフィードバックし、ui操作を行う必要があります.
サブスレッドがUIを変更するには、メインスレッドに通知する必要があります.これは,スレッド間通信,すなわち,スレッド間の通信を実現するためのHandlerメッセージメカニズムの出現に関する.
いくつかの名詞を理解する
UIスレッド:メインスレッドです.UIスレッドを作成するときにLooperオブジェクトを初期化し、関連付けられたMessageQueue も作成します.
Handler:メッセージの送信と処理を行います.Handlerが正常に動作するには、現在のスレッドにLooperオブジェクトが必要です.
Message:Handlerが受信して処理するオブジェクト.HandlerはRunnableオブジェクトを受信して処理することもできる.
MessageQueue:メッセージキュー、管理Messageの先頭に立って、Looperオブジェクトを初期化すると、それに関連付けられたMessageQueue が作成されます.
Looper:各スレッドには1つのLooperしかありません.Looperは現在のスレッドのMessageQueueの作成と管理を担当しています.loopメソッドを呼び出すと、無限ループでMessageQueueからMessageを取り出して対応するHandlerに配布し、最後にhandleMessage()メソッドをコールしてこのメッセージを処理します.Looperこそメカニズム全体の核心だ!
Messageオブジェクトの内部実装はチェーンテーブルであり、最大長は50であり、メッセージオブジェクトをキャッシュし、メッセージオブジェクトを再利用する目的を達成し、メッセージオブジェクトの作成を減らすために、obtainMessageメソッドを使用してメッセージオブジェクトを取得するのが一般的である.
Handler実装手順
1.メインスレッドでHandler handle=new Handler()を使用してHandlerオブジェクトを作成し、handlenessageメソッドを書き換える
Hanldeを作成すると、この2つの方法が実行され、メインスレッドのLooperオブジェクトとmessageQueueオブジェクトが取得されます.
mLooper = Looper.myLooper();
mQueue = mLooper.mQueue;1.       Handler handle=new Handler()    Handler  
private final Handler mMessageHandler = new Handler(){
    @Override
    public void handleMessage(Message msg){
        ....;
    }
}
はmsgを認識する.whatは対応する操作を行います
2.実行終了後にsendMessageを介してスレッドを作成
 class DownloadThread extends Thread{
        @Override
        public void run() {
            try{
                System.out.println("      ");
                //     DownloadThread  5  ,         
                Thread.sleep(5000);
                System.out.println("      ");
                //         UI
              
              Message msg=new Message();
               handle.sendMessage(msg);

            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }

handler.postメソッドはコードを直接送信します.
new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            mTest.setText("post");//  UI
                        }
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

内部も呼び出し

sendMessageDelayedメソッドでは、RunnableをMessageオブジェクトにカプセル化し、m.callback=rでrunnableをコールバックに設定します.
Looper         messageQueue      ,     handle handlemessage       。
         Lopper      

handlerメモリの漏洩と解決方法
handleは静的内部クラスではないので、handleはactivityの参照を隠すことができます.Activityが回収されるのは、handlerが時間のかかる操作をしても解放されないためであり、handlerが保有するactivityの参照が解放されないため、activityが回収されずにメモリに残ってメモリが漏洩する
1.handlerを静的内部クラスに設定
2.handlerはactivityの弱い参照を持っている
3.ActivityライフサイクルonDestroyでhandlerを呼び出す.removeCallbackメソッド