Service:
(一)、Service 簡介:
1、何謂“Service”?
“Service” 意思即“服務”的意思, 像 Windows 上面的服務一樣,服務是在後臺上運行,承擔着靜悄悄的不爲人所注意的工作。Service運行在後臺,它是不可見的、無界面的程序。
Service可以在很多場合的應用中使用,比如播放多媒體的時候用戶啓動了其他Activity,這個時候程序要在後臺繼續播放;比如檢測SD卡上文件的變化;再或者在後臺記錄用戶的地理信息位置的改變;或者啓動一個服務來運行並一直監聽某種動作等等。
2、Service概念的總結:
Service在後臺運行,不可以與用戶直接交互;
一個服務不是一個單獨的進程。服務對象本身並不意味着它是在自己的進程中運行,除非另有規定,否則它與運行程序是同在一個進程中;
一個服務不是一個單獨的線程。Service和其他組件一樣,默認情況下,Service中的所有代碼都是運行在主線程中;
Service存在的價值雖然不如Activity那麼清晰。但是一般都讓Service執行耗時較長的操作。例如:播放音樂、下載文件、上傳文件等等。但是因爲Service默認運行在主線程中,因此不能直接用它來做耗時的請求或者動作,最好在Service中啓動新線程來運行耗時的任務;
需要通過某一個Activity或其他Context對象來啓動Service。context.startService() 或 context.bindService();
Service很大程度上充當了應用程序後臺線程管理器的角色。(如果Activity中新開啓一個線程,當該Acitivity關閉後,該線程依然在工作,但是與開啓它的Activity失去聯繫。也就是說此時的這個線程處於失去管理的狀態。但是使用Service,則可以對後臺運行的線程有效地管理。)
3、爲什麼不使用後臺線程而使用Service?
1、Service可以放在獨立的進程中,所以更安全;
2、使用Service可以依賴現有的binder機制,不需要在應用層面上處理線程同步的繁雜工作;
3、系統可以重新啓動異常死去的Service。
4、Service 與 Activity 的相同點與不同點:
不同點:Activity是與用戶交互的組件,即可以看到UI界面,而Service是在後臺運行、無需界面;
相同點:使用Activity 時我們需要在配置文件中聲明<activity>標籤,同樣的使用Service 也需要在配置文件中聲明<service>標籤。都具有一定的生命週期。
(二)、服務的分類:
1、本地服務Local Service:
Local Service 用於應用程序內部。用於實現應用程序自己的一些耗時任務,比如查詢升級信息,並不佔用應用程序比如Activity所屬線程,而是單開線程後臺執行,這樣用戶體驗比較好。
啓動service有兩種方法:
1)、 Context.startService()
調用者與服務之間沒有關聯,即使調用者退出,服務仍可運行
2)、 Context.bindService()
調用者與服務綁定在一起,調用者一旦退出,服務也就終止
A、根據啓動方式將本地服務分爲:啓動服務Started Service和綁定服務Bound Service。【重點】
- Started Service:被啓動的服務
- 被啓動的服務是由其它組件調用startService()方法而啓動的,該方法會導致被啓動服務的生命週期方法onStartCommand()被回調。當服務是被啓動狀態後,其生命週期與啓動它的組件無關,即使啓動服務的組件(Activity,BroadcastReceiver)已經被銷燬,該服務還可以在後臺無限期運行。除非調用stopSelf()或stopService()來停止該服務。
- Bound Service:被綁定的服務
- 綁定服務是允許其它應用程序綁定並且與之交互的Service的實現類。爲了提供綁定,必須實現onBind()回調方法。該方法返回IBinder對象,它定義了服務類與Activity交互的程序接口。
- Activity通過bindService()方法綁定到服務類,同時Activity必須提供ServiceConnection接口的實現類,它監視Activity與服務類之間的連接。在重寫ServiceConnection接口的onServiceConnected()方法時,實現了將服務類順利賦值到了Activity中,實現了在Activity中使用該服務類並執行其中的方法。
B、根據onStartCommand()回調方法的返回值,將Service分爲粘性Service和非粘性Service:
onStartCommand()方法有三種返回值:
- START_STICKY(常量值:1):sticky的意思是“粘性的”。使用這個返回值時,我們啓動的服務跟應用程序"粘"在一起,如果在執行完onStartCommand後,服務被異常kill掉,系統會自動重啓該服務。當再次啓動服務時,傳入的第一個參數將爲null;
- START_NOT_STICKY(常量值:2):“非粘性的”。使用這個返回值時,如果在執行完onStartCommand後,服務被異常kill掉,系統不會自動重啓該服務。
- START_REDELIVER_INTENT(常量值:3):重傳Intent。使用這個返回值時,如果在執行完onStartCommand後,服務被異常kill掉,系統會自動重啓該服務,並將Intent的值傳入。
【備註:】
以上三種情況,可以理解爲發生車禍後的人:
START_STICKY:(常量值:1)車禍後自己甦醒,但是失憶;
START_NOT_STICKY:(常量值:2)車禍後再也沒有甦醒;
START_REDELIVER_INTENT:(常量值:3)車禍後自己甦醒,依然保持記憶。
2、遠程服務Remote Service:
Remote Service 用於android系統內部的應用程序之間。可以定義接口並把接口暴露出來,以便其他應用進行操作。可被其他應用程序複用,比如天氣預報服務,其他應用程序不需要再寫這樣的服務,調用已有的即可。
(三)、Service的生命週期:
1、Started Service的生命週期:
onCreate():創建服務
onStartCommand():服務開始運行(在2.0以前版本中,使用onStart()回調方法)
onDestroy() :服務被停止
【詳細說明:】
在程序中調用:context.startService() 會觸發執行Service生命週期中的onCreate()、onStartCommand()回調方法,此時服務就開始正式運行;
如果Service還沒有運行,則android先調用onCreate()然後調用onStartCommand();如果Service已經運行,則只調用onStartCommand(),所以一個Service的onStartCommand方法可能會重複調用多次;
如果在程序中調用:context.stopService()會觸發執行Service生命週期中的onDestroy()回調方法,會讓服務停止;
stopService()的時候直接onDestroy,如果是調用者自己直接退出而沒有調用stopService()的話,Service會一直在後臺運行。該Service的調用者再啓動該Service後可以通過stopService關閉Service;stopSelf()
所以StartService的生命週期爲:onCreate --> onStartCommand(可多次調用) --> onDestroy。
2、Bound Service的生命週期:
onCreate():創建服務
onBind():綁定服務,服務開始運行
onUnbind():取消綁定
onDestroy() :服務被停止
【詳細說明:】
在程序中調用:context.bindService()會觸發執行Service生命週期中的onCreate()、onBind()回調方法,此時服務開始運行;
onBind將返回給客戶端一個IBind接口實例,IBind允許客戶端回調服務的方法,比如得到Service運行的狀態或其他操作。此後調用者(Context,例如Activity)會和Service綁定在一起;
如果調用Service的調用者Context退出了,那麼會依次調用Service生命週期中的onUnbind()、onDestroy()回調方法,會讓服務停止;
所以BindService的生命週期爲:onCreate --> onBind(只一次,不可多次綁定) --> onUnbind --> onDestory。
【備註:】
Service是不能自己啓動的,只有通過 Context 對象調用startService() 和bindService() 方法來啓動。
在Service每一次的開啓關閉過程中,只有onStartCommand()可被多次調用(通過多次startService調用),其他onCreate()、onBind()、onUnbind()、onDestory()在一個生命週期中只能被調用一次。
Service可以在和多場合的應用中使用,比如播放多媒體的時候用戶啓動了其他Activity這個時候程序要在後臺繼續播放,比如檢測SD卡上文件的變化,再或者在後臺記錄你地理信息位置的改變等等,總之服務總是藏在後頭的。
二、本地Service:
(一)、Started Service啓動MediaPlayer播放音樂:
1、操作步驟:
1、寫xml佈局文件;
2、寫MainActivity文件,通過按鈕點擊事件啓動Service;
3、寫繼承於Service的StartService類文件:重寫onCreate()/onStartCommand()/onDestroy()回調方法。
2、XML佈局文件核心代碼:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/button_main_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="播放音樂" />
<Button
android:id="@+id/button_main_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="暫停音樂" />
<Button
android:id="@+id/button_main_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="停止音樂" />
<Button
android:id="@+id/button_main_exit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="關閉當前窗體" />
<Button
android:id="@+id/button_main_stopservice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="停止服務" />
</LinearLayout>
3、MainActivty核心代碼:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private Intent intent = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i (TAG, "==onCreate執行");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(this, StartServicePlayMusic.class);
}
@Override
protected void onDestroy() {
Log.i ("MainActivty", "==onDestroy()");
super.onDestroy();
if (intent != null) {
// 停止服務可以通過stopService(intent)來停止,也可以intent到Service程序中,通過stopSelf()來停止。
stopService(intent);
}
}
public void clickButton(View view) {
int type = 0;
switch (view.getId()) {
case R.id.button_main_play:
type = 1;
break;
case R.id.button_main_pause:
type = 2;
break;
case R.id.button_main_stop:
type = 3;
break;
case R.id.button_main_exit:
finish();
break;
case R.id.button_main_stopservice:
// 停止服務可以通過stopService(intent)來停止,也可以intent到Service程序中,通過stopSelf()來停止
// stopService(intent);
// finish();
type = 4;
break;
}
Bundle bundle = new Bundle();
bundle.putInt("type", type);
intent.putExtras(bundle);
startService(intent);
}
}
4、StartServicePlayMusic核心代碼:
public class StartServicePlayMusic extends Service {
private static final String TAG = "StartServicePlayMusic";
private MediaPlayer mediaPlayer;
@Override
public IBinder onBind(Intent intent) {
Log.i (TAG, "==onBind執行");
return null;
}
@Override
public void onCreate() {
Log.i (TAG, "==onCreate執行");
super.onCreate();
if (mediaPlayer == null) {
mediaPlayer = MediaPlayer.create(this, R.raw.hitta);
mediaPlayer.setLooping(false);
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i (TAG, "==onStartCommand執行");
if (intent != null) {
Bundle bundle = intent.getExtras();
int type = bundle.getInt("type");
switch (type) {
case 1:
play();
break;
case 2:
pause();
break;
case 3:
stop();
break;
case 4:
stopSelf();
break;
}
}
return START_STICKY;
}
@Override
public void onDestroy() {
Log.i (TAG, "==onDestroy執行");
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
public void play() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
public void pause() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
public void stop() {
if (mediaPlayer != null) {
mediaPlayer.stop();
}
}
}
5、Manifest清單配置文件核心代碼:
<service
android:name=".StartServicePlayMusic">
<intent-filter>
<action android:name="com.steven.startservice.playmusic"/>
</intent-filter>
</service>
android:name=".StartServicePlayMusic">
<intent-filter>
<action android:name="com.steven.startservice.playmusic"/>
</intent-filter>
</service>
6、Started Service總結:
Activity頁面中需要startService(intent) 和 stopService(intent)兩個方法來啓動Service和停止Service;
繼承於Service類的自定義子類——MyStartService類中,生命週期回調方法有:onCreate() 、onStartCommand() 、onDestroy();
如果停止服務,可以在Activity中調用stopService(intent),也可以intent到Service中執行stopSelf()方法;
執行停止服務方法,會回調Service生命週期中的onDestroy()方法;
如果希望關閉Activity窗體,服務也停止,那麼在Activity的onDestroy()方法中執行stopService()方法。如果希望關閉窗體後,服務還繼續,那麼Activity的onDestroy()中不執行停止服務即可;
在StartService中不會回調onBind()方法;
在停止服務後,如果再次點擊“播放”,可以重新啓動StartService。
7、IntentService與Service:
不管是何種Service,它默認都是在應用程序的主線程(亦即UI線程)中運行的。所以,如果你的Service將要運行非常耗時或者可能被阻塞的操作時,你的應用程序將會被掛起,甚至會出現ANR錯誤。爲了避免這一問題,你應該在Service中重新啓動一個新的線程來進行這些操作。現有兩種方法大家參考:
① 直接在Service的onStartCommand()方法中新建一個線程來執行;
② Android SDK 中爲我們提供了一個現成的Service類來實現這個功能,它就是IntentService,它主要負責以下幾個方面:
Creates a default worker thread that executes all intents delivered to onStartCommand() separate from your application's main thread.
生成一個默認的且與主線程互相獨立的工作者線程來執行所有傳送至 onStartCommand() 方法的Intetnt
Creates a work queue that passes one intent at a time to your onHandleIntent() implementation, so you never have to worry about multi-threading.
生成一個工作隊列來傳送Intent對象給你的onHandleIntent()方法,同一時刻只傳送一個Intent對象,這樣一來,你就不必擔心多線程的問題。
Stops the service after all start requests have been handled, so you never have to call stopSelf().
在所有的請求(Intent)都被執行完以後會自動停止服務,所以,你不需要自己去調用stopSelf()方法來停止該服務
Provides default implementation of onBind() that returns null.
提供了一個onBind()方法的默認實現,它返回null
Provides a default implementation of onStartCommand() that sends the intent to the work queue and then to your onHandleIntent() implementation
提供了一個onStartCommand()方法的默認實現,它將Intent先傳送至工作隊列,然後從工作隊列中每次取出一個傳送至onHandleIntent()方法,在該方法中對Intent對相應的處理
IntentService使用隊列的方式將請求的Intent加入隊列,然後開啓一個worker thread(線程)來處理隊列中的Intent,對於異步的startService請求,IntentService會處理完成一個之後再處理第二個,每一個請求都會在一個單獨的worker thread中處理,不會阻塞應用程序的主線程。
這裏就給我們提供了一個思路,如果有耗時的操作可以在Service裏面開啓新線程,也可以使用IntentService來處理耗時操作。 但你若是想在Service中讓多個線程併發的話,就得使用第一種方法,在Service內部起多個線程,但是這樣的話,你可要處理好線程的同步。
(1)、Service實現加載圖片的核心代碼:
public class DownloadService extends IntentService {
private static final String TAG = "DownloadService";
private String urlString = "https://www.google.com.hk/images/srpr/logo11w.png";
private NotificationCompat.Builder builder = null;
private NotificationManager manager = null;
public DownloadService() {
super("");
}
@Override
protected void onHandleIntent(Intent intent) {
manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
builder = new NotificationCompat.Builder(getApplicationContext());
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentTitle("提示:");
builder.setContentText("圖片加載完成,請點擊查看!");
builder.setTicker("圖片加載完成");
builder.setAutoCancel(true);
Intent intent2 = new Intent(getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent2,
PendingIntent.FLAG_ONE_SHOT);
builder.setContentIntent(pIntent);
byte[] data = HttpClientHelper.loadByteFromURL(urlString);
boolean flag = SDCardHelper.saveFileToSDCard(data, "Download", "logo11w.png");
if (flag) {
manager.notify(1, builder.build());
}
}
}
(2)、IntentService實現加載圖片的核心代碼:
public class DownloadService extends Service {
private static final String TAG = "DownloadService";
private String urlString = "https://www.google.com.hk/images/srpr/logo11w.png";
private NotificationCompat.Builder builder = null;
private NotificationManager manager = null;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
builder = new NotificationCompat.Builder(getApplicationContext());
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentTitle("提示:");
builder.setContentText("圖片加載完成,請點擊查看!");
builder.setTicker("圖片加載完成");
builder.setAutoCancel(true);
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent,
PendingIntent.FLAG_ONE_SHOT);
builder.setContentIntent(pIntent);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
byte[] data = HttpClientHelper.loadByteFromURL(urlString);
boolean flag = SDCardHelper.saveFileToSDCard(data, "Download","logo11w.png");
if (flag) {
manager.notify(1, builder.build());
stopSelf();
}
}
}).start();
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
(二)、Bound Service啓動MediaPlayer播放音樂:
1、操作步驟:
1、寫xml佈局文件;
2、寫MainActivity文件,構建ServiceConnection對象,重寫其中的抽象方法onServiceDisconnected()和onServiceConnected();
3、寫繼承於Service的BindService類文件,定義繼承於Binder的內部類MyBinder,在其中定義方法getService();
4、BindService類中重寫onCreate()方法、重寫onBind()回調方法,onBind()方法返回MyBinder對象,重寫onDestroy()方法;
2、XML佈局文件:同上
3、MainActivty核心代碼:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private Intent intent;
private ServiceConnection conn = null;
private BindServicePlayMusic musicService;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i (TAG, "==onCreate執行");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 啓動服務有多種寫法:
// 可以通過new Intent(action字符串)來實現;
// intent = new Intent("com.steven.bindservice.playmusic");
intent = new Intent(this, BindServicePlayMusic.class);
conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
musicService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
musicService = ((BindServicePlayMusic.MyBinder) service).getService();
if (musicService != null) {
musicService.play();
}
}
};
}
public void clickButton(View view) {
switch (view.getId()) {
case R.id.button_main_play:
if (musicService == null) {
bindService(intent, conn, Context.BIND_AUTO_CREATE);
} else {
musicService.play();
}
break;
case R.id.button_main_pause:
if (musicService != null) {
musicService.pause();
}
break;
case R.id.button_main_stop:
if (musicService != null) {
musicService.stop();
}
break;
case R.id.button_main_exit:
finish();
break;
case R.id.button_main_stopservice:
// BindService中stopService(intent)不起作用,要通過undbindService來停止服務
// stopService(intent);
// musicService = null的目的是如果停止服務後,再次”播放“,可以正常執行。
// 如果不將musicService設置爲null,再次播放時,將直接執行musicService.play(),
//而不執行bindService(),那麼會導致異常
musicService = null;
unbindService(conn);
break;
}
}
}
4、BindServicePlayMusic核心代碼:
public class BindServicePlayMusic extends Service {
private static final String TAG = "BindServicePlayMusic";
private MediaPlayer mediaPlayer;
private IBinder binder = null;
@Override
public void onCreate() {
Log.i (TAG, "==onCreate執行");
super.onCreate();
if (mediaPlayer == null) {
mediaPlayer = MediaPlayer.create(this, R.raw.heavencity);
mediaPlayer.setLooping(false);
}
binder = new MyBinder();
}
class MyBinder extends Binder {
public BindServicePlayMusic getService() {
return BindServicePlayMusic.this;
}
};
@Override
public IBinder onBind(Intent intent) {
Log.i (TAG, "==onBind執行");
play();
return binder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.i (TAG, "==onUnbind執行");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.i (TAG, "==onDestroy執行");
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
public void play() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
public void pause() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
public void stop() {
if (mediaPlayer != null) {
mediaPlayer.stop();
}
}
}
5、Manifest清單配置文件核心代碼:
<service
android:name=".BindServicePlayMusic">
<intent-filter>
<action android:name=“com.steven.bindservice.playmusic"/>
</intent-filter>
</service>
<service android:name=".BindServicePlayMusic">
<intent-filter>
<action android:name=“com.steven.bindservice.playmusic"/>
</intent-filter>
</service>
<service android:name=".BindServicePlayMusic">
<intent-filter>
<action android:name=“com.steven.bindservice.playmusic"/>
</intent-filter>
</service>
6、Bound Service總結:
三、 拓展知識(進程和生命週期):
Android操作系統嘗試儘可能長時間保持應用的進程,但當可用內存很低時要移走一部分進程。哪些程序可以運行,哪些要被銷燬?答案是:重要級別低的進程可能被淘汰。
按照重要性排列,一共可以分成5級:
1、前臺運行進程:
用戶此時需要處理和顯示的進程。符合下列條件任何一個,這個進程就被認爲是前臺運行進程。
與用戶正發生交互;
它控制一個與用戶交互的必須的基本的服務;
一個正在調用生命週期回調方法的ervice(如onCreate()、onStar()、onDestroy());
一個正在運行onReceive()方法的廣播接收對象。
銷燬前臺運行進程是系統萬不得已的、最後的選擇——當內存不夠系統繼續運行下去時,殺掉一些前臺進程來保證能夠響應用戶的需求。
2、可用進程:
一個可用進程沒有任何前臺組件,但它仍然可以影響到用戶的界面。下面情況發生時,可以稱該進程爲可用進程。
它是一個非前臺的activity,但對用戶仍然可用(onPause()方法已經被調用)。例如:前臺的activity是一個允許上一個activity可見的對話框。也就是說當前activity中是一個對話框,對話框之外的地方能看到前一個activity的界面。
3、服務進程:
服務進程是一個通過調用startService()方法啓動的服務,並且不屬於前兩種情況。儘管服務進程沒有直接被用戶看到,但他們確實是用戶所關心的,比如後臺播放音樂或網絡下載數據,所以系統保證他們的運行。
4、後臺進程:
一個後臺進程就是非當前正在運行的activity(activity的onStop()方法已經被調用),他們不會對用戶體驗造成直接的影響,當沒有足夠內存來運行前臺可見程序時,他們將會被終止。
通常,後臺進程會有很多個在運行,LRU最近使用程序列表來保證經常運行的activity能最後一個被終止。
5、空線程:
一個空線程沒有運行任何可用應用程序,保留他們的唯一原因是爲了設立一個緩存機制,來加快組件啓動的時間。系統經常殺死這些內存來平衡系統的整個系統的資源,進程緩存和基本核心緩存之間的資源。
四、AIDL實現掛斷電話:
(一)、核心代碼:
public class InCallReceiver extends BroadcastReceiver {
private TelephonyManager manager = null;
@Override
public void onReceive(Context context, Intent intent) {
manager = (TelephonyManager) context .getSystemService(Service.TELEPHONY_SERVICE);
switch (manager.getCallState()) {
case TelephonyManager.CALL_STATE_RINGING:
String incomingNumber = intent.getStringExtra("incoming_number");
if ("12345678".equals(incomingNumber)) {
try {
// 獲得TelephonyManager的class對象
Class<TelephonyManager> telephonyManagerClass = TelephonyManager.class;
// 獲得TelephonyManager.getITelephony方法的Method對象
Method telephonyMethod = telephonyManagerClass
.getDeclaredMethod("getITelephony", (Class[]) null);
// 允許訪問私有的方法
telephonyMethod.setAccessible(true);
// 調用getITelephony()方法返回ITelephony對象
ITelephony telephony = (com.android.internal.telephony.ITelephony) telephonyMethod
.invoke(manager, (Object[]) null);
// 掛斷電話
telephony.endCall();
} catch (Exception e) {
Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
break;
}
}
}
(一)、Service 簡介:
1、何謂“Service”?
“Service” 意思即“服務”的意思, 像 Windows 上面的服務一樣,服務是在後臺上運行,承擔着靜悄悄的不爲人所注意的工作。Service運行在後臺,它是不可見的、無界面的程序。
Service可以在很多場合的應用中使用,比如播放多媒體的時候用戶啓動了其他Activity,這個時候程序要在後臺繼續播放;比如檢測SD卡上文件的變化;再或者在後臺記錄用戶的地理信息位置的改變;或者啓動一個服務來運行並一直監聽某種動作等等。
2、Service概念的總結:
Service在後臺運行,不可以與用戶直接交互;
一個服務不是一個單獨的進程。服務對象本身並不意味着它是在自己的進程中運行,除非另有規定,否則它與運行程序是同在一個進程中;
一個服務不是一個單獨的線程。Service和其他組件一樣,默認情況下,Service中的所有代碼都是運行在主線程中;
Service存在的價值雖然不如Activity那麼清晰。但是一般都讓Service執行耗時較長的操作。例如:播放音樂、下載文件、上傳文件等等。但是因爲Service默認運行在主線程中,因此不能直接用它來做耗時的請求或者動作,最好在Service中啓動新線程來運行耗時的任務;
需要通過某一個Activity或其他Context對象來啓動Service。context.startService() 或 context.bindService();
Service很大程度上充當了應用程序後臺線程管理器的角色。(如果Activity中新開啓一個線程,當該Acitivity關閉後,該線程依然在工作,但是與開啓它的Activity失去聯繫。也就是說此時的這個線程處於失去管理的狀態。但是使用Service,則可以對後臺運行的線程有效地管理。)
3、爲什麼不使用後臺線程而使用Service?
1、Service可以放在獨立的進程中,所以更安全;
2、使用Service可以依賴現有的binder機制,不需要在應用層面上處理線程同步的繁雜工作;
3、系統可以重新啓動異常死去的Service。
4、Service 與 Activity 的相同點與不同點:
不同點:Activity是與用戶交互的組件,即可以看到UI界面,而Service是在後臺運行、無需界面;
相同點:使用Activity 時我們需要在配置文件中聲明<activity>標籤,同樣的使用Service 也需要在配置文件中聲明<service>標籤。都具有一定的生命週期。
(二)、服務的分類:
1、本地服務Local Service:
Local Service 用於應用程序內部。用於實現應用程序自己的一些耗時任務,比如查詢升級信息,並不佔用應用程序比如Activity所屬線程,而是單開線程後臺執行,這樣用戶體驗比較好。
啓動service有兩種方法:
1)、 Context.startService()
調用者與服務之間沒有關聯,即使調用者退出,服務仍可運行
2)、 Context.bindService()
調用者與服務綁定在一起,調用者一旦退出,服務也就終止
A、根據啓動方式將本地服務分爲:啓動服務Started Service和綁定服務Bound Service。【重點】
- Started Service:被啓動的服務
- 被啓動的服務是由其它組件調用startService()方法而啓動的,該方法會導致被啓動服務的生命週期方法onStartCommand()被回調。當服務是被啓動狀態後,其生命週期與啓動它的組件無關,即使啓動服務的組件(Activity,BroadcastReceiver)已經被銷燬,該服務還可以在後臺無限期運行。除非調用stopSelf()或stopService()來停止該服務。
- Bound Service:被綁定的服務
- 綁定服務是允許其它應用程序綁定並且與之交互的Service的實現類。爲了提供綁定,必須實現onBind()回調方法。該方法返回IBinder對象,它定義了服務類與Activity交互的程序接口。
- Activity通過bindService()方法綁定到服務類,同時Activity必須提供ServiceConnection接口的實現類,它監視Activity與服務類之間的連接。在重寫ServiceConnection接口的onServiceConnected()方法時,實現了將服務類順利賦值到了Activity中,實現了在Activity中使用該服務類並執行其中的方法。
B、根據onStartCommand()回調方法的返回值,將Service分爲粘性Service和非粘性Service:
onStartCommand()方法有三種返回值:
- START_STICKY(常量值:1):sticky的意思是“粘性的”。使用這個返回值時,我們啓動的服務跟應用程序"粘"在一起,如果在執行完onStartCommand後,服務被異常kill掉,系統會自動重啓該服務。當再次啓動服務時,傳入的第一個參數將爲null;
- START_NOT_STICKY(常量值:2):“非粘性的”。使用這個返回值時,如果在執行完onStartCommand後,服務被異常kill掉,系統不會自動重啓該服務。
- START_REDELIVER_INTENT(常量值:3):重傳Intent。使用這個返回值時,如果在執行完onStartCommand後,服務被異常kill掉,系統會自動重啓該服務,並將Intent的值傳入。
【備註:】
以上三種情況,可以理解爲發生車禍後的人:
START_STICKY:(常量值:1)車禍後自己甦醒,但是失憶;
START_NOT_STICKY:(常量值:2)車禍後再也沒有甦醒;
START_REDELIVER_INTENT:(常量值:3)車禍後自己甦醒,依然保持記憶。
2、遠程服務Remote Service:
Remote Service 用於android系統內部的應用程序之間。可以定義接口並把接口暴露出來,以便其他應用進行操作。可被其他應用程序複用,比如天氣預報服務,其他應用程序不需要再寫這樣的服務,調用已有的即可。
(三)、Service的生命週期:
1、Started Service的生命週期:
onCreate():創建服務
onStartCommand():服務開始運行(在2.0以前版本中,使用onStart()回調方法)
onDestroy() :服務被停止
【詳細說明:】
在程序中調用:context.startService() 會觸發執行Service生命週期中的onCreate()、onStartCommand()回調方法,此時服務就開始正式運行;
如果Service還沒有運行,則android先調用onCreate()然後調用onStartCommand();如果Service已經運行,則只調用onStartCommand(),所以一個Service的onStartCommand方法可能會重複調用多次;
如果在程序中調用:context.stopService()會觸發執行Service生命週期中的onDestroy()回調方法,會讓服務停止;
stopService()的時候直接onDestroy,如果是調用者自己直接退出而沒有調用stopService()的話,Service會一直在後臺運行。該Service的調用者再啓動該Service後可以通過stopService關閉Service;stopSelf()
所以StartService的生命週期爲:onCreate --> onStartCommand(可多次調用) --> onDestroy。
2、Bound Service的生命週期:
onCreate():創建服務
onBind():綁定服務,服務開始運行
onUnbind():取消綁定
onDestroy() :服務被停止
【詳細說明:】
在程序中調用:context.bindService()會觸發執行Service生命週期中的onCreate()、onBind()回調方法,此時服務開始運行;
onBind將返回給客戶端一個IBind接口實例,IBind允許客戶端回調服務的方法,比如得到Service運行的狀態或其他操作。此後調用者(Context,例如Activity)會和Service綁定在一起;
如果調用Service的調用者Context退出了,那麼會依次調用Service生命週期中的onUnbind()、onDestroy()回調方法,會讓服務停止;
所以BindService的生命週期爲:onCreate --> onBind(只一次,不可多次綁定) --> onUnbind --> onDestory。
【備註:】
Service是不能自己啓動的,只有通過 Context 對象調用startService() 和bindService() 方法來啓動。
在Service每一次的開啓關閉過程中,只有onStartCommand()可被多次調用(通過多次startService調用),其他onCreate()、onBind()、onUnbind()、onDestory()在一個生命週期中只能被調用一次。
Service可以在和多場合的應用中使用,比如播放多媒體的時候用戶啓動了其他Activity這個時候程序要在後臺繼續播放,比如檢測SD卡上文件的變化,再或者在後臺記錄你地理信息位置的改變等等,總之服務總是藏在後頭的。
二、本地Service:
(一)、Started Service啓動MediaPlayer播放音樂:
1、操作步驟:
1、寫xml佈局文件;
2、寫MainActivity文件,通過按鈕點擊事件啓動Service;
3、寫繼承於Service的StartService類文件:重寫onCreate()/onStartCommand()/onDestroy()回調方法。
2、XML佈局文件核心代碼:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/button_main_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="播放音樂" />
<Button
android:id="@+id/button_main_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="暫停音樂" />
<Button
android:id="@+id/button_main_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="停止音樂" />
<Button
android:id="@+id/button_main_exit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="關閉當前窗體" />
<Button
android:id="@+id/button_main_stopservice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="停止服務" />
</LinearLayout>
3、MainActivty核心代碼:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private Intent intent = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i (TAG, "==onCreate執行");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(this, StartServicePlayMusic.class);
}
@Override
protected void onDestroy() {
Log.i ("MainActivty", "==onDestroy()");
super.onDestroy();
if (intent != null) {
// 停止服務可以通過stopService(intent)來停止,也可以intent到Service程序中,通過stopSelf()來停止。
stopService(intent);
}
}
public void clickButton(View view) {
int type = 0;
switch (view.getId()) {
case R.id.button_main_play:
type = 1;
break;
case R.id.button_main_pause:
type = 2;
break;
case R.id.button_main_stop:
type = 3;
break;
case R.id.button_main_exit:
finish();
break;
case R.id.button_main_stopservice:
// 停止服務可以通過stopService(intent)來停止,也可以intent到Service程序中,通過stopSelf()來停止
// stopService(intent);
// finish();
type = 4;
break;
}
Bundle bundle = new Bundle();
bundle.putInt("type", type);
intent.putExtras(bundle);
startService(intent);
}
}
4、StartServicePlayMusic核心代碼:
public class StartServicePlayMusic extends Service {
private static final String TAG = "StartServicePlayMusic";
private MediaPlayer mediaPlayer;
@Override
public IBinder onBind(Intent intent) {
Log.i (TAG, "==onBind執行");
return null;
}
@Override
public void onCreate() {
Log.i (TAG, "==onCreate執行");
super.onCreate();
if (mediaPlayer == null) {
mediaPlayer = MediaPlayer.create(this, R.raw.hitta);
mediaPlayer.setLooping(false);
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i (TAG, "==onStartCommand執行");
if (intent != null) {
Bundle bundle = intent.getExtras();
int type = bundle.getInt("type");
switch (type) {
case 1:
play();
break;
case 2:
pause();
break;
case 3:
stop();
break;
case 4:
stopSelf();
break;
}
}
return START_STICKY;
}
@Override
public void onDestroy() {
Log.i (TAG, "==onDestroy執行");
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
public void play() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
public void pause() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
public void stop() {
if (mediaPlayer != null) {
mediaPlayer.stop();
}
}
}
5、Manifest清單配置文件核心代碼:
<service
android:name=".StartServicePlayMusic">
<intent-filter>
<action android:name="com.steven.startservice.playmusic"/>
</intent-filter>
</service>
android:name=".StartServicePlayMusic">
<intent-filter>
<action android:name="com.steven.startservice.playmusic"/>
</intent-filter>
</service>
6、Started Service總結:
Activity頁面中需要startService(intent) 和 stopService(intent)兩個方法來啓動Service和停止Service;
繼承於Service類的自定義子類——MyStartService類中,生命週期回調方法有:onCreate() 、onStartCommand() 、onDestroy();
如果停止服務,可以在Activity中調用stopService(intent),也可以intent到Service中執行stopSelf()方法;
執行停止服務方法,會回調Service生命週期中的onDestroy()方法;
如果希望關閉Activity窗體,服務也停止,那麼在Activity的onDestroy()方法中執行stopService()方法。如果希望關閉窗體後,服務還繼續,那麼Activity的onDestroy()中不執行停止服務即可;
在StartService中不會回調onBind()方法;
在停止服務後,如果再次點擊“播放”,可以重新啓動StartService。
7、IntentService與Service:
不管是何種Service,它默認都是在應用程序的主線程(亦即UI線程)中運行的。所以,如果你的Service將要運行非常耗時或者可能被阻塞的操作時,你的應用程序將會被掛起,甚至會出現ANR錯誤。爲了避免這一問題,你應該在Service中重新啓動一個新的線程來進行這些操作。現有兩種方法大家參考:
① 直接在Service的onStartCommand()方法中新建一個線程來執行;
② Android SDK 中爲我們提供了一個現成的Service類來實現這個功能,它就是IntentService,它主要負責以下幾個方面:
Creates a default worker thread that executes all intents delivered to onStartCommand() separate from your application's main thread.
生成一個默認的且與主線程互相獨立的工作者線程來執行所有傳送至 onStartCommand() 方法的Intetnt
Creates a work queue that passes one intent at a time to your onHandleIntent() implementation, so you never have to worry about multi-threading.
生成一個工作隊列來傳送Intent對象給你的onHandleIntent()方法,同一時刻只傳送一個Intent對象,這樣一來,你就不必擔心多線程的問題。
Stops the service after all start requests have been handled, so you never have to call stopSelf().
在所有的請求(Intent)都被執行完以後會自動停止服務,所以,你不需要自己去調用stopSelf()方法來停止該服務
Provides default implementation of onBind() that returns null.
提供了一個onBind()方法的默認實現,它返回null
Provides a default implementation of onStartCommand() that sends the intent to the work queue and then to your onHandleIntent() implementation
提供了一個onStartCommand()方法的默認實現,它將Intent先傳送至工作隊列,然後從工作隊列中每次取出一個傳送至onHandleIntent()方法,在該方法中對Intent對相應的處理
IntentService使用隊列的方式將請求的Intent加入隊列,然後開啓一個worker thread(線程)來處理隊列中的Intent,對於異步的startService請求,IntentService會處理完成一個之後再處理第二個,每一個請求都會在一個單獨的worker thread中處理,不會阻塞應用程序的主線程。
這裏就給我們提供了一個思路,如果有耗時的操作可以在Service裏面開啓新線程,也可以使用IntentService來處理耗時操作。 但你若是想在Service中讓多個線程併發的話,就得使用第一種方法,在Service內部起多個線程,但是這樣的話,你可要處理好線程的同步。
(1)、Service實現加載圖片的核心代碼:
public class DownloadService extends IntentService {
private static final String TAG = "DownloadService";
private String urlString = "https://www.google.com.hk/images/srpr/logo11w.png";
private NotificationCompat.Builder builder = null;
private NotificationManager manager = null;
public DownloadService() {
super("");
}
@Override
protected void onHandleIntent(Intent intent) {
manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
builder = new NotificationCompat.Builder(getApplicationContext());
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentTitle("提示:");
builder.setContentText("圖片加載完成,請點擊查看!");
builder.setTicker("圖片加載完成");
builder.setAutoCancel(true);
Intent intent2 = new Intent(getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent2,
PendingIntent.FLAG_ONE_SHOT);
builder.setContentIntent(pIntent);
byte[] data = HttpClientHelper.loadByteFromURL(urlString);
boolean flag = SDCardHelper.saveFileToSDCard(data, "Download", "logo11w.png");
if (flag) {
manager.notify(1, builder.build());
}
}
}
(2)、IntentService實現加載圖片的核心代碼:
public class DownloadService extends Service {
private static final String TAG = "DownloadService";
private String urlString = "https://www.google.com.hk/images/srpr/logo11w.png";
private NotificationCompat.Builder builder = null;
private NotificationManager manager = null;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
builder = new NotificationCompat.Builder(getApplicationContext());
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentTitle("提示:");
builder.setContentText("圖片加載完成,請點擊查看!");
builder.setTicker("圖片加載完成");
builder.setAutoCancel(true);
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent,
PendingIntent.FLAG_ONE_SHOT);
builder.setContentIntent(pIntent);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
byte[] data = HttpClientHelper.loadByteFromURL(urlString);
boolean flag = SDCardHelper.saveFileToSDCard(data, "Download","logo11w.png");
if (flag) {
manager.notify(1, builder.build());
stopSelf();
}
}
}).start();
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
(二)、Bound Service啓動MediaPlayer播放音樂:
1、操作步驟:
1、寫xml佈局文件;
2、寫MainActivity文件,構建ServiceConnection對象,重寫其中的抽象方法onServiceDisconnected()和onServiceConnected();
3、寫繼承於Service的BindService類文件,定義繼承於Binder的內部類MyBinder,在其中定義方法getService();
4、BindService類中重寫onCreate()方法、重寫onBind()回調方法,onBind()方法返回MyBinder對象,重寫onDestroy()方法;
2、XML佈局文件:同上
3、MainActivty核心代碼:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private Intent intent;
private ServiceConnection conn = null;
private BindServicePlayMusic musicService;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i (TAG, "==onCreate執行");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 啓動服務有多種寫法:
// 可以通過new Intent(action字符串)來實現;
// intent = new Intent("com.steven.bindservice.playmusic");
intent = new Intent(this, BindServicePlayMusic.class);
conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
musicService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
musicService = ((BindServicePlayMusic.MyBinder) service).getService();
if (musicService != null) {
musicService.play();
}
}
};
}
public void clickButton(View view) {
switch (view.getId()) {
case R.id.button_main_play:
if (musicService == null) {
bindService(intent, conn, Context.BIND_AUTO_CREATE);
} else {
musicService.play();
}
break;
case R.id.button_main_pause:
if (musicService != null) {
musicService.pause();
}
break;
case R.id.button_main_stop:
if (musicService != null) {
musicService.stop();
}
break;
case R.id.button_main_exit:
finish();
break;
case R.id.button_main_stopservice:
// BindService中stopService(intent)不起作用,要通過undbindService來停止服務
// stopService(intent);
// musicService = null的目的是如果停止服務後,再次”播放“,可以正常執行。
// 如果不將musicService設置爲null,再次播放時,將直接執行musicService.play(),
//而不執行bindService(),那麼會導致異常
musicService = null;
unbindService(conn);
break;
}
}
}
4、BindServicePlayMusic核心代碼:
public class BindServicePlayMusic extends Service {
private static final String TAG = "BindServicePlayMusic";
private MediaPlayer mediaPlayer;
private IBinder binder = null;
@Override
public void onCreate() {
Log.i (TAG, "==onCreate執行");
super.onCreate();
if (mediaPlayer == null) {
mediaPlayer = MediaPlayer.create(this, R.raw.heavencity);
mediaPlayer.setLooping(false);
}
binder = new MyBinder();
}
class MyBinder extends Binder {
public BindServicePlayMusic getService() {
return BindServicePlayMusic.this;
}
};
@Override
public IBinder onBind(Intent intent) {
Log.i (TAG, "==onBind執行");
play();
return binder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.i (TAG, "==onUnbind執行");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.i (TAG, "==onDestroy執行");
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
public void play() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
public void pause() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
public void stop() {
if (mediaPlayer != null) {
mediaPlayer.stop();
}
}
}
5、Manifest清單配置文件核心代碼:
<service
android:name=".BindServicePlayMusic">
<intent-filter>
<action android:name=“com.steven.bindservice.playmusic"/>
</intent-filter>
</service>
<service android:name=".BindServicePlayMusic">
<intent-filter>
<action android:name=“com.steven.bindservice.playmusic"/>
</intent-filter>
</service>
<service android:name=".BindServicePlayMusic">
<intent-filter>
<action android:name=“com.steven.bindservice.playmusic"/>
</intent-filter>
</service>
6、Bound Service總結:
三、 拓展知識(進程和生命週期):
Android操作系統嘗試儘可能長時間保持應用的進程,但當可用內存很低時要移走一部分進程。哪些程序可以運行,哪些要被銷燬?答案是:重要級別低的進程可能被淘汰。
按照重要性排列,一共可以分成5級:
1、前臺運行進程:
用戶此時需要處理和顯示的進程。符合下列條件任何一個,這個進程就被認爲是前臺運行進程。
與用戶正發生交互;
它控制一個與用戶交互的必須的基本的服務;
一個正在調用生命週期回調方法的ervice(如onCreate()、onStar()、onDestroy());
一個正在運行onReceive()方法的廣播接收對象。
銷燬前臺運行進程是系統萬不得已的、最後的選擇——當內存不夠系統繼續運行下去時,殺掉一些前臺進程來保證能夠響應用戶的需求。
2、可用進程:
一個可用進程沒有任何前臺組件,但它仍然可以影響到用戶的界面。下面情況發生時,可以稱該進程爲可用進程。
它是一個非前臺的activity,但對用戶仍然可用(onPause()方法已經被調用)。例如:前臺的activity是一個允許上一個activity可見的對話框。也就是說當前activity中是一個對話框,對話框之外的地方能看到前一個activity的界面。
3、服務進程:
服務進程是一個通過調用startService()方法啓動的服務,並且不屬於前兩種情況。儘管服務進程沒有直接被用戶看到,但他們確實是用戶所關心的,比如後臺播放音樂或網絡下載數據,所以系統保證他們的運行。
4、後臺進程:
一個後臺進程就是非當前正在運行的activity(activity的onStop()方法已經被調用),他們不會對用戶體驗造成直接的影響,當沒有足夠內存來運行前臺可見程序時,他們將會被終止。
通常,後臺進程會有很多個在運行,LRU最近使用程序列表來保證經常運行的activity能最後一個被終止。
5、空線程:
一個空線程沒有運行任何可用應用程序,保留他們的唯一原因是爲了設立一個緩存機制,來加快組件啓動的時間。系統經常殺死這些內存來平衡系統的整個系統的資源,進程緩存和基本核心緩存之間的資源。
四、AIDL實現掛斷電話:
(一)、核心代碼:
public class InCallReceiver extends BroadcastReceiver {
private TelephonyManager manager = null;
@Override
public void onReceive(Context context, Intent intent) {
manager = (TelephonyManager) context .getSystemService(Service.TELEPHONY_SERVICE);
switch (manager.getCallState()) {
case TelephonyManager.CALL_STATE_RINGING:
String incomingNumber = intent.getStringExtra("incoming_number");
if ("12345678".equals(incomingNumber)) {
try {
// 獲得TelephonyManager的class對象
Class<TelephonyManager> telephonyManagerClass = TelephonyManager.class;
// 獲得TelephonyManager.getITelephony方法的Method對象
Method telephonyMethod = telephonyManagerClass
.getDeclaredMethod("getITelephony", (Class[]) null);
// 允許訪問私有的方法
telephonyMethod.setAccessible(true);
// 調用getITelephony()方法返回ITelephony對象
ITelephony telephony = (com.android.internal.telephony.ITelephony) telephonyMethod
.invoke(manager, (Object[]) null);
// 掛斷電話
telephony.endCall();
} catch (Exception e) {
Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
break;
}
}
}