編輯:關於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; } } }
在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
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(); }
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創建,看一下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"); }
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) { } }); }
通過對源碼的分析,我們知道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就是一個存儲消息的容器
先寫到這裡先,後續會繼續去完善
今天給大家講講android開發中比較常見的listView的下拉加載,其實也可以叫做分頁加載。為什麼會有這個叫法呢?說說我的理解吧!從字面上很好理解。當你滑動一個列表到
當ListView實例addheaderView()或者addFooterView後,再通過setAdapter來添加適配器,此時在ListView實例變量裡保存的適配器
我們在用手機的時候,如果來了短信,而我們沒有點擊查看的話,是不是在手機的最上邊的狀態欄裡有一個短信的小圖標提示啊?你是不是也想實現這種功能呢?今天的Notificatio
簡介: 一般我們在自定義ViewGroup 的時候會通常都會用到onInterceptTouchEvent ,onTouchEvent 這些方法去進行距離的判斷然後利用s