Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android之handler篇

Android之handler篇

編輯:關於Android編程

Android的消息機制主要是指Handler的運行機制,Handler的運行需要底層的MessageQueue和Looper的支撐。對於有開發過Android經驗的童鞋都知道,我們一般都是用Handler來更新UI的,更新UI只是handler用法的一部分,下面一起來研究一下handler的神秘面紗。

那麼handler是什麼?

handler是android給我們用來更新UI的一套機制,也是一套消息處理機制,我們可以通過handler來發送消息,也可以通過它來處理消息

handler主要有以下4種用法

1、sendMessage

2、sendMessageDelayed

3、post(Runnable)

4、postDelayed(Runnable,long)

 

sendMessage

 

public class MainActivity extends Activity implements View.OnClickListener {
    private Button btn1;
    private Button btn2;

    private Handler handler = new Handler(){

        //這種方式我們在開發中用的比較多,在主線程中去更新UI
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Log.v("hjz","執行了handleMessage");
        }
    };

    private Handler handler1 = new Handler(new Handler.Callback() {

        //創建一個回調Callback,並實現handleMessage
        @Override
        public boolean handleMessage(Message msg) {
            Log.v("hjz","執行了Callback裡面的handleMessage");
            /**
             * 返回false,說明事件繼續向下分發,繼續調用下面的handleMessage方法
             * 返回true,說明自己消耗此事件,到此就結束了,起到攔截作用
             * 這種用法似曾相識吧,不錯,跟ViewGroup分發事件很類似
             */
            return false;
        }
    }){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Log.v("hjz","執行了handleMessage");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        setLister();
    }

    private void initView() {
        btn1 = (Button) findViewById(R.id.btn1);
        btn2 = (Button) findViewById(R.id.btn2);
    }

    private void setLister() {
        btn1.setOnClickListener(this);
        btn2.setOnClickListener(this);
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn1:
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Message msg = handler.obtainMessage();
                        msg.what = 1;
                        handler.sendMessage(msg);
                    }
                }).start();
                break;
            case R.id.btn2:
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Message msg = handler1.obtainMessage();
                        msg.what = 1;
                        handler1.sendMessage(msg);
                    }
                }).start();
                break;
        }
    }
}

xml

 

 


在Callback中handleMessage返回值為false時,點擊btn1 和 btn2打印日志:
07-19 21:16:31.091 9943-9943/com.example.handlerdemo V/hjz: 執行了handleMessage
07-19 21:16:34.341 9943-9943/com.example.handlerdemo V/hjz: 執行了Callback裡面的handleMessage
07-19 21:16:34.341 9943-9943/com.example.handlerdemo V/hjz: 執行了handleMessage

在Callback中handleMessage返回值為true時,點擊btn1 和 btn2打印日志:

 

 

07-19 21:23:18.991 22980-22980/com.example.handlerdemo V/hjz: 執行了handleMessage
07-19 21:23:20.901 22980-22980/com.example.handlerdemo V/hjz: 執行了Callback裡面的handleMessage
從打印的日志中也驗證了在上面handler1的分析

 

 

sendMessageDelayed

 

 case R.id.btn1:
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Message msg = handler.obtainMessage();
                        msg.what = 1;
                        /**
                         * 第一個參數是一個Message對象
                         * 第二次參數是延遲時間(單位毫秒)
                         */
                        handler.sendMessageDelayed(msg,1000);
                    }
                }).start();
                break;


 

post(Runnable)

 

private Handler postHandler = new Handler();
    private void setPost(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                postHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Log.v("hjz","postHandler");
                    }
                });
            }
        }).start();
    }

postDelayed(Runnable,long)

 

 

private Handler postDelayedHandler = new Handler();
    private void setPostDelayed(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                postDelayedHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        Log.v("hjz","postDelayedHandler");
                    }
                },1000);
            }
        }).start();
    }

上面就是handler的4種基本用法,如果這4種都跟進源碼裡去看,你會發現它們最終都會去調用sendMessageDelayed(getPostMessage(r), delayMillis)這個方法

 

接著我們一起分析Handler創建,看一下Handler的構造函數

 

 public Handler() {
        this(null, false);
    }

public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();   //獲取一個Looper對象,那麼Looper在什麼時候被創建呢?
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
通過源碼ActivityThread中main方法

 

 

