第七章 后臺服務(wù)(本地服務(wù))

?參考資料:
《Android應(yīng)用程序開發(fā)》ISBN 9787302283164
參考軟件:
Android Studio、Eclipse+ADT、Android SDK、JDK
本地服務(wù)
本地服務(wù)的調(diào)用者和服務(wù)都在同一個程序中,是不需要跨進(jìn)程就可以實(shí)現(xiàn)服務(wù)的調(diào)用
步驟1:新建子類繼承Service類
需重寫父類的onCreate()、onStartCommand()、onDestroy()和onBind()方法
步驟2:構(gòu)建用于啟動Service的Intent對象
步驟3:調(diào)用startService()啟動Service、調(diào)用stopService()停止服務(wù)
步驟4:在AndroidManifest.xml里注冊Service
一、實(shí)現(xiàn)啟動服務(wù)(1)界面實(shí)現(xiàn)

<?xml?version="1.0"??encoding="utf-8"?>
?
<LinearLayout?xmlns:android="http://schemas.android.com/apk/res/android"
?
??? ?android:orientation="vertical"
?
??? ?android:layout_width="fill_parent"
?
??? ?android:layout_height="fill_parent"
?
??? ?>
?
??<TextView? ?android:id="@+id/label"
?
??? ?android:layout_width="fill_parent"??
?
??? ?android:layout_height="wrap_content"??
?
??? ?android:text="@string/hello">
?
??</TextView>
?
??<Button?android:id="@+id/start"??
?
?????android:layout_width="wrap_content"
?
?????android:layout_height="wrap_content"
?
?????android:text="啟動Service"?>
?
??</Button>
?
??<Button?android:id="@+id/stop"??
?
?????android:layout_width="wrap_content"
?
?????android:layout_height="wrap_content"
?
?????android:text="停止Service"?>
?
??</Button>
?
</LinearLayout>
?
?
?
(2)建立Service類
?
?
package ?edu.hrbeu.SimpleRandomServiceDemo;
?
?
?
import android.app.Service;
?
import android.content.Intent;
?
import android.os.IBinder;
?
import android.widget.Toast;
?
?
?
public class RandomService extends ?Service{
?
????????
?
???????? @Override
?
???????? public ?void onCreate() {
?
???????? ??? super.onCreate();
?
???????? ??? Toast.makeText(this, "(1)?調(diào)用onCreate()",
?
???????? ??? ?????????????????? Toast.LENGTH_LONG).show();???
?
???????? }
?
????????
?
???????? @Override
?
???????? public ?void onStart(Intent intent, int startId) {
?
???????? ????? super.onStart(intent, startId);
?
???????? ????? Toast.makeText(this, "(2)?調(diào)用onStart()",
?
???????? ??? ?????????????????? ??Toast.LENGTH_SHORT).show();
?
?
?
???????? ????? double randomDouble = Math.random();
?
???????? ????? String msg = "隨機(jī)數(shù):"+ String.valueOf(randomDouble);
?
???????? ????? Toast.makeText(this,msg, ?Toast.LENGTH_SHORT).show();
?
???????? }
?
????????
?
???????? @Override
?
???????? public ?void onDestroy() {
?
???????? ???? super.onDestroy();
?
???????? ???? Toast.makeText(this, "(3)?調(diào)用onDestroy()",
?
???????? ??? ?????????????????? ?Toast.LENGTH_SHORT).show();????
?
???????? }
?
???????? ?
?
????????
?
???????? @Override
?
???????? public ?IBinder onBind(Intent intent) {
?
?????????????????? return ?null;
?
???????? }
?
?
?
}
?
(3)注冊Service

