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