android 進程的優先順序
進程的優先順序
12.1.1.概述
Android規定:進程的優先順序分為以下五個層級,-1所示:
圖-1
1、 前台進程 -Activte process
Active (前台) process是包含(與使用者互動的)控制項的那種應用程式。這些是Android通過回收資源來極力保護的進程。Active process包括:
(1)處於“active”狀態的Activity,它們運行在前台來響應使用者的事件。
(2)Activity Service或者正在執行onReceive事件處理函數的Broadcast Receiver。
(3)正在執行onStart,onCreate,OnDestroy事件處理函數的Service。
2、 可見進程-Visible Process
可見但不活動的進程是那些擁有“可見”Activity的進程。“可見”Activity是那些在螢幕上可見,但不是在前台或不響應使用者事件的Activity。這種情況發生在當一個Activity被部分遮蓋的時候(被一個非全屏或者透明的Activity)。可見進程只在極端的情況下,才會被殺死來保證Active Process的運行。包括以下情況:
(1)可見的Activity,但處於暫停(onPause()) 狀態;
(2)被可見Activity綁定的Service
3、 服務進程 Service process
進程中包含已經啟動的Service。Service以動態方式持續運行但沒有可見的介面。因為Service不直接和使用者互動,它們擁有比visible Process較低的優先順序。它們還是可以被認為是前台進程,不會被殺死,直到資源被active/visible Process需求。
4、 背景進程 Background process
進程中的Activity不可見和進程中沒有任何啟動的Service,這些進程都可以看作是後台進程。在系統中,擁有大量的後台進程,並且Android按照後看見先殺掉的原則來殺掉後台進程以擷取資源給前台進程。
5、 空進程-Empty process
為了改善整個系統的效能,Android經常在記憶體中保留那些已經走完生命週期的應用程式。Android維護這些緩衝來改善應用程式重新啟動的時間。這些進程在資源需要的時候常常被殺掉。
當一個進程被殺掉,進程保留,變成空進程。
12.1.2.設定/取消Service為前台進程的方法
由上所述,Service排在進程的第三優先順序,通常耗時的操作是放線上程中,那麼將這樣的線程放在Service中將會有較高的優先順序,降低被Android系統殺掉的幾率。
若是將線程放在Activity中,當Activity被完全遮蓋,處於onStop狀態時,其進程的優先順序別降為第四級。明顯不如放在處於第三層級的Service中更保險。
應用情境,如音樂播放器,通過在前台做其它操作時,音樂播放器在背景播放音樂,這種情況將播放音樂的線程放在Service中是適宜的。
Service類中有兩個方法,分別用來設定Service為前台進程和取消前台進程。被設定為前台進程的Service擁有最高的優先順序別,被Android系統殺掉的幾率降至最低。
1、startForeground(int id,Notification noti);
作用:設定Service對象為前台進程。
說明:
第一個參數是通知的id值。
第二個參數是通知對象。
startForegroud方法的參數與通知管理器相同,使用上也類似,都是發送一個通知,並指定該通知對象的id值。
2、stopForeGround(int id);
作用:取消(指定id值所通知的Service對象)前台進程。
12.1.3.設定Service為前台進程的步驟
步驟1、在Service類的onStartCommand方法中(通常在該方法中)建立Intent對象,並指定與其綁定的Activity,範例程式碼如下:
Intent foreIntent=new Intent(this, MainActivity.class);
步驟2、建立PendingIntetn對象
PendingIntent pintent=PendingIntent.getActivity(
this, 0, foreIntent, PendingIntent.FLAG_UPDATE_CURRENT);
說明:第四個參數指明在通知欄隨時重新整理通知。
步驟3、建立通知對象,範例程式碼如下:
Notification noti=new Notification(
R.drawable.icon,"notification",System.currentTimeMillis());
說明:
第一個參數是通知欄中顯示的本通知的表徵圖。
第二個參數是通知欄中顯示的本通知的標題。
第三個參數是本通知發出的時間。
步驟4、將此通知放到通知欄的(Ongoing)正在運行組中,範例程式碼如下:
noti.flags=Notification.FLAG_ONGOING_EVENT;
步驟5、設定通知的點擊事件,範例程式碼如下:
noti.setLatestEventInfo(this, "title","content", pintent);
步驟6、向指定的Activity發送通知,並設定當前的Service對象為前台進程,範例程式碼如下:
startForeground(97789, noti);
12.1.4.樣本
運行圖-1所示的視窗:
圖-2
1、單擊圖-1中的start foreground按鈕,將啟動一個Service對象,並設定改Service為前台進程,在該在日誌視窗中出現圖-2中紅框內的第一行資訊。
2、單擊圖-2中的stop foreground按鈕,將取消Service的當前進程,並在日誌視窗中顯示圖-2中紅框內的第二行資訊。
以下列出關鍵代碼:
步驟1、建立項目exer12_01,包名為com.tarena.exer12_01,項目入口:MainActivity類,該中關鍵代碼如下所示:
@Override
public void onClick(View v) {
//建立Intent對象,並設定目標組件為MyService
Intent intent=new Intent();
intent.setClass(this, MyService.class);
switch(v.getId()){
case R.id.btnStartFore:
//設定intent.action的值為Constant.ACTION_FORE
intent.setAction(Constant.ACTION_FORE);
startService(intent);//啟動服務
break;
case R.id.btnStopFore:
//設定intent.action的值為Constant.ACTION_STOP_FORE
intent.setAction(Constant.ACTION_STOP_FORE);
startService(intent);
break;
case R.id.btnStopService:
stopService(intent);//停止服務
break;
}
}
步驟2、在src/com.tarena.exer12_01包下建立MyService.java該類繼承自Service類。關鍵代碼如下所示:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String action=intent.getAction();
if(Constant.ACTION_FORE.equals(action)){
Log.i(tag,"startForeground");
Intent foreIntent=new Intent();
foreIntent.setClass(this, MainActivity.class);
PendingIntent pintent=PendingIntent.getActivity(
this, 0, foreIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification noti=new Notification(
R.drawable.icon,"notification",System.currentTimeMillis());
//將此通知放到通知欄的"Ongoing"即"正在運行"組中
noti.flags=Notification.FLAG_ONGOING_EVENT;
noti.setLatestEventInfo(
this, "改變Service優先順序", "設定service為foreground層級", pintent);
startForeground(97789, noti);
}else if(Constant.ACTION_STOP_FORE.equals(action)){
Log.i(tag,"stopForeground");
stopForeground(true);//取消當前服務為前台服務
}
return super.onStartCommand(intent, flags, startId);
}
步驟3、開啟項目資訊清單檔,註冊該服務,如下代碼中紅框中代碼所示:
<application android:icon="@drawable/icon"
android:label="@string/app_name">
<service android:name="MyService"></service>
</application>
12.2.UI與線程
12.2.1.概述
UI是英文User Interface單詞的簡稱。
當應用程式啟動時,系統會為應用程式建立一個主線程(main)或者叫UI線程,它負責分發事件到不同的控制項(例如繪畫事件)以完成應用程式與Android UI孔廟件的互動。
例如,當觸控螢幕幕上的一個按鈕時,UI線程會把觸摸事件分發到控制項上,更改狀態並加入事件隊列,UI線程會分發請求和通知到各個控制項,完成相應的動作。
單執行緒模式的效能是非常差的,除非應用程式相當簡單,特別是當所有的操作都在主線程中執行,比如訪問網路或資料庫之類的耗時操作將會導致使用者介面鎖定,所有的事件將不能分發,應用程式就像死了一樣,更嚴重的是當超過5秒時,系統就會彈出“應用程式無響應”的對話方塊。
12.2.2.main線程
主線程也叫UI線程,主線程負責UI的建立,UI的重新整理以及處理使用者的輸入事件。
提示:Android規定,Activity中的控制項的重新整理由主線程負責,其它線程不能直接重新整理。
12.2.3.ANR術語
ANR的全稱:Activity or Application is not responding,當使用者操作超過系統規定的回應時間時,會彈出ANR對話方塊,-3所示:
圖-3
若選擇Force close按鈕將強制關閉當前的Activity;
若選擇Wait按鈕將保留當前的Activity繼續等待。
出現ANR的條件:
1. 在main線程(或稱主線程)中有一個耗時操作正在執行,此時使用者輸入事件並且這個事件在5秒內沒有得到響應,就會彈出ANR。
2. 廣播接收者的onReceive()方法在10秒內沒有執行完成,也會彈出ANR。
提示:在廣播接收者的onReceive方法中要避免執行耗時的操作。
12.2.4.樣本-測試ANR發生的兩種情況
建立項目exer12_02,在該類中建立MyReceiver類,該類是BroadcastRecevier的子類。
圖-4
1、單擊download按鈕,在主線程中執行一個迴圈類比從網路下載資料的操作,該迴圈耗時10秒,在該迴圈執行過程中,在圖-4的標註所指的編輯框中連續試圖輸入字串,5秒後,將彈出圖-3所示的ANR對話方塊。
2、單擊send broadcast按鈕,發送廣播,然後在圖-4的標註所指的編輯框內連續試圖輸入字串,10秒後將彈出ANR對話方塊。
以下是關鍵代碼:
步驟1、建立工具類-CommonUtils.java,該類中定義了一個類比耗時操作的迴圈,代碼如下所示:
public final class CommonUtils {
public static final String ACTION_RECEIVER="com.tarena.ACTION_RECEIVER";
public static void timeConsuming(int n){
for(int i=0;i<n;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
步驟2、建立MyReceiver.java類,該類繼承自BroadcastReceiver類,代碼如下所示:
public class MyReceiver extends BroadcastReceiver {
private static final String tag="MyReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Log.i(tag,"onReceiver");
CommonUtils.timeConsuming(15);
}
}
步驟3、以下是MainActivity.java類的代碼,該代碼負責發送廣播,類比下載的耗時操作,代碼如下所示:
public class MainActivity extends Activity implements OnClickListener{
TextView mTextView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTextView=(TextView)findViewById(R.id.tv);
//執行個體化按鈕對象
Button btnDownload=(Button)findViewById(R.id.btnDownload);
Button btnSendBraodcast=(Button)findViewById(R.id.btnSendBroadcast);
//註冊按鈕對象的單擊事件
btnDownload.setOnClickListener(this);
btnSendBraodcast.setOnClickListener(this);
}
//實現按鈕的單擊事件
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.btnDownload://下載按鈕
CommonUtils.timeConsuming(10);//類比(耗時10秒的)下載
mTextView.setText("finished");
break;
case R.id.btnSendBroadcast://發送廣播按鈕
//發送廣播
Intent intent=new Intent(CommonUtils.ACTION_RECEIVER);
sendBroadcast(intent);
mTextView.setText("finished");
break;
}
}
}
12.3.Message對象
12.3.1.概述
Message類用於存放訊息,該類通常與Handler類配合使用。
12.3.2.常用屬性
1、int arg1:存放一個int類型的資料。
2、int arg2:存放一個int類型的資料。
3、int what:存放一個int類型的資料。
4、Object obj:存放任意類型的對象。
12.3.3.範例程式碼
Message msg=new Message();
msg.what=1;
msg.arg1=100;
msg.obj=”hello”;
msg.obj=new Runnable();
12.4.用Handler更新UI
12.4.1.概述
由以上所述,在主線程中不宜執行耗時操作,因此,通常的耗時操作都放在其它線程中,Androidghi稱這樣的線程為work thread(背景工作執行緒)。但Android還規定:只有主線程才能修改Activity中的控制項,其它線程不能修改。
解決以上問題有多種方法,本節介紹如何通過Handler類提供的方法解決背景工作執行緒不能直接修改UI的問題。
Handler修改主線程UI的思路:Handler對象通過在背景工作執行緒中發送訊息,該訊息發送至訊息對列中,等待處理。
在主線程中從訊息對列中接收訊息,根據訊息中的資訊決定如何更新主線程中UI.
12.4.2.常用方法
1、sendEmptyMessage(int what);
作用:從work thead(背景工作執行緒)向主線程發送一個空訊息。
說明:若多個線程向主線程發送訊息,則參數what用於區別不同的線程。
2、sendEmptyMessageAtTime(int what,long uptime);
作用:從work thead(背景工作執行緒)按指定時間發送空訊息。
說明:第二個參數uptime:指定的時間。
3、sendEmptyMessageDelayed(int what,long delay);
作用:從work thead(背景工作執行緒)延遲發送空訊息。
說明:第二個參數用於指定延遲的時間,單位:毫秒。
5、sendMessage(Message msg);
作用:從work thead(背景工作執行緒)向主線程發送訊息;
說明:msg是存放訊息資料的對象。
6、sendMessageAtTime(Message msg,long uptime);
作用:從work thead(背景工作執行緒)按指定時間向主線程發送訊息
7、sendMessageDelayed(Message msg,long delay);
作用:從work thead(背景工作執行緒)延遲指定時間向主線程發送訊息。
8、handleMessage(Message msg);
作用:接收並處理從work thread發送的訊息。
說明:參數-msg:send***Message發送過來的訊息對象。
圖-5是Android處理訊息機制的:
圖-5
圖-5顯示了Android系統提供了一個稱為Looper(迴圈對列)用來管理訊息對列,各線程通過Handler類的Send***Message命令將訊息發送至訊息對列,Looper再將訊息對列中的訊息依次交給主線程處理。
12.4.3.樣本
從兩個背景工作執行緒向主線程發送不同的訊息,主線程接收訊息並顯示不同的處理資訊。
步驟1、以下是Activity類中的onClick()方法中的代碼,該方法用於處理按鈕單擊事件。
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.btnDownload://若單擊了標題為下載的按鈕
//建立一個work thread(背景工作執行緒)線程對象
new Thread(){
public void run() {
//以下一行代碼類比下載進度,執行時間約為10秒
CommonUtils.timeConsuming(10);
//建立訊息對象
Message msg=new Message();
//CommonUtils.FLAG_DOWNLOAD值代表下載操作
msg.what=CommonUtils.FLAG_DOWNLOAD;
msg.obj="download finished";
mHandler.sendMessage(msg);//發送訊息
};
}.start();//啟動線程
break;
case R.id.btnUpdate://若單擊了標題為更新的按鈕
//建立一個work thread(背景工作執行緒對象)
new Thread(){
public void run() {
//以下一行代碼類比更新進度,執行時間約為10秒
CommonUtils.timeConsuming(8);
//建立訊息對象
Message msg=new Message();
//CommonUtils.FLAG_UPDATE代表更新操作
msg.what=CommonUtils.FLAG_UPDATE;
msg.obj="update finished";
mHandler.sendMessage(msg);//發送訊息
};
}.start();//啟動線程
break;
}
}
步驟2、以下是在Activity.onCreate()方法中(主線程)中建立的Handler對象-mHandler:
Button btnDownload.setOnClickListener(this);
Button btnUpdate.setOnClickListener(this);
mHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case CommonUtils.FLAG_DOWNLOAD:
mTextView.setText(“下載結束”);
break;
case CommonUtils.FLAG_UPDATE:
mTextView.setText(“更新結束”);
break;
}
}
說明:
1、CommonUtils是一個自訂的工具類,該類中包括以下兩個int類型的常量:
public static final int FLAG_DOWNLOAD=1;
public static final int FLAG_UPDATE=2;
2、msg是work thread線程發送過來的訊息對象,該線程代碼在步驟1中列出。
3、若msg.what的值是CommonUtils.FLAG_DOWNLOAD,則在標籤中顯示:下載結束。
若msg.what的值是CommonUtils.FLAG_UPDATE ,則在標籤中顯示:更新結束。
12.4. 發送Runnalbe對象-更新UI
12.4.1.概述
1、Runnable介面
該介面的原始碼如下所示:
public interface Runnable {
public void run();
}
Java規定:一個線程要實現Runnable中的run方法。Android的線程也同樣如此。在new 一個Thread時,查看Android原始碼,將發現內部代碼也是要建立一個Runnable的對象,並實現run方法。
2、Handler.post()方法
Handler類中有一個方法:post(Runnable r);
作用:將Runnable對象作為參數發送至訊息對列中,以下是post方法的原始碼:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
由上代碼可知,Runnable對象r被當作訊息的第一個參數發送至訊息佇列,然後由Looper交給主線程處理,-5所示。
根據以上原理,Runnable.run中的代碼可以在主線程中運行,那麼在Runnable.run方法中可以編寫更新主線程UI的代碼。
12.4.2.樣本
在按鈕單擊事件方法中建立一個背景工作執行緒,在該線程中先類比下載操作,操作結束後,向主線程發送了一個實現Runnable的內部匿名類,代碼如下所示:
public void onClick(View v) {
switch(v.getId()){
case R.id.btnDownload:
//建立Handler對象
final Handler handler=new Handler();
//new一個背景工作執行緒類比下載操作
new Thread(){
public void run() {
CommonUtils.timeConsuming(5);//類比下載操作
/*下載結束後,
*將Runable的內部匿名類的代碼
*當作訊息中的第一個參數發送至訊息對列,
* 再由Looper交給主線程執行*/
handler.post(new Runnable() {
@Override
public void run() {
mTextView.setText("download finished");
}
});
};
}.start();//啟動背景工作執行緒
break;
case R.id.btnUpdate:
break;
}
}
12.5.runOnUiThread()發送Runnable對象
12.5.1.概述
Activity類中提供了一個runOnUiThread方法,該方法封裝了Handler.post方法,因此作用與Handler.post相同。
12.5.2.樣本
用runOnUiThread方法發送Runnable對象,讓主線程執行該對象中的run方法。範例程式碼如下:
//new一個背景工作執行緒
new Thread(){
public void run() {
CommonUtils.timeConsuming(8); //類比更新操作
//建立一個Runnable介面的執行個體
Runnable action=new Runnable() {
//實現run方法,在該方法中可修改UI
@Override
public void run() {
mTextView.setText("update finished");
}
};
//將action對象發送至訊息對列,交由主線程執行run方法中的代碼
runOnUiThread(action);
};
}.start();//啟動線程
12.6. View.post()發送Runnable對象-更新UI
12.6.1.概述
View類中也提供了發送Runnable對象至訊息對列,然後由Looper交給主線程的方法:
1、Post(Runnable r);
2、postDelayed(Runnable r,long delayMillis);
作用:延遲指定時間,再將r對象發送至主線程執行。
12.6.2.樣本
@Override
public void onClick(final View v) {
switch (v.getId()) {
case R.id.download:
new Thread() {
public void run() {
CommonUtils.timeConsuming(1);
Runnable action = new Runnable() {
@Override
public void run() {
mTextView.setText("下載完成");
}
};
//v-當前的按鈕對象,延遲1秒發送action對象由主線程執行
v.postDelayed(action, 1000);
}
}.start();
break;
case R.id.update:
new Thread() {
public void run() {
CommonUtils.timeConsuming(8);
Runnable action = new Runnable() {
@Override
public void run() {
mTextView.setText("更新新聞完成");
}
};
/v-當前的按鈕對象,延遲3秒發送action對象由主線程執行
v.postDelayed(action, 3000);
}
}.start();
break;
12.7.post總結
12.7.1.概述
Android提供了post方法,將Runnable對象(當作訊息中的第一參數)發送至訊息對列,然後由Looper將訊息對列中的訊息交給主線程執行。如此,就可以在Runnable.run中編寫修改UI的代碼。但要注意:不要在run方法中編寫耗時操作的代碼。耗時的代碼要放在背景工作執行緒的run方法中運行。以下列出已介紹過的post的方法
1、runOnUiThread(Runnable):該方法對handler.post進行了封裝。
2、View.post(Runnable):運行被選擇的控制項對象發送Runnable對象。
3、Handler.post(Runnable)
4、View.postDelayed(Runnable, long):延遲發送
5、Handler.postDelayed(Runnable, long):延遲發送
12.7.2.Handler.post與runOnUiThread的比較
1. Handler可以實現線程間訊息通訊。
2. 在代碼的可讀性和效能(建立對象的個數)方面,Handler都更有優勢。
12.8. AsyncTask更新UI
12.8.1.概述
前面我們採用的都是new一個線程對象,採用這種匿名線程的方式存在以下缺陷:
第一,線程的開銷較大,如果每個任務都要建立一個線程,那麼應用程式的效率要低很多;
第二,線程無法管理,匿名線程建立並啟動後就不受程式的控制了,如果有很多個請求發送,那麼就會啟動非常多的線程,系統將不堪重負。 另外,在背景工作執行緒中更新UI還必須要引入handler,這讓代碼看上去非常臃腫。
為瞭解決這一問題,引入了AsyncTask。AsyncTask的特點是任務在主線程之外運行,而回調方法是在主線程中執行, 這就有效地避免了使用Handler帶來的麻煩。閱讀AsyncTask的源碼可知,AsyncTask是使用java.util.concurrent 架構來管理線程以及任務的執行的,concurrent架構是一個非常成熟,高效的架構,經過了嚴格的測試。這說明AsyncTask的設計很好的解決了匿名線程存在的問題。
AsyncTask是抽象類別,子類必須實現抽象方法doInBackground(Params... p) ,在此方法中實現任務的執行工作,比如串連網路擷取資料等。通常還應該實現onPostExecute(Result r)方法,因為應用程式關心的結果在此方法中返回。
提示:AsyncTask一定要在主線程中建立執行個體。
AsyncTask定義了三種泛型型別 Params,Progress和Result。
(1)Params 啟動任務執行的輸入參數,比如HTTP請求的URL。
(2)Progress 背景工作執行的百分比。
(3)Result 後台執行任務最終返回的結果,比如String。
12.8.2.常用方法
AsyncTask 的執行分為四個步驟,每一步都對應一個回調方法,需要注意的是這些方法不應該由應用程式調用,開發人員需要做的就是實現這些方法。在任務的執行過程中,這些方法被自動調用。
1、 onPreExecute();
作用:當任務執行之前開始調用此方法,可以在這裡顯示進度對話方塊。
2、doInBackground(Params...);
作用:在後台線程執行,執行耗時操作。在執行過程中可以調用publicProgress(Progress...)來更新任務的進度。
提示:publicProgress()相當於Handler.sendmessage()方法
3、onProgressUpdate(Progress...);
作用:此方法在主線程執行,用於顯示任務執行的進度。
4、onPostExecute(Result);
作用:此方法在主線程執行,任務執行的結果作為此方法的參數返回。
12.8.3.樣本
用AsyncTask實現圖-6效果,當單擊dwonload按鈕後,在進度條中顯示類比的下載進度,並在標籤中顯示進度的百分比。下載結束後顯示download finised。
圖-6a 圖-6b
public class MainActivity extends Activity implements OnClickListener{
Handler mHandler;
ProgressBar mProgressBar;//聲明進度條
TextView mTextView;//標籤:顯示進度的百分比和操作的結果
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//執行個體化各控制項
mProgressBar=(ProgressBar)findViewById(R.id.progressBar);
mTextView=(TextView)findViewById(R.id.tvMessage);
Button btnDownload=(Button)findViewById(R.id.btnDownload);
Button btnUpdate=(Button)findViewById(R.id.btnUpdate);
//註冊按鈕的單擊事件
btnDownload.setOnClickListener(this);
btnUpdate.setOnClickListener(this);
}
//實現按鈕的單擊時間事件
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnDownload:
//建立對象
MyAsyncTask myAsyncTask=new MyAsyncTask();
myAsyncTask.execute(null);//執行任務
break;
case R.id.btnUpdate:
break;
}
}
private class MyAsyncTask extends AsyncTask<URL, Integer, String>{
//在UI中執行,更新UI
@Override
protected void onProgressUpdate(Integer... values) {
mProgressBar.setProgress(values[0]);
if(values[0]<100){
mTextView.setText("progress="+values[0]+"%");
}
}
//現在work thread中執行耗時操作
@Override
protected String doInBackground(URL... params) {
for (int i = 0; i < 100; i++) {
publishProgress(i+1);//向onProgressUpdate發送訊息
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "download finished";
}
//doInBackground結束後,執行本方法,result是doInBackground方法返回的資料
@Override
protected void onPostExecute(String result) {
mTextView.setText(result);
}
}
}
12.9. 軟體開發術語
12.9.1效能
臨時對象越多,記憶體回收(GC)的頻率越高
GC佔用CPU,CPU被佔用時,無法響應使用者的操作
使用者感覺到卡,影響使用者體驗。
12.9.2資源集區
存放一定數量的同樣類型的對象,當程式需要使用時,可以從資源集區中擷取,使用完成,收回資源集區。
等待下一次被使用。
樣本:從資源集區中擷取Message對象。
Message msg=Message.obtainMessage();
提示:若之前沒有建立過Message,則建立給對象。Android系統會在適當時候回收該對象,方便下次取用。
提示:解決效能問題的前提是不能影響功能。