?
?
<service ?android:name=".RandomService"/>
?
(4)實(shí)現(xiàn)啟動和停止
顯示啟動
1??? ?final Intent serviceIntent = new Intent(this, RandomService.class);
?
2??? ?startService(serviceIntent);
?
?
?
?
?
隱式啟動
?
?
?
1??? ?<service android:name=".RandomService">
?
2??????? ?<intent-filter>
?
3??????????? <action ?android:name="edu.hrbeu.RandomService" />
?
4??????? ?</intent-filter>
?
5??? ?</service>
?
?
?
?
?
?
?
?
?
package edu.hrbeu.SimpleRandomServiceDemo;
?
?
?
import android.app.Activity;
?
import android.content.Intent;
?
import android.os.Bundle;
?
import android.view.View;
?
import android.widget.Button;
?
?
?
public class ?SimpleRandomServiceDemoActivity extends Activity {
?
??? ?/** Called when the activity is first created. */
?
??? ?@Override
?
??? ?public void onCreate(Bundle savedInstanceState) {
?
??????? ?super.onCreate(savedInstanceState);
?
??????? ?setContentView(R.layout.main);
?
??????? ?
?
??????? ?Button startButton = (Button)findViewById(R.id.start);
?
??????? ?Button stopButton = (Button)findViewById(R.id.stop);
?
??????? ?
?
??????? ?final Intent serviceIntent = new Intent(this, RandomService.class);
?
??????? ?
?
??????? ?startButton.setOnClickListener(new Button.OnClickListener(){
?
??????? ????????? public void onClick(View ?view){
?
??????? ??????????????????? startService(serviceIntent);
?
??????? ????????? }
?
??????? ?});
?
??????? ?
?
??????? ?stopButton.setOnClickListener(new Button.OnClickListener(){
?
??????? ????????? public void onClick(View ?view){
?
??????? ??????????????????? stopService(serviceIntent);
?
??????? ????????? }
?
??????? ?});
?
? ??}
?
}
?
停止一個started服務(wù)有兩種方法:
(1)在外部使用stopService()
(2)在服務(wù)內(nèi)部(onStartCommand方法內(nèi)部)使用stopSelf()方法。
?
(5)查看
我們還可以在正在“設(shè)置--應(yīng)用---運(yùn)行”中找到這個服務(wù),如下圖所示:

點(diǎn)開上圖中的紅框部分,可以看到:

