一個應用只有一個線程
在默認情況下,更確切的講一個進程中只有一個線程,這跟其他語言,比如C/C++,Java等是一致。也就是說在Android應用程序裡面一個進程只有一個線程,所有組件都運行在一個線程裡面!
當應用程序啟動時,系統會為其創建一個進程,也會創建一個線程名字叫做main,所有其所屬組件的創建,系統事件的處理,系統的回調等一切應用相關的事情都運行在此名叫main的線程中。此線程即為常說的主線程(main thread)。俗稱的UI線程(UI thread)也是它,因為只有主線程可以操作UI相關的事情,所以有人把主線程也稱作UI線程,但這並不是正確的說法,因為Service所屬的線程也可以操作Toast,但是Service並沒有UI。為什麼非主線程不能操作UI呢?因為對UI操作常常會引發系統的回調,所以如果允許第三線程來操作可能會引發系統回調的紊亂,進而會打亂整個框架的時序!
這裡要特別注意的就是同一個進程中的所有組件運行在同一個線程中,Activiy,Service,BoradcastReceiver和ContentProvider都運行在主線程中。
最容易引起誤解的就是Service,文檔和常識都會認為Service是放在後台用於操作費時運算的,但是實則不然,如果你在Service中做費時操作,同樣會引發臭名昭著的ANR(Application Not Responding)。所以如果想把Service當做一個Server,必須在Service用HandlerThread或Thread創建一個Worker線程!
Activity也是一樣的,你startActivity()後,開啟了一個新的Activity,但它們都運行在同一個線程中,所以你還是不能在原Activity中做費時操作!也即在調用startActivity()開啟了一個新的Activity後,或者在onPause(), onStop(), onDestroy()中做費時操作會引發ANR。
對於ContentProvider也是一樣的,如果跟其他組件在同一進程內,那麼調用ContentResolver的方法會相當於直接調用ContentProvider的方法。如果是在另外一個進程中,雖是通過IPC,但也是同步的,因為IBinder的同步的,也即調用ContentResolver時會把調用者的進程掛起,等待ContentProvider的進程操作結束,再把結果傳給調用者進程!所以,如果ContentProvider中有費時操作,或者會同步鎖數據庫等,也一定要注意ANR的發生!
所以一定要記住:一個進程只有一個線程,所有組件都運行在主線程中。
因此,如果有費時操作,必須要創建Worker線程!
實例
下面有一個小實例,一個應用中有五個組件:2個Activity,一個Service,一個ContentProvider和一個BroadcastReceiver。在每個組件的方法中都有打印所屬線程信息,另外對於Activity,Service和ContentProvider如果做費時操作會引發ANR,對於BroadcastReceiver更是如此,這個大家都懂得的!
復制代碼 代碼如下:
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());
}
}