編輯:關於Android編程
一、ThreadLocal的分析:
從字面上這個Threadlocal很容易讓人引起誤解,認真是一個本地 thread,實際上這是一個Thread的本地信息變量,也就是說用來存儲線程中不安全變量的一個機制。分析如下:
ThreadLocal類接口很簡單,只有4個方法,我們先來了解一下:
void set(Object value)
設置當前線程的線程局部變量的值。
· public Object get()
該方法返回當前線程所對應的線程局部變量。
· public void remove()
將當前線程局部變量的值刪除,目的是為了減少內存的占用,該方法是JDK 5.0新增的方法。需要指出的是,當線程結束後,對應該線程的局部變量將自動被垃圾回收,所以顯式調用該方法清除線程的局部變量並不是必須的操作,但它可以加快內存回收的速度。
protected Object initialValue()
返回該線程局部變量的初始值,該方法是一個protected的方法,顯然是為了讓子類覆蓋而設計的。這個方法是一個延遲調用方法,在線程第1次調用get()或set(Object)時才執行,並且僅執行1次。ThreadLocal中的缺省實現直接返回一個null。
對於每個線程,同名的變量,我們可以新建一個實例,並以Thread.currentThread為key保存到ThreadLocal中。當我們用到的時候,通過get()獲取。
對於Handler,通常存的是 mLooper
二、Handler究竟是運行在子線程還是主線程
來看看Handler的構造函數,這裡面有一個變量進行如下操作:
mLooper = Looper.myLooper();
上面的調用實際是如下操作:
public static Looper myLooper() {
return sThreadLocal.get();
}
也就是獲取當前線程的Looper,這樣看來,Handler運行環境不是確定的,而是在哪個線程創建這個handler,在主線程創建就運行在主線程,否則就是子線程。
三、如何正確啟動一個子線程:
//在主線程先創建一個HandlerThread
HandlerThread mHandlerThread = new HandlerThread("XXX");
//第二步,是創建一個自己的Looper
mHandlerThread.start();
創建一個繼承自Handler的子類,將上面創建的Looper賦給這個子類,在創建的時候,這樣,我們就是創建一個不是運行在主線程的子線程了。否則,默認的是使用啟動Handler的線程的Looper。
class myThread extends Handler {
public myThread (Looper looper) {
super(looper);
}
public myThread() {
super();
}
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
switch (msg.what) {
case 1:
try {
Thread.sleep(20* 1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
}
}
//初始化
mHandlerThread = new HandlerThread("handler");
mHandlerThread.start();
//創建子線程
mHandler = new myThread(mHandlerThread.getLooper());
四、IntentService
IntentService繼承自Service,它能夠在後台運行不阻塞主線程主要歸於它內部開啟一個工作線程,也就是創建一個繼承自Handler的ServiceHandler,只是這個handler的looper是新創建的,不同於主線程的Looper,因而不會阻塞主線程。
public abstract class IntentService extends Service {
}
當我們通過Intent啟動一個IntentService的時候,先進入onCreate:
public void onCreate() {
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
是不是通過HandlerThread先創建一個Looper,然後將這個Looper賦給工作線程ServiceHandler
啟動好IntentService之後,我們開始
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
ServiceHandler的函數中有處理消息的機制,這裡就調用onHandleIntent進行處理
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
五、如何銷毀線程
1、銷毀Handler:
由上面我們知道:我們開啟一個子線程重要的依據在於要創建一個HandlerThread,在這裡會新建一個Looper,然後通過它進行處理Message。那麼在退出時如下處理:
onDestroy() {
super.onDestroy();
//將HandlerThread的looper.quit,下面應該是實例調用quit(此處不考慮語法問題)
HandlerThread.quit();
}
對於以Handler.post(Runnable)形式發送Message的方式,在上面函數中應該是:
Handler.removeCallbacks(mRunnable);
2、銷毀Thread
目前是通過:設置一個全局變量,在退出時將這個變量設置為true,thread中判斷到這個值為true時退出thread的循環。
首先配置一個布局: 然後在activity中把發短信的代碼寫出來: package com.ydl.smssender;i
思路分析:1、自定義View實現字母導航欄2、ListView實現聯系人列表3、字母導航欄滑動事件處理4、字母導航欄與中間字母的聯動5、字母導航欄與ListView的聯動
在Android開發中,經常需要通過點擊某個按鈕彈出對話框或者選擇框,通過Dialog或者PopupMenu、PopupWindow都能實現。 這裡主要介紹後兩者:Pop
Content Providers是Android中四大組件之一,用於管理應用程序訪問結構化的數據。Content Providers可以壓縮數據(They encaps