深入Android線程的相關(guān)問題解惑
更新時(shí)間:2013年05月21日 11:00:21 作者:
本篇文章是對(duì)Android線程的相關(guān)問題進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
一個(gè)應(yīng)用只有一個(gè)線程
在默認(rèn)情況下,更確切的講一個(gè)進(jìn)程中只有一個(gè)線程,這跟其他語言,比如C/C++,Java等是一致。也就是說在Android應(yīng)用程序里面一個(gè)進(jìn)程只有一個(gè)線程,所有組件都運(yùn)行在一個(gè)線程里面!
當(dāng)應(yīng)用程序啟動(dòng)時(shí),系統(tǒng)會(huì)為其創(chuàng)建一個(gè)進(jìn)程,也會(huì)創(chuàng)建一個(gè)線程名字叫做main,所有其所屬組件的創(chuàng)建,系統(tǒng)事件的處理,系統(tǒng)的回調(diào)等一切應(yīng)用相關(guān)的事情都運(yùn)行在此名叫main的線程中。此線程即為常說的主線程(main thread)。俗稱的UI線程(UI thread)也是它,因?yàn)橹挥兄骶€程可以操作UI相關(guān)的事情,所以有人把主線程也稱作UI線程,但這并不是正確的說法,因?yàn)镾ervice所屬的線程也可以操作Toast,但是Service并沒有UI。為什么非主線程不能操作UI呢?因?yàn)閷?duì)UI操作常常會(huì)引發(fā)系統(tǒng)的回調(diào),所以如果允許第三線程來操作可能會(huì)引發(fā)系統(tǒng)回調(diào)的紊亂,進(jìn)而會(huì)打亂整個(gè)框架的時(shí)序!
這里要特別注意的就是同一個(gè)進(jìn)程中的所有組件運(yùn)行在同一個(gè)線程中,Activiy,Service,BoradcastReceiver和ContentProvider都運(yùn)行在主線程中。
最容易引起誤解的就是Service,文檔和常識(shí)都會(huì)認(rèn)為Service是放在后臺(tái)用于操作費(fèi)時(shí)運(yùn)算的,但是實(shí)則不然,如果你在Service中做費(fèi)時(shí)操作,同樣會(huì)引發(fā)臭名昭著的ANR(Application Not Responding)。所以如果想把Service當(dāng)做一個(gè)Server,必須在Service用HandlerThread或Thread創(chuàng)建一個(gè)Worker線程!
Activity也是一樣的,你startActivity()后,開啟了一個(gè)新的Activity,但它們都運(yùn)行在同一個(gè)線程中,所以你還是不能在原Activity中做費(fèi)時(shí)操作!也即在調(diào)用startActivity()開啟了一個(gè)新的Activity后,或者在onPause(), onStop(), onDestroy()中做費(fèi)時(shí)操作會(huì)引發(fā)ANR。
對(duì)于ContentProvider也是一樣的,如果跟其他組件在同一進(jìn)程內(nèi),那么調(diào)用ContentResolver的方法會(huì)相當(dāng)于直接調(diào)用ContentProvider的方法。如果是在另外一個(gè)進(jìn)程中,雖是通過IPC,但也是同步的,因?yàn)镮Binder的同步的,也即調(diào)用ContentResolver時(shí)會(huì)把調(diào)用者的進(jìn)程掛起,等待ContentProvider的進(jìn)程操作結(jié)束,再把結(jié)果傳給調(diào)用者進(jìn)程!所以,如果ContentProvider中有費(fèi)時(shí)操作,或者會(huì)同步鎖數(shù)據(jù)庫等,也一定要注意ANR的發(fā)生!
所以一定要記住:一個(gè)進(jìn)程只有一個(gè)線程,所有組件都運(yùn)行在主線程中。
因此,如果有費(fèi)時(shí)操作,必須要?jiǎng)?chuàng)建Worker線程!
下面有一個(gè)小實(shí)例,一個(gè)應(yīng)用中有五個(gè)組件:2個(gè)Activity,一個(gè)Service,一個(gè)ContentProvider和一個(gè)BroadcastReceiver。在每個(gè)組件的方法中都有打印所屬線程信息,另外對(duì)于Activity,Service和ContentProvider如果做費(fèi)時(shí)操作會(huì)引發(fā)ANR,對(duì)于BroadcastReceiver更是如此,這個(gè)大家都懂得的!
public class ActivityDemo extends Activity {
private static final String TAG = "ActivityDemo";
private Handler mMainHandler = new Handler(new Handler.Callback() {
public boolean handleMessage(Message msg) {
dumpThreadInfo();
return false;
}
});
@Override
protected void onCreate(Bundle savedInstanceState) {
dumpThreadInfo();
super.onCreate(savedInstanceState);
// add four buttons
LinearLayout layout = new LinearLayout(getApplication());
layout.setOrientation(LinearLayout.VERTICAL);
Button startService = new Button(getApplication());
startService.setText("Start a Service");
startService.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent i = new Intent(getApplication(), ServiceDemo.class);
startService(i);
}
});
layout.addView(startService);
Button startAnother = new Button(getApplication());
startAnother.setText("Start another Activity");
startAnother.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent i = new Intent(getApplication(), AnotherActivity.class);
startService(i);
}
});
layout.addView(startAnother);
Button startContentProvider = new Button(getApplication());
startContentProvider.setText("Start a ContentProvider");
startContentProvider.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
getContentResolver().query(ContentProviderDemo.CONTENT_URI, null, null, null, null);
}
});
layout.addView(startContentProvider);
Button startReceiver = new Button(getApplication());
startReceiver.setText("Start a BroadcastReceiver");
startReceiver.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent i = new Intent("android.action.start_broadcastreceiver_demo");
sendBroadcast(i);
}
});
layout.addView(startReceiver);
setContentView(layout);
mMainHandler.sendEmptyMessageDelayed(0, 500);
}
public void dumpThreadInfo() {
Thread.dumpStack();
Log.e(TAG, Thread.currentThread().toString());
Log.e(TAG, " " + getMainLooper());
}
}
public class AnotherActivity extends Activity {
private static final String TAG = "AnotherActivity";
private Handler mMainHandler = new Handler(getMainLooper(), new Handler.Callback() {
public boolean handleMessage(Message msg) {
// this will cause ANR
Log.e(TAG, "you know what this is very slow slow slow slow");
SystemClock.sleep(20 * 1000);
dumpThreadInfo();
return false;
}
});
@Override
protected void onCreate(Bundle savedInstanceState) {
dumpThreadInfo();
super.onCreate(savedInstanceState);
setTitle("this is another activity");
mMainHandler.sendEmptyMessageDelayed(0, 500);
}
@Override
protected void onDestroy() {
dumpThreadInfo();
super.onDestroy();
}
public void dumpThreadInfo() {
Thread.dumpStack();
Log.e(TAG, Thread.currentThread().toString());
Log.e(TAG, " " + getMainLooper());
}
}
public class ServiceDemo extends Service {
private Handler mMainHandler = new Handler(new Handler.Callback() {
public boolean handleMessage(Message msg) {
// this will cause ANR, too
Log.e(TAG, "this is very slow you know, slow slow");
SystemClock.sleep(20 * 1000);
dumpThreadInfo();
return false;
}
});
private static final String TAG = "ServiceDemo";
@Override
public IBinder onBind(Intent arg0) {
dumpThreadInfo();
return null;
}
@Override
public void onCreate() {
dumpThreadInfo();
super.onCreate();
mMainHandler.sendEmptyMessageDelayed(0, 500);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
dumpThreadInfo();
return super.onStartCommand(intent, flags, startId);
}
public void dumpThreadInfo() {
Thread.dumpStack();
Log.e(TAG, Thread.currentThread().toString());
Log.e(TAG, " " + getMainLooper());
}
}
public class ContentProviderDemo extends ContentProvider {
public static final Uri CONTENT_URI = Uri.parse("content://com.hilton.effectiveandroid.app/content");
private static final String TAG = "ContentProviderDemo";
@Override
public int delete(Uri arg0, String arg1, String[] arg2) {
dumpThreadInfo();
return 0;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
dumpThreadInfo();
return null;
}
@Override
public boolean onCreate() {
dumpThreadInfo();
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
dumpThreadInfo();
// it will cause ANR of course
Log.e(TAG, "this is very slow, you know that");
SystemClock.sleep(20 * 1000);
return null;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
dumpThreadInfo();
return 0;
}
public void dumpThreadInfo() {
Thread.dumpStack();
Log.e(TAG, Thread.currentThread().toString());
}
@Override
public String getType(Uri arg0) {
return null;
}
}
public class BroadcastReceiverDemo extends BroadcastReceiver {
private static final String TAG = "BroadcastReceiverDemo";
@Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, "intent is " + intent);
dumpThreadInfo();
}
public void dumpThreadInfo() {
Thread.dumpStack();
Log.e(TAG, Thread.currentThread().toString());
}
}
在默認(rèn)情況下,更確切的講一個(gè)進(jìn)程中只有一個(gè)線程,這跟其他語言,比如C/C++,Java等是一致。也就是說在Android應(yīng)用程序里面一個(gè)進(jìn)程只有一個(gè)線程,所有組件都運(yùn)行在一個(gè)線程里面!
當(dāng)應(yīng)用程序啟動(dòng)時(shí),系統(tǒng)會(huì)為其創(chuàng)建一個(gè)進(jìn)程,也會(huì)創(chuàng)建一個(gè)線程名字叫做main,所有其所屬組件的創(chuàng)建,系統(tǒng)事件的處理,系統(tǒng)的回調(diào)等一切應(yīng)用相關(guān)的事情都運(yùn)行在此名叫main的線程中。此線程即為常說的主線程(main thread)。俗稱的UI線程(UI thread)也是它,因?yàn)橹挥兄骶€程可以操作UI相關(guān)的事情,所以有人把主線程也稱作UI線程,但這并不是正確的說法,因?yàn)镾ervice所屬的線程也可以操作Toast,但是Service并沒有UI。為什么非主線程不能操作UI呢?因?yàn)閷?duì)UI操作常常會(huì)引發(fā)系統(tǒng)的回調(diào),所以如果允許第三線程來操作可能會(huì)引發(fā)系統(tǒng)回調(diào)的紊亂,進(jìn)而會(huì)打亂整個(gè)框架的時(shí)序!
這里要特別注意的就是同一個(gè)進(jìn)程中的所有組件運(yùn)行在同一個(gè)線程中,Activiy,Service,BoradcastReceiver和ContentProvider都運(yùn)行在主線程中。
最容易引起誤解的就是Service,文檔和常識(shí)都會(huì)認(rèn)為Service是放在后臺(tái)用于操作費(fèi)時(shí)運(yùn)算的,但是實(shí)則不然,如果你在Service中做費(fèi)時(shí)操作,同樣會(huì)引發(fā)臭名昭著的ANR(Application Not Responding)。所以如果想把Service當(dāng)做一個(gè)Server,必須在Service用HandlerThread或Thread創(chuàng)建一個(gè)Worker線程!
Activity也是一樣的,你startActivity()后,開啟了一個(gè)新的Activity,但它們都運(yùn)行在同一個(gè)線程中,所以你還是不能在原Activity中做費(fèi)時(shí)操作!也即在調(diào)用startActivity()開啟了一個(gè)新的Activity后,或者在onPause(), onStop(), onDestroy()中做費(fèi)時(shí)操作會(huì)引發(fā)ANR。
對(duì)于ContentProvider也是一樣的,如果跟其他組件在同一進(jìn)程內(nèi),那么調(diào)用ContentResolver的方法會(huì)相當(dāng)于直接調(diào)用ContentProvider的方法。如果是在另外一個(gè)進(jìn)程中,雖是通過IPC,但也是同步的,因?yàn)镮Binder的同步的,也即調(diào)用ContentResolver時(shí)會(huì)把調(diào)用者的進(jìn)程掛起,等待ContentProvider的進(jìn)程操作結(jié)束,再把結(jié)果傳給調(diào)用者進(jìn)程!所以,如果ContentProvider中有費(fèi)時(shí)操作,或者會(huì)同步鎖數(shù)據(jù)庫等,也一定要注意ANR的發(fā)生!
所以一定要記住:一個(gè)進(jìn)程只有一個(gè)線程,所有組件都運(yùn)行在主線程中。
因此,如果有費(fèi)時(shí)操作,必須要?jiǎng)?chuàng)建Worker線程!