public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        AndroidKeyStoreProvider.install();

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

  
        Looper.prepareMainLooper();//這句話創建了一個Looper對象,通過Looper構造方法創建一個MessageQueue對象,並將Looper對象存儲在ThreadLocal集合中,供後面在Handler創建時獲取對應的Looper對象(需注意拿到對應Looper對象也能拿到Looper對應的MessageQueue對象)

        ActivityThread thread = new ActivityThread(); //創建ActivityThread對象
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

一起來看一下上面thread.attach(false)這個方法,源碼

 

 

private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            ViewRootImpl.addFirstDrawHandler(new Runnable() {
                @Override
                public void run() {
                    ensureJitEnabled();
                }
            });
            android.ddm.DdmHandleAppName.setAppName("",
                                                    UserHandle.myUserId());
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            final IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                // Ignore
            }
            // Watch for getting close to heap limit.
            BinderInternal.addGcWatcher(new Runnable() {
                @Override public void run() {
                    if (!mSomeActivitiesChanged) {
                        return;
                    }
                    Runtime runtime = Runtime.getRuntime();
                    long dalvikMax = runtime.maxMemory();
                    long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
                    if (dalvikUsed > ((3*dalvikMax)/4)) {
                        if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
                                + " total=" + (runtime.totalMemory()/1024)
                                + " used=" + (dalvikUsed/1024));
                        mSomeActivitiesChanged = false;
                        try {
                            mgr.releaseSomeActivities(mAppThread);
                        } catch (RemoteException e) {
                        }
                    }
                }
            });
        } else {
            // Don't set application object here -- if the system crashes,
            // we can't display an alert, we just want to die die die.
            android.ddm.DdmHandleAppName.setAppName("system_process",
                    UserHandle.myUserId());
            try {
                mInstrumentation = new Instrumentation();
                ContextImpl context = ContextImpl.createAppContext(
                        this, getSystemContext().mPackageInfo);
                mInitialApplication = context.mPackageInfo.makeApplication(true, null);
                mInitialApplication.onCreate();
            } catch (Exception e) {
                throw new RuntimeException(
                        "Unable to instantiate Application():" + e.toString(), e);
            }
        }

        // add dropbox logging to libcore
        DropBox.setReporter(new DropBoxReporter());
//重點來看這裡
        ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
            @Override
            public void onConfigurationChanged(Configuration newConfig) {
                synchronized (mResourcesManager) {
                    // We need to apply this change to the resources
                    // immediately, because upon returning the view
                    // hierarchy will be informed about it.
                    if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) {
                        // This actually changed the resources!  Tell
                        // everyone about it.
                        if (mPendingConfiguration == null ||
                                mPendingConfiguration.isOtherSeqNewer(newConfig)) {
                            mPendingConfiguration = newConfig;
//通過一個handler來切換整個activity的生命周期,並實現將handle存儲在MessageQueue中
                            sendMessage(H.CONFIGURATION_CHANGED, newConfig); 
                        }
                    }
                }
            }
            @Override
            public void onLowMemory() {
            }
            @Override
            public void onTrimMemory(int level) {
            }
        });
    }

有興趣的可以自己研究一下ActivityThread中private class H extends Handler 這個內部類,裡面主要實現了activity相關生命周期切換

 

通過對源碼的分析,我們知道Looper創建是在Acitivity開始啟動時就創建了

Looper、MessageQueue和Handler的關系

Looper

1、內部包含一個消息隊列(MessageQueue),所有的Handler發送消息都走這個消息隊列

2、Looper.Looper方法,就是一個死循環,不斷從MessageQueue中取消息,如果有消息就處理消息,沒有消息就進入阻塞

 

MessageQueue

MessageQueue就是一個消息隊列,可以添加消息,並可以處理消息

 

Handler

Handler內部跟Looper進行關聯,也就是說在Handler的內部可以找到Looper,找到Looper也就可以找到了MessageQueue;在Handler中發送消息,其實就是向MessageQueue隊列中發送消息

總結一下三者的關系:handler負責發送消息,Looper負責接收Handler發送過來的消息,並直接把消息回傳給handler本身,MessageQueue就是一個存儲消息的容器

先寫到這裡先,後續會繼續去完善

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved