編輯:關於Android編程
博客參照< < Android開發全程實錄> >的例子 , 以及其他博客, 希望能給學習Android Service的小伙伴一個比較詳細的解釋與實踐
Service的生命周期比Activity的簡單, 只有3個:
創建服務: onCreate() 啟動服務: onStart() 銷毀服務: onDestroy()其中 onCreate() 和 onDestroy() 只能被調用一次, onStart() 可以被調用多次. 使用start和bind兩種方式啟動Service的生命周期略有不同:
start方式: onCreate() -> onStartCommand() -> onStart() -> onDestroy()
bind方式: onCreate() -> onBind() -> onUnbind() -> onDestroy()
生命周期圖:
兩種啟動方式的注意事項:
代碼測試:
全套的生命周期Log:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;">
public class MyService extends Service {
private final String TAG = this.getClass().getSimpleName();
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind");
return null;
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "onUnbind");
return super.onUnbind(intent);
}
@Override
public void onCreate() {
Log.e(TAG, "onCreate");
super.onCreate();
}
@Override
public void onStart(Intent intent, int startId) {
Log.e(TAG, "onStart");
super.onStart(intent, startId);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy");
super.onDestroy();
}
}
別忘記注冊service:
...
通過Start方式開啟
case R.id.btn_start_service:
Intent intent1 = new Intent(MainActivity.this, MyService.class);
startService(intent1);
break;
case R.id.btn_stop_service:
Intent intent2 = new Intent(MainActivity.this, MyService.class);
stopService(intent2);
break;
service第一次啟動:
onCreate() -> onStartCommand() -> onStart()
再次啟動:
onStartCommand() -> onStart()
關閉Service:
onDestroy()
再次onStart():
onCreate() -> onStartCommand() -> onStart()
通過Bind方式開啟
如果通過bind方式, 除非調用過unbindService(), 否則service的生命周期和context相同, 在context被銷毀時, service自動被銷毀.
使用bind方法要復雜一點, 首先 需要一個 ServiceConnection對象, 當綁定時需要獲得一個連接, 連接可以返回一個 IBinder接口, 可通過 IBinder接口獲取 綁定Service的實例.
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private final String TAG = this.getClass().getSimpleName();
private Button mBtnStartServce;
private Button mBtnStopServce;
private Button mBtnBindServce;
private Button mBtnUnbindServce;
private Button mBtnDoSomeThing;
private boolean isBind;
private MyService mBindService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBtnStartServce = (Button) findViewById(R.id.btn_start_service);
mBtnStopServce = (Button) findViewById(R.id.btn_stop_service);
mBtnBindServce = (Button) findViewById(R.id.btn_bind_service);
mBtnUnbindServce = (Button) findViewById(R.id.btn_unbind_service);
mBtnDoSomeThing = (Button) findViewById(R.id.btn_do_something);
mBtnStartServce.setOnClickListener(this);
mBtnStopServce.setOnClickListener(this);
mBtnBindServce.setOnClickListener(this);
mBtnUnbindServce.setOnClickListener(this);
mBtnDoSomeThing.setOnClickListener(this);
isBind = false;
}
ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e(TAG, "onServiceConnected:" + componentName.toString());
mBindService = ((MyService.MyBinder) iBinder).getService();
isBind = true;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.e(TAG, "onServiceDisconnected");
mBindService = null;
isBind = false;
}
};
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, MyService.class);
switch (view.getId()) {
case R.id.btn_start_service:
startService(intent);
break;
case R.id.btn_stop_service:
stopService(intent);
break;
case R.id.btn_bind_service:
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
isBind = true;
break;
case R.id.btn_unbind_service:
if (isBind) {
unbindService(mServiceConnection);
isBind = false;
mBindService = null;
}
break;
case R.id.btn_do_something:
if(mBindService!=null){
mBindService.doSomeThing();
}
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mServiceConnection);
}
}
MyService.java
public class MyService extends Service {
private final String TAG = this.getClass().getSimpleName();
public class MyBinder extends Binder {
public MyService getService() {
return MyService.this;
}
}
public void doSomeThing() {
Log.e(TAG, "doSomeThing");
}
public MyService() {
Log.e(TAG, "MyService");
}
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind");
return new MyBinder();
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "onUnbind");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy");
super.onDestroy();
}
}
service第一次啟動:
onCreate() -> onBind() -> onServiceConnected()
繼續點擊bind:
無響應
點擊 unbind:
onUnbind() -> onDestroy()
繼續點擊 unbind:
無響應
注意:
ServiceConnection 中的: onServiceDisconnected() 不是在 unBind() 時調用, 而是在Service被異常結束時才調用. 在Activity的 onDestroy() 方法中, 最好加上 unBinderService(), 避免因程序結束沒有接觸servcie綁定拋出異常
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mServiceConnection);
}
AIDL遠程服務
簡介
總之, AIDL是Android中通過Service獲取統一接口, 進行進程間通信的的一種方法
AIDL代碼實例
寫兩個App, 一個作為Server端, 一個作為Client端. 在Server啟動服務, 在Client端綁定Server端的服務, 並獲取數據.
其實AIDL也是用bind方法綁定Service, 與前面不同的就是需要server端和cient端都定義統一的接口, 然後可以從client端得到server端的binder對象, 進而完成進程間通信.
Server端
Server端主要有3個文件修改:
創建aidl文件 創建Service
在manifest中添加 intent-filter
如下圖:
創建AIDL文件, 我這裡使用的是AndroidStudio, 直接在在 package上右鍵即可New AIDL文件.
AIDLService.aidl 文件
package org.xm;
interface AIDLService {
String getServiceName();
}
注意這裡的包名是: org.xm, 而不應該是你創建aidl時點擊的package 的name, 大家自行修改.
創建Service文件
MyService.java
package org.xm.server;
public class MyService extends Service {
private static final String TAG = "MainActivity";
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind");
return binder;
}
private AIDLService.Stub binder = new AIDLService.Stub() {
@Override
public String getServiceName() throws RemoteException {
return "ServiceName";
}
};
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
}
特別注意這裡要返回的binder是 AIDLService.Stub對象, 而不是AIDLService對象.
然後我們在MainActivity啟動時啟動Service, 關閉時關閉Service:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(MainActivity.this, MyService.class);
startService(intent);
}
@Override
protected void onDestroy() {
Intent intent = new Intent(MainActivity.this, MyService.class);
stopService(intent);
super.onDestroy();
}
最後在manifest文件中添加 intent-filter, 來接收請求:
注意:
"org.xm.AIDLService"最好是填寫Service的名稱, 後面bind的時候發送請求需要用到這裡字段, 如果匹配上才能成功綁定.
到這裡Server端就寫完了.
Client端
Client端其實很簡單了:
1. 定義和Server端相同的aidl接口
2. 執行基本的綁定步驟, 創建connection, 然後綁定 service
- AIDLService.aidl 與Server端的完全一致:
package org.xm;
interface AIDLService {
String getServiceName();
}
在MainActivity中寫兩個按鈕, 綁定Service和獲取Service的返回值
package org.xm.client;
//...
import org.xm.AIDLService;
public class MainActivity extends AppCompatActivity {
//...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//...
mBtnBindService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent("org.xm.AIDLService");
intent.setPackage("org.xm.server");
bindService(intent, mConnection, BIND_AUTO_CREATE);
}
});
mBtnGetValue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mAidlService != null) {
try {
Log.e(TAG, "result:" + mAidlService.getServiceName());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnection);
}
private AIDLService mAidlService = null;
ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e(TAG, "onServiceConnected");
mAidlService = AIDLService.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mAidlService = null;
}
};
}
注意:
在綁定的代碼中, 記得使用下面的方法:
Intent intent = new Intent("org.xm.AIDLService");
intent.setPackage("org.xm.server");
bindService(intent, mConnection, BIND_AUTO_CREATE);
1. 這種方法綁定不能成功
Intent intent = new Intent(MainActiity.this, AIDLService.class);
//Intent intent = new Intent(MainActiity.this,AIDLService.Stub.class);
intent.setPackage("org.xm.server");
bindService(intent, mConnection, BIND_AUTO_CREATE);
2. Service Intent must be explicit: Intent ....錯誤
一定要使用
intent.setPackage("org.xm.server");
獲取系統服務
系統自帶的一些服務:
獲取系統服務的方法:
NFC簡介:Near Field Communication 近場通信,是一種數據傳輸技術。與wifi、藍牙、紅外線等數據傳輸技術的一個主要差異就是有效距離一般不能超過4
玩過微信的人都知道,微信有個收藏功能,可以將平時看到的可愛圖片,搞笑視頻收藏起來,網頁文字也是可以收藏的,微信收藏可以刪除嗎?怎麼快速的刪除掉這些內容?最近
最近公司的軟件需要改國際版,需要Facebook和Twitter的登錄和分享。本人先用Umeng的第三方社會化分享實現了該功能,但是後來一想問題來了,經過查證。Umeng
Android的PopupWindow是個很有用的widget,利用它可以實現懸浮窗體的效果,比如實現一個懸浮的菜單,最常見的應用就是在視頻播放界面裡,做一個工具欄,用來