android中應用層的服務級别與activity差不多。service都是運作在背景的服務,那麼它就是不可見的,沒有界面的東西。你可以啟動一個服務Service來播放音樂,或者記錄你地理資訊位置的改變,或者啟動一個服務來運作并一直監聽某種動作。
Service和其他元件一樣,都是運作在主線程中,是以不能用它來做耗時的請求或者動作。你可以在服務中開一一個線程,線上程中做耗時動作。
一.基礎知識
服務一般分為兩種:
1:本地服務, Local Service 用于應用程式内部。在Service可以調用Context.startService()啟動,調用Context.stopService()結束。在内部可以調用Service.stopSelf() 或 Service.stopSelfResult()來自己停止。無論調用了多少次startService(),都隻需調用一次stopService()來停止。
2:遠端服務, Remote Service 用于android系統内部的應用程式之間。可以定義接口并把接口暴露出來,以便其他應用進行操作。用戶端建立到服務對象的連接配接,并通過那個連接配接來調用服務。調用Context.bindService()方法建立連接配接,并啟動,以調用 Context.unbindService()關閉連接配接。多個用戶端可以綁定至同一個服務。如果服務此時還沒有加載,bindService()會先加載它。提供給可被其他應用複用,比如定義一個天氣預報服務,提供與其他應用調用即可。
3、生命周期
context.startService() ->onCreate()- >onStart()->Service running--調用context.stopService() ->onDestroy()
context.bindService()->onCreate()->onBind()->Service running--調用>onUnbind() ->onDestroy()
二.本地服務示範
1、startService的demo
(1)服務端
package com.example.localserver;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class DataService extends Service {
public static final String TAG = "LocalService";
@Override
public void onCreate() {
Log.d(TAG, "onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
}
@Override
public void onStart(Intent intent, int startId) {
Log.d(TAG, "onStart");
super.onStart(intent, startId);
}
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return null;
}
}
(2)用戶端
package com.example.localserver;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity implements OnClickListener {
public static final String TAG = "MainActivity";
private Button mbtn1;
private Button mbtn2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mbtn1 = (Button) findViewById(R.id.start_service);
mbtn2 = (Button) findViewById(R.id.stop_service);
mbtn1.setOnClickListener(this);
mbtn2.setOnClickListener(this);
}
@Override
public void onClick(View v) {
Intent mIntent = new Intent(this, DataService.class);
switch (v.getId()) {
case R.id.start_service:
Log.d(TAG, "click Start Service button");
startService(mIntent);
break;
case R.id.stop_service:
Log.d(TAG, "click Stop Service button");
stopService(mIntent);
break;
default:
break;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
【實驗結果】
06-10 05:56:54.182: D/MainActivity(2084): click Start Service button
06-10 05:56:54.216: D/LocalService(2084): onCreate
06-10 05:56:54.228: D/LocalService(2084): onStartCommand
06-10 05:56:54.228: D/LocalService(2084): onStart
06-10 05:57:08.123: D/MainActivity(2084): click Start Service button
06-10 05:57:08.186: D/LocalService(2084): onStartCommand
06-10 05:57:08.186: D/LocalService(2084): onStart
06-10 05:57:13.865: D/MainActivity(2084): click Stop Service button
06-10 05:57:13.880: D/LocalService(2084): onDestroy
【分析】
startService的特點是activity與service沒有共存亡,當退出activity時,service仍在背景運作,是以,當再次進入activity時,點選開始按鈕,就沒有再使用onCreate方法了,而是直接調用onStartCommand方法。
2、bindService的demo
bindservice實作的關鍵之處,在于 onBind(Intent) 這個方法 傳回了一個實作了 IBinder 接口的對象,這個對象将用于綁定 Activity 與 Service 通信。
【實作方法】
(1)Service中,建立一個 Binder實體,重載onBind(Intent intent)方法,傳回Binder執行個體給Activity,然後執行onCreate()函數。
(2)Activity中,通過private ServiceConnection sc = new ServiceConnection() 建立一個Service連接配接,onServiceConnected()擷取Service執行個體,onServiceDisconnected()釋放連接配接;并通過IBinder接口,調用service中的方法。
(3)Activity中,Intent intent = new Intent("******"); 建構一個service的action,然後bindService(intent, sc, BIND_AUTO_CREATE)綁定服務
【demo】
(1)service端
package com.example.localserver;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class DataService extends Service {
public static final String TAG = "LocalService";
private DataDownloadBinder mBinder = new DataDownloadBinder();
@Override
public void onCreate() {
Log.d(TAG, "onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnbind");
return super.onUnbind(intent);
}
}
package com.example.localserver;
import android.os.Binder;
import android.util.Log;
public class DataDownloadBinder extends Binder{
public static final String TAG = "Binder";
public void startDownload() {
Log.d(TAG, "startDownload() executed");
}
public int add(int a, int b) {
Log.d(TAG, "add() executed");
return a + b;
}
// 執行具體的下載下傳任務
}
(2)clinet端
package com.example.localserver;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity implements OnClickListener {
public static final String TAG = "MainActivity";
private Button mbtn1;
private Button mbtn2;
private Button mbtn3;
private Button mbtn4;
private DataDownloadBinder mbinder;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mbinder = (DataDownloadBinder) service;
mbinder.startDownload();
int sum = mbinder.add(3, 5);
Log.d(TAG, "sum = " + sum);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mbtn1 = (Button) findViewById(R.id.start_service);
mbtn2 = (Button) findViewById(R.id.stop_service);
mbtn3 = (Button) findViewById(R.id.bind_service);
mbtn4 = (Button) findViewById(R.id.unbind_service);
mbtn1.setOnClickListener(this);
mbtn2.setOnClickListener(this);
mbtn3.setOnClickListener(this);
mbtn4.setOnClickListener(this);
}
@Override
public void onClick(View v) {
Intent mIntent = new Intent(this, DataService.class);
switch (v.getId()) {
case R.id.start_service:
Log.d(TAG, "click Start Service button");
startService(mIntent);
break;
case R.id.stop_service:
Log.d(TAG, "click Stop Service button");
stopService(mIntent);
break;
case R.id.bind_service:
bindService(mIntent, mServiceConnection, BIND_AUTO_CREATE);
break;
case R.id.unbind_service:
unbindService(mServiceConnection);
break;
default:
break;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
【實驗結果】
06-10 06:03:27.322: D/MainActivity(2195): click Start Service button
06-10 06:03:27.376: D/LocalService(2195): onCreate
06-10 06:03:27.388: D/LocalService(2195): onStartCommand
06-10 06:03:27.388: D/LocalService(2195): onStart
06-10 06:03:39.088: D/LocalService(2195): onBind
06-10 06:03:39.132: D/Binder(2195): startDownload() executed
06-10 06:03:39.132: D/Binder(2195): add() executed
06-10 06:03:39.132: D/MainActivity(2195): sum = 8
06-10 06:03:52.363: D/LocalService(2195): onUnbind
06-10 06:04:08.229: D/MainActivity(2195): click Start Service button
06-10 06:04:08.243: D/LocalService(2195): onStartCommand
06-10 06:04:08.243: D/LocalService(2195): onStart
06-10 06:04:19.284: D/MainActivity(2195): click Stop Service button
06-10 06:04:19.307: D/LocalService(2195): onDestroy
三、遠端服務示範
需要使用aidl與bindService共同實作遠端服務。
(1)client
package com.example.client;
import com.example.service.ICom;
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.os.RemoteException;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity implements OnClickListener {
private static final String TAG = "Client";
private ICom mICom;
private Button mbtn1;
private Button mbtn2;
private TextView mTV;
private String url;
private boolean isBind = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mbtn1 = (Button) findViewById(R.id.btn_bind);
mbtn2 = (Button) findViewById(R.id.btn_allinfo);
mbtn2.setOnClickListener(this);
mbtn1.setOnClickListener(this);
mTV = (TextView) findViewById(R.id.textView);
}
ServiceConnection mSC = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "onServiceDisconnected...");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "Client onServiceConnected");
mICom = ICom.Stub.asInterface(service);
if (mICom == null) {
Log.d(TAG, "Failed");
} else {
isBind = true;
mbtn1.setText("斷開");
mTV.setText("已連接配接");
try {
url = mICom.getWebSite();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_bind:
if (isBind == false) {
Intent mIntent = new Intent();
mIntent.setAction("com.example.remote");
mIntent.setPackage("com.example.service");
mbtn2.setEnabled(true);
bindService(mIntent, mSC, Context.BIND_AUTO_CREATE);
} else {
mbtn2.setEnabled(false);
mbtn1.setText("連接配接");
isBind = false;
mTV.setText("已斷開連接配接!");
unbindService(mSC);
}
break;
case R.id.btn_allinfo:
mTV.setText(url);
break;
default:
break;
}
}
}
(2)server
package com.example.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class RemoteService extends Service {
private static final String TAG = "Remote Service";
private Com mtest = new Com();
@Override
public void onCreate() {
// TODO Auto-generated method stub
Log.d(TAG, "Oncreate");
super.onCreate();
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
Log.d(TAG, "OnDestroy");
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return mtest;
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnbind");
return super.onUnbind(intent);
}
private class Com extends ICom.Stub {
@Override
public String getWebSite() throws RemoteException {
String url = "www.baidu.com";
return url;
}
}
}
(3)aidl檔案
package com.example.service;
interface ICom{
String getWebSite();
}