Android獲取手機(jī)狀態(tài)和監(jiān)聽手機(jī)來電狀態(tài)例子
獲取手機(jī)狀態(tài):
import?android.content.Context;??
import?android.telephony.TelephonyManager;??
??
//獲得相應(yīng)的系統(tǒng)服務(wù)??
TelephonyManager?tm?=?(TelephonyManager)?getSystemService(Context.TELEPHONY_SERVICE);??
???????/**?
????????*?返回電話狀態(tài)?
????????*??
????????*?CALL_STATE_IDLE?無任何狀態(tài)時??
????????*?CALL_STATE_OFFHOOK?接起電話時?
????????*?CALL_STATE_RINGING?電話進(jìn)來時??
????????*/??
???????tm.getCallState();??
???????if(tm.getCallState()?==?TelephonyManager.CALL_STATE_IDLE)?{??
????????Log.d("test",?"call?state?idle...");??
???????}?else?if(tm.getCallState()?==?TelephonyManager.CALL_STATE_OFFHOOK)?{??
????????Log.d("test",?"call?state?offhook...");??
???????}?else?if(tm.getCallState()?==?TelephonyManager.CALL_STATE_RINGING)?{??
????????Log.d("test",?"call?state?ringing...");??
???????} ?
監(jiān)聽手機(jī)來電狀態(tài):
TelephonyManager?tm?=?(TelephonyManager)?getSystemService(Context.TELEPHONY_SERVICE);??
??
//使用TelephonyManager對象的listen(PhoneStateListener?listener,?int?events)??
??
??
//實(shí)現(xiàn)PhoneStateListener?listener并實(shí)現(xiàn)相應(yīng)的方法??
??
public?class?MyPhoneCallListener?extends?PhoneStateListener??
{??
??
@Override??
public?void?onCallStateChanged(int?state,?String?incomingNumber)??
{??
??
??switch?(state)?{??
????case?TelephonyManager.CALL_STATE_OFFHOOK:???????????????????//電話通話的狀態(tài)??
????????Toast.makeText(Main.this,?"正在通話...",?Toast.LENGTH_SHORT).show();??
????????break;??
??
????case?TelephonyManager.CALL_STATE_RINGING:???????????????????//電話響鈴的狀態(tài)??
????????Toast.makeText(Main.this,?incomingNumber,?Toast.LENGTH_SHORT).show();??
????????break;??
??}??
??super.onCallStateChanged(state,?incomingNumber);??
} ?
第一個參數(shù)需要實(shí)現(xiàn)PhoneStateListener listener并實(shí)現(xiàn)相應(yīng)的方法,第二個參數(shù)是PhoneStateListener的靜態(tài)常量,此處由于是監(jiān)聽電話狀態(tài),所以需要傳入LISTEN_CALL_STATE,而同時也需要在AndroidManifest中注冊相應(yīng)的權(quán)限
<uses-permission?Android:name="android.permission.READ_PHONE_STATE" />
二、實(shí)現(xiàn)綁定服務(wù)
以綁定方式使用Service,能夠獲取到Service實(shí)例,不僅能夠正常啟動Service,還能夠調(diào)用Service中的公有方法和屬性
應(yīng)用程序組件(客戶端)通過調(diào)用bindService()方法能夠綁定服務(wù),然后Android系統(tǒng)會調(diào)用服務(wù)的onBind()回調(diào)方法,則個方法會返回一個跟服務(wù)器端交互的Binder對象。
這個綁定是異步的,bindService()方法立即返回,并且不給客戶端返回IBinder對象。要接收IBinder對象,客戶端必須創(chuàng)建一個ServiceConnection類的實(shí)例,并且把這個實(shí)例傳遞給bindService()方法。ServiceConnection對象包含了一個系統(tǒng)調(diào)用的傳遞IBinder對象的回調(diào)方法。
注意:只有Activity、Service、Content Provider能夠綁定服務(wù);BroadcastReceiver廣播接收器不能綁定服務(wù)。
?
(1)界面實(shí)現(xiàn)

?
?
<?xml?version="1.0"??encoding="utf-8"?>
?
<LinearLayout?xmlns:android="http://schemas.android.com/apk/res/android"
?
??? ?android:orientation="vertical"
?
??? ?android:layout_width="fill_parent"
?
?? ??android:layout_height="fill_parent"
?
??? ?>
?
??<TextView? ?android:id="@+id/label"
?
??? ?android:layout_width="fill_parent"??
?
??? ?android:layout_height="wrap_content"??
?
??? ?android:text="@string/hello">
?
??</TextView>
?
??<Button?android:id="@+id/bind"??
?
?????android:layout_width="wrap_content"
?
?????android:layout_height="wrap_content"
?
?????android:text="服務(wù)綁定"?>
?
??</Button>
?
?????<Button?android:id="@+id/unbind"??
?
?????android:layout_width="wrap_content"
?
?????android:layout_height="wrap_content"
?
?????android:text="取消綁定"?>
?
??</Button>
?
??<Button?android:id="@+id/compute"??
?
?????android:layout_width="wrap_content"
?
?????android:layout_height="wrap_content"
?
?????android:text="加法運(yùn)算"?>
?
??</Button>
?
</LinearLayout>
?
?
?
?
(2)建立服務(wù)類
?
?
package edu.hrbeu.SimpleMathServiceDemo;
?
?
?
import android.app.Service;
?
import android.content.Intent;
?
import android.os.Binder;
?
import android.os.IBinder;
?
import android.widget.Toast;
?
?
?
public class MathService extends Service{
?
?
?
???????? private ?final IBinder mBinder = new LocalBinder();
?
?
?
???????? public ?class LocalBinder extends Binder{
?
?????????????????? MathService ?getService() {
?
??????????????????????????? return ?MathService.this;
?
???????? ??? }
?
???????? }
?
?
?
???????? @Override
?
???????? public ?IBinder onBind(Intent intent) {
?
?????????????????? ?Toast.makeText(this, "本地綁定:MathService",
?
???????? ???? ??????????????? ??Toast.LENGTH_SHORT).show();
?
?????????????????? return ?mBinder;
?
???????? }
?
????????
?
???????? @Override
?
???????? public ?boolean onUnbind(Intent intent){
?
?????????????????? ? Toast.makeText(this, "取消本地綁定:MathService",
?
?????????????????? ??? ?????????????????? ?Toast.LENGTH_SHORT).show();?
?
?????????????????? return ?false;
?
???????? }
?
????????
?
?
?
???????? public ?long Add(long a, long b){
?
?????????????????? return ?a+b;
?
???????? }
?
????????
?
}
?
?
(3)注冊

?
?
<service android:name=".MathService"/>
?
(4)實(shí)現(xiàn)啟動和停止
?
?
package edu.hrbeu.SimpleMathServiceDemo;
?
?
?
import android.app.Activity;
?
import android.content.ComponentName;
?
import android.content.Context;
?
import android.content.Intent;
?
import android.content.ServiceConnection;
?
import android.os.Bundle;
?
import android.os.IBinder;
?
import android.view.View;
?
import android.widget.Button;
?
import android.widget.TextView;
?
?
?
public class SimpleMathServiceDemoActivity ?extends Activity {
?
???????? private ?MathService mathService;
?
???????? private ?boolean isBound = false;
?
???????? TextView ?labelView;
?
??? ?@Override
?
??? ?public void onCreate(Bundle savedInstanceState) {
?
??????? ?super.onCreate(savedInstanceState);
?
??????? ?setContentView(R.layout.main);
?
??????? ?
?
??????? ?labelView = (TextView)findViewById(R.id.label);
?
??????? ?Button bindButton = (Button)findViewById(R.id.bind);
?
??????? ?Button unbindButton = (Button)findViewById(R.id.unbind);
?
??????? ?Button computButton = (Button)findViewById(R.id.compute);
?
??????? ?
?
??????? ?bindButton.setOnClickListener(new View.OnClickListener(){
?
??????????????????????????? @Override
?
??????????????????????????? public ?void onClick(View v) {
?
???????????????????????????????????? if(!isBound){
?
?????????????????????????????????????????????? final ?Intent serviceIntent = new ?Intent(SimpleMathServiceDemoActivity.this,MathService.class);
?
?????????????????????????????????????????????? bindService(serviceIntent,mConnection,Context.BIND_AUTO_CREATE);
?
?????????????????????????????????????????????? isBound ?= true;
?
???????????????????????????????????? }
?
??????????????????????????? }? ??
?
??????? ?});
?
??????? ?
?
??????? ?unbindButton.setOnClickListener(new View.OnClickListener(){
?
??????????????????????????? @Override
?
??????????????????????????? public ?void onClick(View v) {
?
???????????????????????????????????? if(isBound){
?
?????????????????????????????????????????????? isBound ?= false;
?
?????????????????????????????????????????????? unbindService(mConnection);
?
?????????????????????????????????????????????? mathService ?= null;
?
???????????????????????????????????? }
?
??????????????????????????? }??? ???????
?
??????? ?});
?
??????? ?
?
??????? ?computButton.setOnClickListener(new View.OnClickListener(){
?
??????????????????????????? @Override
?
??????????????????????????? public ?void onClick(View v) {
?
?????????????????????????????????????????????? if ?(mathService == null){
?
??????????????????????????????????????????????????????? labelView.setText("未綁定服務(wù)");
?
??????????????????????????????????????????????????????? return;
?
?????????????????????????????????????????????? }
?
?????????????????????????????????????????????? long ?a = Math.round(Math.random()*100);
?
?????????????????????????????????????????????? long ?b = Math.round(Math.random()*100);
?
?????????????????????????????????????????????? long ?result = mathService.Add(a, b);
?
?????????????????????????????????????????????? String ?msg = String.valueOf(a)+" + "+String.valueOf(b)+
?
??????????????????????????????????????????????????????????????????????????????????? " ?= "+String.valueOf(result);
?
?????????????????????????????????????????????? labelView.setText(msg);
?
??????????????????????????? } ??????
?
??????? ?});
?
?
?
??? ?}
?
??? ?
?
??? ?private ServiceConnection mConnection = new ServiceConnection() {
?
?????????????????? @Override
?
?????????????????? public ?void onServiceConnected(ComponentName name, IBinder service) {
?
???????? ?????????????????? mathService = ?((MathService.LocalBinder)service).getService();
?
?????????????????? }
?
?
?
?????????????????? @Override
?
?????????????????? public ?void onServiceDisconnected(ComponentName name) {
?
??????????????????????????? mathService ?= null;?
?
?????????????????? }
?
??? ?};
?
}
?三、IntentService(多線程)
IntentService是Android里面的一個封裝類,繼承自四大組件之一的Service。
作用是:處理異步請求,實(shí)現(xiàn)多線程
1.?工作流程

工作流程
注意:若啟動IntentService?多次,那么每個耗時操作則以隊(duì)列的方式在?IntentService的onHandleIntent回調(diào)方法中依次執(zhí)行,執(zhí)行完自動結(jié)束。
2.?實(shí)現(xiàn)步驟
·????????步驟1:定義IntentService的子類:傳入線程名稱、復(fù)寫onHandleIntent()方法
·????????步驟2:在Manifest.xml中注冊服務(wù)
·????????步驟3:在Activity中開啟Service服務(wù)
3.?例子
服務(wù)中的代碼默認(rèn)運(yùn)行在主線程中,如果直接在服務(wù)里執(zhí)行一些耗時操作,容易造成ANR(Application NotResponding)異常,所以就需要用到多線程的知識了。
一個比較標(biāo)準(zhǔn)的服務(wù)可以這樣寫
?
?
package com.example.servicetest;
?
?
?
import android.app.Service;
?
import android.content.Intent;
?
import android.os.IBinder;
?
?
?
public class MyService extends Service ?{?
?
????? ?
?
??? ?public static final String TAG = "MyService";??
?
?
?
??? ?//服務(wù)執(zhí)行的操作
?
??? ?@Override?
?
??? ?public int onStartCommand(Intent intent, int flags, int startId) ?{?
?
??????? ?new Thread(new Runnable() {
?
??????????? public void run() {
?
??????????????? //處理具體的邏輯
?
??????????????? stopSelf();? //服務(wù)執(zhí)行完畢后自動停止
?
??????????? }
?
??????? ?}).start();???????
?
??????? ?return super.onStartCommand(intent, flags, startId);?
?
??? ?}
?
?
?
??? ?@Override
?
??? ?public IBinder onBind(Intent intent) {
?
??????? ?// TODO Auto-generated method stub
?
??????? ?return null;
?
??? ?}?????
?
?
?
}
?
(1)新建一個MyIntentService類
?
?
package com.example.servicetest;
?
?
?
import android.app.IntentService;
?
import android.content.Intent;
?
import android.util.Log;
?
?
?
public class MyIntentService extends ?IntentService{
?
?
?
??? ?public MyIntentService() {
?
??????? ?super("MyIntentService");//調(diào)用父類有參構(gòu)造函數(shù)。這里我們手動給服務(wù)起個名字為:MyIntentService
?
??????? ?// TODO Auto-generated constructor stub
?
??? ?}
?
?
?
??? ?//該方法在會在一個單獨(dú)的線程中執(zhí)行,來完成工作任務(wù)。任務(wù)結(jié)束后,該Service自動停止
?
??? ?@Override
?
??? ?protected void onHandleIntent(Intent intent) {
?
??????? ?// TODO Auto-generated method stub
?
??????? ?for(int i = 0;i<3;i++) {
?
??????????? //打印當(dāng)前線程的id
?
??????????? ?Log.d("MyIntentService","IntentService線程的id是:"+Thread.currentThread().getId());
?
??????????? try {
?
????? ???????????Thread.sleep(1000);
?
??????????? } catch (InterruptedException e) ?{
?
??????????????? // TODO Auto-generated catch ?block
?
??????????????? e.printStackTrace();
?
??????????? }
?
??????? ?}???????
?
??? ?}
?
?
?
??? ?@Override
?
??? ?public void onDestroy() {
?
??????? ?// TODO Auto-generated method stub
?
??????? ?super.onDestroy();
?
??????? ?Log.d("MyIntentService","onDestroy");
?
??? ?}
?
}
?
(2)在清單文件中對服務(wù)進(jìn)行注冊服務(wù)
?
?
<service?android:name=".MyIntentService"></service>
?
?
?
(3)實(shí)現(xiàn)啟動
在activity_main.xml中添加一個按鈕button3_stop_intentservice,用于啟動MyIntentService服務(wù),代碼略
?
?
case?R.id.button3_stop_intentservice:
2?????????????Log.d("MainActivity","主線程的id是:"+Thread.currentThread().getId());
3?????????????Intent?intentService?=?new?Intent(this,MyIntentService.class);
4?????????????startService(intentService);
5?????????default:
?
?
?

3.?總結(jié)
從上面源碼可以看出,IntentService本質(zhì)是采用Handler & HandlerThread方式:通過HandlerThread單獨(dú)開啟一個名為IntentService的線程
創(chuàng)建一個名叫ServiceHandler的內(nèi)部Handler
把內(nèi)部Handler與HandlerThread所對應(yīng)的子線程進(jìn)行綁定
通過onStartCommand()傳遞給服務(wù)intent,依次插入到工作隊(duì)列中,并逐個發(fā)送給onHandleIntent()
通過onHandleIntent()來依次處理所有Intent請求對象所對應(yīng)的任務(wù)
因此我們通過復(fù)寫方法onHandleIntent(),再在里面根據(jù)Intent的不同進(jìn)行不同的線程操作就可以了