1. service是什么悬垃?及其生命周期祝闻?
在前臺不可見占卧,但是承擔(dān)大部分?jǐn)?shù)據(jù)處理工作(勞模),它和Activity的地位是并列的联喘,區(qū)別在于:Activity運(yùn)行與前臺华蜒,Service運(yùn)行于后臺,沒有圖形用戶界面豁遭,通常他為其他的組件提供后臺服務(wù)或監(jiān)控其他組件的運(yùn)行狀態(tài)叭喜。
service的生命周期:
- onCreate():當(dāng)service第一次被啟動的時候就會調(diào)用此方法
- onStartConnand():當(dāng)service第一次啟動onCreate方法執(zhí)行完畢之后就會調(diào)用此方法,再次進(jìn)入service的時候就會直接進(jìn)入該方法蓖谢,在此方法內(nèi)可以進(jìn)行大量的業(yè)務(wù)邏輯處理
- onDestroy():當(dāng)停止一個service的時候就會調(diào)用此方法
2. Service開啟的方式捂蕴?
- 2.1 startService開啟后Activity和Service就沒有關(guān)系了,即使調(diào)用者activity退出了闪幽,服務(wù)還會長期的在后臺運(yùn)行【不可以調(diào)用服務(wù)里的方法】
startService: onCreate ->onStartCommand
stopService:onDestroy
- 2.2 bindService啥辨,開啟后Activity和Service的生命周期就捆綁在了一起,如果調(diào)用者activity 銷毀了盯腌,服務(wù)也跟著銷毀【間接調(diào)用服務(wù)里的方法】
bindService:onCreate->onBind
unbindService:onUnbind->onDetroy
- 2.3. 混合調(diào)用
需求:既要保證服務(wù)長期在后臺運(yùn)行溉知,又想去調(diào)用服務(wù)里面的方法
技巧:1.先開啟服務(wù) 2.綁定服務(wù)
開啟服務(wù):
startService --> bindService
onCreate -->onStartCommand -->onBind停止服務(wù):
unBindService -- > stopService
onUnbind--> onDestory開啟服務(wù):
bindService --> startService
onCreate -->onBind --> onStartCommand-
停止服務(wù):
unBindService -- > stopService
onUnbind --> onDestory步驟:
2.3.1 開啟服務(wù)(保證服務(wù)的后臺長期運(yùn)行) startService->onCreate() ->onStartCommand;
2.3.2 綁定服務(wù)(獲取中間人,間接的調(diào)用服務(wù)里面的方法) bindService->onBind();
2.3.3 關(guān)閉程序,調(diào)用者退出级乍,服務(wù)被解綁unBinderService()解除綁定服務(wù)舌劳,失去服務(wù)的連接,會調(diào)用onUnbind方法
-
2.3.4 服務(wù)會長期在后臺運(yùn)行 stopService()停止服務(wù)
如果服務(wù)被綁定過了玫荣,直接利用stopService是停不掉的甚淡,必須要顯示的解除綁定服務(wù),服務(wù)才能被停掉捅厂,服務(wù)只能被解除綁定一次贯卦,多次解除綁定服務(wù) 應(yīng)用程序會拋出異常
-
?
?
?
3. Service使用場景舉例?
音樂播放器
- 3.1 播放邏輯寫在Service里面(保證Service長期后臺運(yùn)行)startService
- 3.2 快進(jìn)恒傻、快退脸侥、暫停調(diào)用服務(wù)里面的方法bindService
- 3.3 activity關(guān)閉的時候 不需要調(diào)用服務(wù)的方法了unbindService
- 3.4 關(guān)閉播放器的時候 stopService
4. 開機(jī)自啟Service?
- 4.1 實現(xiàn)一個開機(jī)監(jiān)聽廣播
public class BootBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context,XXXclass);
context.startService(service);
//啟動應(yīng)用,參數(shù)為需要自動啟動的應(yīng)用的包名
Intent intent = getPackageManager().getLaunchIntentForPackage(packageName);
context.startActivity(intent );
}
}
- 4.2 配置廣播接收器的過濾器intent-filter
<receiver android:name="BootBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</receiver>
4.3 添加權(quán)限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
5. 什么是進(jìn)程盈厘,什么是線程睁枕,進(jìn)程分類?
進(jìn)程就是正在進(jìn)行中的程序沸手,它是系統(tǒng)分配資源的基本單位外遇,線程就是一次單一順序的執(zhí)行控制流, 一個進(jìn)程里面可以有多個線程契吉,一般情況下跳仿,一個應(yīng)用程序會對應(yīng)一個進(jìn)程,關(guān)閉應(yīng)用就是關(guān)閉了所有的界面捐晶,關(guān)閉所有的activity菲语,應(yīng)用程序的進(jìn)程是不會關(guān)閉掉的,仍然在后臺長期的運(yùn)行惑灵,當(dāng)系統(tǒng)內(nèi)存不夠用的時候會優(yōu)先關(guān)閉空進(jìn)程和后臺進(jìn)程山上。
采用一組組策略,幫助我們自動的管理進(jìn)程英支,進(jìn)程按照優(yōu)先級分為不同的等級:
- 5.1 前臺進(jìn)程 用戶可以看到這個進(jìn)程里的某一個activity界面佩憾,可以操作這個界面
- 5.2 可見進(jìn)程 用戶仍然可以看到這個進(jìn)程的某個activity,但是不可以操作這個界面
- 5.3 服務(wù)進(jìn)程 如果一個應(yīng)用程序有一個服務(wù)在后臺運(yùn)行
- 5.4 后臺進(jìn)程 沒有任何的服務(wù)進(jìn)程干花,打開一個activity后妄帘,按了home鍵婶恼,最小化了
- 5.5 空進(jìn)程 沒有任何活動組件存在的進(jìn)程
6.簡述通過Binder調(diào)用服務(wù)流程眷篇?
6.1 客戶端調(diào)用服務(wù)代理方法開始【方法調(diào)用】
6.2 服務(wù)代理方法準(zhǔn)備方法參數(shù)數(shù)據(jù)包和方法執(zhí)行結(jié)果數(shù)據(jù)包【準(zhǔn)備數(shù)據(jù)】
6.3 客戶端調(diào)用binder驅(qū)動層的binder對象的transact方法進(jìn)行數(shù)據(jù)傳遞【數(shù)據(jù)傳遞】
6.4 服務(wù)端binder對象的onTransact方法開啟響應(yīng)并進(jìn)行事件分發(fā)處理【事件分發(fā)】
6.5 服務(wù)端讀取方法參數(shù)數(shù)據(jù)包并調(diào)用真正的服務(wù)方法【數(shù)據(jù)處理】
6.6 服務(wù)端服務(wù)方法執(zhí)行完畢將執(zhí)行結(jié)果寫入結(jié)果數(shù)據(jù)包并且返回【返回結(jié)果】
6.7 Binde驅(qū)動層的binder接受返回執(zhí)行結(jié)果并且繼續(xù)向客戶端返回【繼續(xù)返回】
-
6.8 客戶端接收處理結(jié)果數(shù)據(jù)【接收數(shù)據(jù)】
?
7.創(chuàng)建綁定服務(wù)都有那幾種方式?
- 7.1 擴(kuò)展 Binder 類:客戶端和服務(wù)端在同一個應(yīng)用,同一個進(jìn)程
- 7.2 使用 Messenger:這是跨進(jìn)程通信的最簡單方法丰辣,方法調(diào)用需要排隊
- 7.3 使用 AIDL:如果同時要執(zhí)行服務(wù)端的多個方法杖玲,則采用aidl的方法
8.通過擴(kuò)展binder實現(xiàn)本地服務(wù)調(diào)用?
9.利用Messanger進(jìn)行跨進(jìn)程通信流程乓搬?
Messenger封裝了Binder和Handler江掩,有了Handler,Messenger就可以發(fā)送消息了统抬,有了Binder,Messanger就可以遠(yuǎn)程通信了
- 9.1 服務(wù)端利用Handler創(chuàng)建一個服務(wù)端的Messenger【創(chuàng)建服務(wù)端信使】
- 9.2 客戶端利用服務(wù)端返回的Binder構(gòu)造一個服務(wù)端的Messenger【接受服務(wù)端信使】
- 9.3 客戶端利用Handler創(chuàng)建一個客戶端的Messenger【創(chuàng)建客戶端信使】
- 9.4 客戶端利用拿到服務(wù)端信使給服務(wù)端發(fā)送消息攜帶上客戶端信使【把客戶端信使發(fā)送給服務(wù)端】
- 9.5 服務(wù)端接受消息就拿到客戶端信使【接受客務(wù)端信使】
結(jié)果:客戶端拿到了服務(wù)端的信使【使用binder構(gòu)造】蓄喇,服務(wù)端拿到了客戶端信使【使用消息攜帶】发侵,然后就可以互發(fā)信息了
服務(wù)端:
public class MyService extends Service {
private Messenger mServidceMessenger;// 服務(wù)端消息信使
private Messenger mClientMessenger;// 客戶端消息信使
private Handler mServideHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
mClientMessenger = msg.replyTo;
break;
}
super.handleMessage(msg);
}
};
@Override
public void onCreate() {
mServidceMessenger = new Messenger(mServideHandler);
}
@Override
public IBinder onBind(Intent intent) {
return mServidceMessenger.getBinder();
}
}
客戶端:
pubblic class MainActivity extends Activity{
private Messenger mServidceMessenger;// 服務(wù)端消息信使
private Messenger mClientMessenger;// 客戶端消息信使
@Override
public void onCreate(Bundle bundle){
bindService(mService, new MyServiceConnection(), Context.BIND_AUTO_CREATE);
}
class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mServiceMessenger = new Messenger(iBinder);
mClientMessenger = new Messenger(mClientHandler);
Message msg = Message.obtain();
msg.replyTo = mClientMessenger;
msg.what = 0;
mServiceMessenger.send(msg);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
}
private Handler mClientHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
}
10. AIDL架構(gòu)分析?
?
?
11. AIDL跨進(jìn)程服務(wù)調(diào)用工作原理妆偏?AIDL實現(xiàn)的步驟刃鳄?
客戶端和服務(wù)端通信協(xié)議解決了兩個問題,服務(wù)端和客戶端約定了方法參數(shù)列表順序;約定了方法的ID標(biāo)識
服務(wù)端:
- 繼承Service創(chuàng)建服務(wù)子類
- 定義服務(wù)所對外提供的服務(wù)接口(跨進(jìn)程服務(wù)則需要創(chuàng)建aidl接口钱骂,創(chuàng)aidl實體)
- 繼承Binder建立中間人對象并且實現(xiàn)服務(wù)接口
- 通過onBinder回調(diào)方法返回中間人對象
- 在清單文件里面發(fā)布服務(wù)
客戶端:
創(chuàng)建一個隱式意圖Intent
繼承ServiceConnection創(chuàng)建一個服務(wù)連接對象conn
通過bindService綁定服務(wù)
在bindService的回調(diào)方法onServiceConnectioned里獲取服務(wù)端的中間人對象
-
通過中間人對象調(diào)用服務(wù)里面的方法
具體流程:
11.1 創(chuàng)建接口服務(wù)
IMyService.aidl
package com.ryg.sayhi.aidl;
import com.ryg.sayhi.aidl.Student;
interface IMyService {
List < Student > getStudent();
void addStudent(in Student student);
}
- 11.2 創(chuàng)建一個AIDL實體
Student.aidl
package com.ryg.sayhi.aidl;
parcelable Student;
- 11.3 創(chuàng)建一個Parcelable實體
Student.java
package com.ryg.sayhi.aidl;
public final class Student implements Parcelable {
public int sno;
public String name;
public Student() {}
}
- 11.4 創(chuàng)建服務(wù)端service
public class MyService extends Service{
private final IMyService.Stub mBinder = new IMyService.Stub() {
@Override
public List < Student > getStudent()throws RemoteException {}
@Override
public void addStudent(Student student)throws RemoteException {}
//在這里可以做權(quán)限認(rèn)證叔锐,return false意味著客戶端的調(diào)用就會失敗,比如下面见秽,只允許包名為com.example.test的客戶端通過愉烙,
//其他apk將無法完成調(diào)用過程
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
String packageName = null;
String[]packages = MyService.this.getPackageManager().
getPackagesForUid(getCallingUid());
if (packages != null && packages.length > 0) {
packageName = packages[0];
}
Log.d(TAG, "onTransact: " + packageName);
if (!PACKAGE_SAYHI.equals("com.example.test")) {
return false;
}
return super.onTransact(code, data, reply, flags);
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
- 11.5 在AndroidMenifest中聲明service
<service
android : name = "com.ryg.sayhi.MyService"
android : process = ":remote"
android : exported = "true" >
< intent - filter >
< category android : name = "android.intent.category.DEFAULT" / >
< action android : name = "com.ryg.sayhi.MyService" / >
< / intent - filter >
< / service >
- 11.6 創(chuàng)建客戶端
import com.ryg.sayhi.aidl.IMyService;
import com.ryg.sayhi.aidl.Student;
public class MainActivity extends Activity implements OnClickListener {
private IMyService mIMyService;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mIMyService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIMyService = IMyService.Stub.asInterface(service);
}
};
@ Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService(intentService, mServiceConnection, BIND_AUTO_CREATE);
}
}import com.ryg.sayhi.aidl.IMyService;
import com.ryg.sayhi.aidl.Student;
public class MainActivity extends Activity implements OnClickListener {
private IMyService mIMyService;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mIMyService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIMyService = IMyService.Stub.asInterface(service);
}
};
@ Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService(intentService, mServiceConnection, BIND_AUTO_CREATE);
}
}
12. AIDL 使用注意事項?
- 12.1 建立aidl實體時必須在aidl文件夾,對應(yīng)的java文件在對應(yīng)的java文件夾
- 12.2 建立aidl實體時解取,需要聲明該文件所在的包
- 12.3 建立實體是使用parcelable關(guān)鍵字
- 12.4 建立的實體必須實現(xiàn)Parcelable接口
- 12.5 aidl實體和其對應(yīng)的java實體所在的包名必須保持一直
- 12.6 建立aidl接口時步责,如果用到了復(fù)合類型的數(shù)據(jù)需要在aidl接口中導(dǎo)入,導(dǎo)入的是aidl文件禀苦,而不是java文件
- 12.7 建立的aidl接口時蔓肯,interface前不能有任何修飾符,方法名前不能有任何的修飾符
- 12.8 建立aidl接口的方法時如果有參數(shù)則執(zhí)行參數(shù)的類型為in
- 12.9 aidl接口振乏,基本類型蔗包、String、List慧邮、Map调限、CharSequence類型之外舟陆,其他類型都要導(dǎo)入包,即使他們在同一包里面也需要導(dǎo)包
- 12.10 如果調(diào)用本地服務(wù)則是顯示意圖耻矮,如果調(diào)用遠(yuǎn)程服務(wù)則用隱式意圖
- 12.11 獲取遠(yuǎn)程服務(wù)的中間人對象是用stub.asInterface方法
13.如何保證Service長期存活
- 13.1 通過推送服務(wù)保持存活
- 13.2 將Service運(yùn)行于另外一個進(jìn)程當(dāng)中 (android:process=":remote" )
- 13.3 在onStartCommand方法返回start_sticky秦躯,同時在onDestroy方法中進(jìn)行重啟服務(wù)【kill掉的話會自動重啟】
- 13.4 把Service所在的App提升至系統(tǒng)應(yīng)用級別(android:persistent=”true”)
- 13.5 為Service建立一個守護(hù)服務(wù)
- 13.6 通過監(jiān)聽系統(tǒng)廣播來喚醒服務(wù)
總結(jié):
1,6簡單粗暴可以保證完全存活
4淘钟,5常用的方案
2宦赠,3比較輕量級
將Service設(shè)置為前臺服務(wù):(startForeground(int, Notification))
編碼通過雙服務(wù)實現(xiàn)服務(wù)長存?
https://www.cnblogs.com/zhujiabin/p/6073529.html
- 1.在AndroidMnifest.xml進(jìn)行配置米母?
<service android:name="ServiceOne" android:process=":remote">
<intent-filter>
<action android:name="com.example.servicedemo.ServiceOne"/>
</intent-filter>
</service>
<service android:name="ServiceTwo" android:process=":remote">
<intent-filter>
<action android:name="com.example.servicedemo.ServiceTwo"/>
</intent-filter>
</service>
- 2.activit中啟動服務(wù)
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent serviceOne = new Intent();
serviceOne.setClass(MainActivity.this, ServiceOne.class);
startService(serviceOne);
Intent serviceTwo = new Intent();
serviceTwo.setClass(MainActivity.this, ServiceTwo.class);
startService(serviceTwo);
}
public static boolean isServiceWorked(Context context, String serviceName) {
ActivityManager myManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ArrayList<RunningServiceInfo> runningService = (ArrayList<RunningServiceInfo>) myManager.getRunningServices(Integer.MAX_VALUE);
for (int i = 0; i < runningService.size(); i++) {
if (runningService.get(i).service.getClassName().toString().equals(serviceName)) {
return true;
}
}
return false;
}
}
- 3.創(chuàng)建服務(wù)1
public class ServiceOne extends Service {
public final static String TAG = "com.example.servicedemo.ServiceOne";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
thread.start();
return START_STICKY;
}
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
Log.e(TAG, "ServiceOne Run: "+System.currentTimeMillis());
boolean b = MainActivity.isServiceWorked(ServiceOne.this, "com.example.servicedemo.ServiceTwo");
if(!b) {
Intent service = new Intent(ServiceOne.this, ServiceTwo.class);
startService(service);
Log.e(TAG, "Start ServiceTwo");
}
}
};
timer.schedule(task, 0, 1000);
}
});
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
- 4.創(chuàng)建服務(wù)2
public class ServiceTwo extends Service {
public final static String TAG = "com.example.servicedemo.ServiceTwo";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
thread.start();
return START_REDELIVER_INTENT;
}
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
Log.e(TAG, "ServiceTwo Run: " + System.currentTimeMillis());
boolean b = MainActivity.isServiceWorked(ServiceTwo.this, "com.example.servicedemo.ServiceOne");
if(!b) {
Intent service = new Intent(ServiceTwo.this, ServiceOne.class);
startService(service);
}
}
};
timer.schedule(task, 0, 1000);
}
});
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}