下面有一個(gè)小實(shí)例,一個(gè)應(yīng)用中有五個(gè)組件:2個(gè)Activity,一個(gè)Service,一個(gè)ContentProvider和一個(gè)BroadcastReceiver。在每個(gè)組件的方法中都有打印所屬線程信息,另外對(duì)于Activity,Service和ContentProvider如果做費(fèi)時(shí)操作會(huì)引發(fā)ANR,對(duì)于BroadcastReceiver更是如此,這個(gè)大家都懂得的!
復(fù)制代碼 代碼如下:
public class ActivityDemo extends Activity {
private static final String TAG = "ActivityDemo";
private Handler mMainHandler = new Handler(new Handler.Callback() {
public boolean handleMessage(Message msg) {
dumpThreadInfo();
return false;
}
});
@Override
protected void onCreate(Bundle savedInstanceState) {
dumpThreadInfo();
super.onCreate(savedInstanceState);
// add four buttons
LinearLayout layout = new LinearLayout(getApplication());
layout.setOrientation(LinearLayout.VERTICAL);
Button startService = new Button(getApplication());
startService.setText("Start a Service");
startService.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent i = new Intent(getApplication(), ServiceDemo.class);
startService(i);
}
});
layout.addView(startService);
Button startAnother = new Button(getApplication());
startAnother.setText("Start another Activity");
startAnother.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent i = new Intent(getApplication(), AnotherActivity.class);
startService(i);
}
});
layout.addView(startAnother);
Button startContentProvider = new Button(getApplication());
startContentProvider.setText("Start a ContentProvider");
startContentProvider.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
getContentResolver().query(ContentProviderDemo.CONTENT_URI, null, null, null, null);
}
});
layout.addView(startContentProvider);
Button startReceiver = new Button(getApplication());
startReceiver.setText("Start a BroadcastReceiver");
startReceiver.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent i = new Intent("android.action.start_broadcastreceiver_demo");
sendBroadcast(i);
}
});
layout.addView(startReceiver);
setContentView(layout);
mMainHandler.sendEmptyMessageDelayed(0, 500);
}
public void dumpThreadInfo() {
Thread.dumpStack();
Log.e(TAG, Thread.currentThread().toString());
Log.e(TAG, " " + getMainLooper());
}
}
復(fù)制代碼 代碼如下:
public class AnotherActivity extends Activity {
private static final String TAG = "AnotherActivity";
private Handler mMainHandler = new Handler(getMainLooper(), new Handler.Callback() {
public boolean handleMessage(Message msg) {
// this will cause ANR
Log.e(TAG, "you know what this is very slow slow slow slow");
SystemClock.sleep(20 * 1000);
dumpThreadInfo();
return false;
}
});
@Override
protected void onCreate(Bundle savedInstanceState) {
dumpThreadInfo();
super.onCreate(savedInstanceState);
setTitle("this is another activity");
mMainHandler.sendEmptyMessageDelayed(0, 500);
}
@Override
protected void onDestroy() {
dumpThreadInfo();
super.onDestroy();
}
public void dumpThreadInfo() {
Thread.dumpStack();
Log.e(TAG, Thread.currentThread().toString());
Log.e(TAG, " " + getMainLooper());
}
}
復(fù)制代碼 代碼如下:
public class ServiceDemo extends Service {
private Handler mMainHandler = new Handler(new Handler.Callback() {
public boolean handleMessage(Message msg) {
// this will cause ANR, too
Log.e(TAG, "this is very slow you know, slow slow");
SystemClock.sleep(20 * 1000);
dumpThreadInfo();
return false;
}
});
private static final String TAG = "ServiceDemo";
@Override
public IBinder onBind(Intent arg0) {
dumpThreadInfo();
return null;
}
@Override
public void onCreate() {
dumpThreadInfo();
super.onCreate();
mMainHandler.sendEmptyMessageDelayed(0, 500);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
dumpThreadInfo();
return super.onStartCommand(intent, flags, startId);
}
public void dumpThreadInfo() {
Thread.dumpStack();
Log.e(TAG, Thread.currentThread().toString());
Log.e(TAG, " " + getMainLooper());
}
}
復(fù)制代碼 代碼如下:
public class ContentProviderDemo extends ContentProvider {
public static final Uri CONTENT_URI = Uri.parse("content://com.hilton.effectiveandroid.app/content");
private static final String TAG = "ContentProviderDemo";
@Override
public int delete(Uri arg0, String arg1, String[] arg2) {
dumpThreadInfo();
return 0;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
dumpThreadInfo();
return null;
}
@Override
public boolean onCreate() {
dumpThreadInfo();
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
dumpThreadInfo();
// it will cause ANR of course
Log.e(TAG, "this is very slow, you know that");
SystemClock.sleep(20 * 1000);
return null;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
dumpThreadInfo();
return 0;
}
public void dumpThreadInfo() {
Thread.dumpStack();
Log.e(TAG, Thread.currentThread().toString());
}
@Override
public String getType(Uri arg0) {
return null;
}
}
復(fù)制代碼 代碼如下:
public class BroadcastReceiverDemo extends BroadcastReceiver {
private static final String TAG = "BroadcastReceiverDemo";
@Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, "intent is " + intent);
dumpThreadInfo();
}
public void dumpThreadInfo() {
Thread.dumpStack();
Log.e(TAG, Thread.currentThread().toString());
}
}
您可能感興趣的文章:
- android開發(fā)教程之子線程中更新界面
- android開發(fā)教程之handle實(shí)現(xiàn)多線程和異步處理
- android使用handler ui線程和子線程通訊更新ui示例
- android使用handlerthread創(chuàng)建線程示例
- android使用多線程更新ui示例分享
- Handler與Android多線程詳解
- 淺析android中的線程封裝
- android中多線程下載實(shí)例
- Android多線程及異步處理問題詳細(xì)探討
- Android多線程處理機(jī)制中的Handler使用介紹
- Android中加載網(wǎng)絡(luò)資源時(shí)的優(yōu)化可使用(線程+緩存)解決
- Android開發(fā)筆記之:如何安全中止一個(gè)自定義線程Thread的方法
- Android 在其他線程中更新UI線程的解決方法
- 深入Android Handler與線程間通信ITC的詳解
- Android開發(fā)筆記之:深入理解多線程AsyncTask
- Android Handler主線程和一般線程通信的應(yīng)用分析
- android 多線程技術(shù)應(yīng)用
- android開發(fā)教程之使用線程實(shí)現(xiàn)視圖平滑滾動(dòng)示例
相關(guān)文章
Android中ShapeableImageView使用實(shí)例詳解(告別shape、三方庫)
之前Google推送了文章,Android?Material組件1.2.0里面就有ShapeableImageView,不用像以前再寫shape,下面這篇文章主要給大家介紹了關(guān)于Android中ShapeableImageView使用的相關(guān)資料,需要的朋友可以參考下2022-09-09
Android實(shí)現(xiàn)清除單個(gè)域名的cookie
這篇文章主要介紹了Android實(shí)現(xiàn)清除單個(gè)域名的cookie,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-03-03
Android 將本地資源圖片轉(zhuǎn)換成Drawable,進(jìn)行設(shè)置大小操作
這篇文章主要介紹了Android 將本地資源圖片轉(zhuǎn)換成Drawable,進(jìn)行設(shè)置大小操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08
android監(jiān)控sim卡有沒有服務(wù)示例(sim卡管理)
android監(jiān)聽SIM卡有沒有服務(wù),可以使用android.telephony.PhoneStateListener類來實(shí)現(xiàn),下面是一個(gè)簡單的小例子,大家參考使用吧2014-01-01
Android UI設(shè)計(jì)系列之自定義EditText實(shí)現(xiàn)帶清除功能的輸入框(3)
這篇文章主要介紹了Android UI設(shè)計(jì)系列之自定義EditText實(shí)現(xiàn)帶清除功能的輸入框,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-06-06
Android Studio打包APK文件具體實(shí)現(xiàn)步驟解析
這篇文章主要介紹了Android Studio打包APK文件具體實(shí)現(xiàn)步驟解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
Android如何實(shí)現(xiàn)動(dòng)態(tài)滾動(dòng)波形圖(心電圖)功能
這篇文章主要介紹了Android如何實(shí)現(xiàn)動(dòng)態(tài)滾動(dòng)波形圖(心電圖)功能,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下2021-03-03

