1.創(chuàng)建一個(gè)簡(jiǎn)單的服務(wù)
1.創(chuàng)建一個(gè)類,繼承自service
public class SimpleService extends Service {
public SimpleService() {
}
@Override
public void onCreate() {
super.onCreate();
Log.v("myApp", "SimpleService onCreate");
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.v("myApp", "SimpleService onDestroy");
}
}
2.在Manifest中只需要注冊(cè)service類就可以了
<service
android:name=".SimpleService"
android:enabled="true"
android:exported="true" />
3.在activity中啟動(dòng)或者停止服務(wù)
private void initButton1() {
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SimpleService.class);
startService(intent);
}
});
}
private void initButton2() {
Button button2 = (Button) findViewById(R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SimpleService.class);
stopService(intent);
}
});
}
2.服務(wù)和子線程的區(qū)別
1.線程是需要依賴app進(jìn)程而存在的,如果app進(jìn)程被殺死了,那么線程的內(nèi)存也就被回收了,線程也會(huì)死
2.服務(wù)咋愛(ài)殺死app的時(shí)候也會(huì)被殺死,但是之后會(huì)重新啟動(dòng)
1.現(xiàn)象:同樣應(yīng)用程序被關(guān)閉了 線程同時(shí)被殺死 如果是服務(wù)(先被殺死 然后重新啟動(dòng))
2.本質(zhì):服務(wù)是一個(gè)安卓組件 (先被殺死 然后重新啟動(dòng)):
系統(tǒng)認(rèn)為服務(wù)之所以被殺死 是因?yàn)楫?dāng)前應(yīng)用的進(jìn)程被殺死 可能是因?yàn)閮?nèi)存不足而造成 它會(huì)重新啟動(dòng)服務(wù)
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(){
@Override
public void run() {
super.run();
while (true) {
SystemClock.sleep(3000);
Log.v("myApp", "線程還在運(yùn)行中...");
}
}
}.start();
}
public class SimpleService extends Service {
int i = 0;
public SimpleService() {
}
@Override
public void onCreate() {
super.onCreate();
new Timer().schedule(new TimerTask() {
@Override
public void run() {
i = i + 1;
Log.v("myApp", "服務(wù)還在進(jìn)行著...." + i);
}
}, 2000, 3000);
}
}
3.接收開(kāi)機(jī)廣播,開(kāi)啟監(jiān)聽(tīng)手機(jī)服務(wù)
1.注冊(cè)接收系統(tǒng)開(kāi)機(jī)廣播的接收者
<receiver
android:name=".BootReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
2.接收到廣播的時(shí)候,開(kāi)啟監(jiān)聽(tīng)服務(wù)
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent(context, CallService.class);
context.startService(serviceIntent);
}
}
3.服務(wù)開(kāi)始監(jiān)聽(tīng)手機(jī)通話并錄音
public class CallService extends Service {
private MediaRecorder mRecorder;
public CallService() {
}
@Override
public void onCreate() {
super.onCreate();
Log.v("myApp", "開(kāi)機(jī)啟動(dòng)監(jiān)聽(tīng)服務(wù)");
final TelephonyManager manager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
manager.listen(new PhoneStateListener() {
private String mIncomingNumber="";
private boolean mIsRecording;
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (manager.getCallState()) {
case TelephonyManager.CALL_STATE_IDLE:
Log.v("myApp", "休閑(沒(méi)有電話)/掛斷:" + incomingNumber);
if (mRecorder!=null&&mIsRecording) {
mRecorder.stop();
mRecorder.release();
mRecorder = null;
mIsRecording=false;
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.v("myApp", "接通 :" + incomingNumber);
//MediaRecorder 錄音
mRecorder = new MediaRecorder();
//設(shè)置音頻的來(lái)源 MIC DEFAULT開(kāi)發(fā)的時(shí)候
//真實(shí)打電話 VOICE_DOWNLINK/VOICE_UPLINK
//VOICE_CALL既能聽(tīng)到自己的聲音 也能聽(tīng)到別人的聲音
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//錄音之后要形成一個(gè)音頻文件 音頻的后綴是 .3gp .mp3 .mp4
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
//設(shè)置錄音的文件保存到什么地方
mRecorder.setOutputFile(getRecordFilePath(mIncomingNumber));
//設(shè)置音頻內(nèi)部解碼
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
mRecorder.prepare();
} catch (IOException e) {
}
mRecorder.start();
mIsRecording=true;
break;
case TelephonyManager.CALL_STATE_RINGING:
Log.v("myApp", "來(lái)電:" + incomingNumber);
mIncomingNumber=incomingNumber;
break;
}
}
}, 1);
}
/**
* 獲取文件的路徑
*/
private String getRecordFilePath(String phone){
//文件名的格式 電話號(hào)碼+"#"時(shí)間+".3gp"
SimpleDateFormat formatter=new SimpleDateFormat("yy-MM-dd hh:mm");
String fileName=phone+"#"+formatter.format(new Date())+".3gp";
File file=new File(getFilesDir(),fileName);
return file.getAbsolutePath();
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
4.動(dòng)態(tài)注冊(cè)廣播接收者,監(jiān)聽(tīng)開(kāi)屏和鎖屏
動(dòng)態(tài)注冊(cè)鎖屏開(kāi)屏的廣播接收者
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ScreenReceiver screenReceiver = new ScreenReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
intentFilter.addAction(Intent.ACTION_USER_PRESENT);
registerReceiver(screenReceiver, intentFilter);
}
}
public class ScreenReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
Log.v("myApp", "000");
if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {
Log.v("myApp", "開(kāi)屏");
} else if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())){
Log.v("myApp", "鎖屏");
}
}
}
5.進(jìn)程等級(jí)
Android系統(tǒng)會(huì)盡量的長(zhǎng)期保存每一個(gè)進(jìn)程不被回收。
- 這樣 第二次開(kāi)啟界面后就會(huì)發(fā)現(xiàn)啟動(dòng)速度比以前快了 這是因?yàn)橄到y(tǒng)已經(jīng)創(chuàng)建了一個(gè)進(jìn)程 沒(méi)有被殺死 這次啟動(dòng)就不用再重新創(chuàng)建。
- 但是 當(dāng)內(nèi)存不足的時(shí)候 系統(tǒng)就要?dú)⒌粢恍├系倪M(jìn)程 就要考慮殺進(jìn)程的策略了。
系統(tǒng)定義了進(jìn)程的優(yōu)先級(jí)
1.Foreground progress 前臺(tái)進(jìn)程
用戶在操作的應(yīng)用程序所在的進(jìn)程是前臺(tái)進(jìn)程
2.Visible progress 可見(jiàn)進(jìn)程
用戶仍然可以看到界面 但是里面的按鈕點(diǎn)擊不了了
3.Service progress 服務(wù)進(jìn)程
進(jìn)程里面有一個(gè)服務(wù)處于運(yùn)行的狀態(tài)
4.Background progress 后臺(tái)進(jìn)程
如果一個(gè)應(yīng)用程序沒(méi)有服務(wù)處于運(yùn)行狀態(tài) 界面最小化
5.Empty progress 空進(jìn)程
應(yīng)用程序沒(méi)有任何活動(dòng)的組件(界面或者服務(wù))
6.使用綁定服務(wù)的方式和service進(jìn)行通信
原因:因?yàn)樵赼ctivity中啟動(dòng)服務(wù)時(shí),是系統(tǒng)利用反射的方式將service實(shí)例化之后啟動(dòng)的,所以如果在activity中需要和service進(jìn)行交互,那么是得不到service的實(shí)例的。這樣的情況下就有了onBindService綁定服務(wù)。綁定服務(wù)會(huì)在service中創(chuàng)建一個(gè)類似管家是內(nèi)部類在activity綁定service的時(shí)候,返回給activity使用,用來(lái)和service進(jìn)行通訊。
public class MainActivity extends AppCompatActivity {
private MyService.MyBinder myBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initButtonStartService();
initButtonConnService();
}
private void initButtonStartService() {
Button button = (Button) findViewById(R.id.button_startService);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, MyService.class);
bindService(intent, new ServiceConnection() {
// 綁定成功之后,回調(diào)的方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (MyService.MyBinder) service;
}
// 解綁成功之后,回調(diào)的方法
@Override
public void onServiceDisconnected(ComponentName name) {
}
}, BIND_AUTO_CREATE);
}
});
}
private void initButtonConnService() {
Button button = (Button) findViewById(R.id.button_connService);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myBinder.showToast();
}
});
}
}
public class MyService extends Service {
public MyService() {
}
@Override
public void onCreate() {
super.onCreate();
Log.v("myApp", "服務(wù)創(chuàng)建");
}
// 服務(wù)開(kāi)啟
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("myApp", "服務(wù)開(kāi)始");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.v("myApp", "服務(wù)銷毀");
}
// 進(jìn)行外部通訊的內(nèi)部類
public class MyBinder extends Binder{
public void showToast(){
// 這里可以調(diào)用服務(wù)的方法,實(shí)現(xiàn)和服務(wù)的交互和通訊
MyService.this.showToast();
}
}
// 服務(wù)綁定
@Override
public IBinder onBind(Intent intent) {
Log.v("myApp", "服務(wù)綁定");
return new MyBinder();
}
private void showToast() {
Toast.makeText(MyService.this, "調(diào)用了服務(wù)里的方法", Toast.LENGTH_SHORT).show();
}
}
使用代理來(lái)進(jìn)行限制
上面這樣寫其實(shí)是不規(guī)范的,因?yàn)镸yBinder這個(gè)類中還可以偷偷實(shí)現(xiàn)其他的方法供外部調(diào)用,而無(wú)法規(guī)范MyBinder的行為,這種情況下就需要使用到接口來(lái)限制MyBinder的權(quán)限,讓外部的activity不能隨意調(diào)用MyBinder中的方法。
這樣將MyBinder這個(gè)內(nèi)部類私有化,讓外部調(diào)用時(shí)只能通過(guò)接口來(lái)調(diào)用方法,起到了對(duì)外部的限制
public class MainActivity extends AppCompatActivity {
private IMyService myBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initButtonStartService();
initButtonConnService();
}
private void initButtonStartService() {
Button button = (Button) findViewById(R.id.button_startService);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.v("myApp", "點(diǎn)擊開(kāi)始綁定按鈕");
Intent intent = new Intent(MainActivity.this, MyService.class);
bindService(intent, new ServiceConnection() {
// 綁定成功之后,回調(diào)的方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (IMyService) service;
}
// 解綁成功之后,回調(diào)的方法
@Override
public void onServiceDisconnected(ComponentName name) {
}
}, BIND_AUTO_CREATE);
}
});
}
private void initButtonConnService() {
Button button = (Button) findViewById(R.id.button_connService);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myBinder.callShowToast();
}
});
}
}
// 用來(lái)限制MyService中MyBinder的協(xié)議
public interface IMyService {
void callShowToast();
}
public class MyService extends Service {
public MyService() {
}
@Override
public void onCreate() {
super.onCreate();
Log.v("myApp", "服務(wù)創(chuàng)建");
}
// 服務(wù)開(kāi)啟
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("myApp", "服務(wù)開(kāi)始");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.v("myApp", "服務(wù)銷毀");
}
// 進(jìn)行外部通訊的內(nèi)部類
private class MyBinder extends Binder implements IMyService {
@Override
public void callShowToast() {
// 這里可以調(diào)用服務(wù)的方法,實(shí)現(xiàn)和服務(wù)的交互和通訊
MyService.this.showToast();
}
}
// 服務(wù)綁定
@Override
public IBinder onBind(Intent intent) {
Log.v("myApp", "服務(wù)綁定");
return new MyBinder();
}
private void showToast() {
Toast.makeText(MyService.this, "調(diào)用了服務(wù)里的方法", Toast.LENGTH_SHORT).show();
}
}
7.service的生命周期
public class MyService extends Service {
@Override
public void onCreate() {
super.onCreate();
Log.v("myApp", "MyService onCreate在服務(wù)創(chuàng)建的時(shí)候調(diào)用");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("myApp", "MyService onStartCommand在服務(wù)開(kāi)啟的時(shí)候調(diào)用");
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
@Override
public void onDestroy() {
super.onDestroy();
Log.v("myApp", "MyService onDestroy在服務(wù)銷毀的時(shí)候調(diào)用");
}
@Override
public boolean onUnbind(Intent intent) {
Log.v("myApp", "服務(wù)解綁");
return super.onUnbind(intent);
}
}
生命周期方法就這幾個(gè),但是在startService和bindService這兩種模式下,調(diào)用的方法還是不一樣的
在startService時(shí),調(diào)用的是onCreate,onStartCommand,onDestroy
在bindService時(shí),調(diào)用的是onCreate,onBind,onUnbind,onDestroy
服務(wù)有兩個(gè)特性,
1.后臺(tái)一直運(yùn)行 2.沒(méi)有界面,能夠與界面交互
startService:后臺(tái)一直運(yùn)行,但是不能與界面交互
bindService:當(dāng)啟動(dòng)服務(wù)的組件被銷毀時(shí),服務(wù)也跟著銷毀,能夠與界面交互
所以在項(xiàng)目中,我們會(huì)將兩種方式一起使用,先startService來(lái)啟動(dòng)服務(wù),這種啟動(dòng)方式下只要不是stopService,service是不會(huì)停止的,然后使用bindService來(lái)綁定服務(wù),實(shí)現(xiàn)service與界面的交互,當(dāng)不需要交互時(shí)可以調(diào)用unBindService來(lái)解除綁定,但是服務(wù)還是存活的,如果連service都不需要了,那么調(diào)用stopService,服務(wù)就會(huì)被銷毀了
8.遠(yuǎn)程服務(wù)創(chuàng)建和aidl使用
舉例:淘寶下單,調(diào)用支付寶的支付功能
1.創(chuàng)建支付service并且注冊(cè)對(duì)應(yīng)的action,淘寶啟動(dòng)service的時(shí)候需要根據(jù)action android:name來(lái)進(jìn)行過(guò)濾
<service
android:name=".AlipayService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.mazhan.alipay.action.SAFEPAY"/>
</intent-filter>
</service>
public class AlipayService extends Service {
public AlipayService() {
}
@Override
public IBinder onBind(Intent intent) {
return new MyAlipayAgent();
}
int callSafePay(String account, String pwd, String payPwd, double price) {
if (!payPwd.equals("123")) {
return 2;
}
if (price > 1000) {
return 3;
}
return 1;
}
class MyAlipayAgent extends IAlipayService.Stub {
@Override
public int callSafePay(String account, String pwd, String payPwd, double price) throws RemoteException {
return AlipayService.this.callSafePay(account, pwd, payPwd, price);
}
}
}
這里在本地調(diào)用的時(shí)候MyAlipayAgent繼承的是Binder并且實(shí)現(xiàn)IAlipayService接口,這里使用的是aidl文件,創(chuàng)建IAlipayService的aidl文件,然后 build->clean project,就會(huì)自動(dòng)生成IAlipayService.java文件,在其中有一個(gè)內(nèi)部類Stub已經(jīng)繼承了android.os.Binder 并且實(shí)現(xiàn)了com.mazhan.alipayservice接口,所以我們的代理MyAlipayAgent 只需要繼承IAlipayService.Stub就可以了
public static abstract class Stub extends android.os.Binder implements com.mazhan.alipayservice.IAlipayService
IAlipayService的aidl文件
package com.mazhan.alipayservice;
interface IAlipayService {
/*
* 返回值:1,支付成功,2,賬號(hào)錯(cuò)誤或密碼錯(cuò)誤,3,余額不足
*
* */
int callSafePay(String account, String pwd, String payPwd, double price);
}
*在淘寶項(xiàng)目中,下單時(shí)調(diào)用IAlipayService 接口,那么就需要將IAlipayService.aidl文件拷貝到淘寶項(xiàng)目中,然后生成IAlipayService.java,這樣就可以調(diào)用IAlipayService 接口中的方法了
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button_pay);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("com.mazhan.alipay.action.SAFEPAY");
intent.setPackage("com.mazhan.alipayservice");
startService(intent);
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IAlipayService iAlipayService = IAlipayService.Stub.asInterface(service);
try {
int i = iAlipayService.callSafePay("zhangsan", "123", "123", 100);
switch (i) {
case 1 :
Toast.makeText(MainActivity.this, "支付成功", Toast.LENGTH_SHORT).show();
break;
case 2 :
Toast.makeText(MainActivity.this, "支付密碼錯(cuò)誤", Toast.LENGTH_SHORT).show();
break;
case 3 :
Toast.makeText(MainActivity.this, "余額不足", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}, BIND_AUTO_CREATE);
}
});
}
}
注意點(diǎn)
1.在淘寶項(xiàng)目中復(fù)制aidl文件時(shí),需要連包名一起復(fù)制

2.在淘寶的mainActivity中,啟動(dòng)支付寶的service時(shí),在安卓5.0之后隱式啟動(dòng)時(shí),需要設(shè)置包名

3.在IAlipayService.Stub中提供了將IBinder轉(zhuǎn)換為IAlipayService的方法
IAlipayService iAlipayService = IAlipayService.Stub.asInterface(service);