1、Service的基本用法
首先看一下如何在項目中定義一個服務,在這個項目中新增一個名爲 MyService 的類,並讓它繼承自 Service。這樣的話一個服務就定義好了。既然是定義一個服務,自然應該在服務中去處理一些事情了,那處理事情的邏輯應該寫在哪裏呢?這時就可以重寫 Service 中的另外一些方法。OnCreate()、onStartCommand()、onDestory()。這三個方法是最常用的方法。其中 onCreate()方法會在服務創建的時候調用,onStartCommand()方法會在每次服務啓動的時候調用,onDestroy()方法會在服務銷燬的時候調用。
通常情況下,如果我們希望服務一旦啓動就立刻去執行某個動作,就可以將邏輯寫在onStartCommand()方法裏。而當服務銷燬時,我們又應該在 onDestroy()方法中去回收那些不再使用的資源。
public class Myservice extends Service {
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
Log.v("msg", "--onBind()--方法被調用");
return null;
}
// onCreate()方法會在服務創建的時候調用
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Log.v("msg", "--onCreate()--方法被調用");
}
//onStartCommand()方法會在每次服務啓動的時候調用
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Log.v("msg", "--onStartCommand()--方法被調用");
return super.onStartCommand(intent, flags, startId);
}
//onDestroy()方法會在服務銷燬的時候調用
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.v("msg", "--onDestroy()--方法被調用");
}
}
另外需要注意,每一個服務都需要在 AndroidManifest.xml文件中進行註冊才能生效。
<service android:name="com.test.testservice.Myservice"></service>
以上操作一個服務就定義好了,接下來去MainActivity中去啓動和停止這個服務
public class MainActivity extends Activity {
private Button btn1;
private Button btn2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1 = (Button) findViewById(R.id.btn_01);
btn2 = (Button) findViewById(R.id.btn_02);
btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//創建一個Intent對象,用來啓動服務
Intent stratIntent = new Intent(MainActivity.this,
Myservice.class);
//啓動服務
startService(stratIntent);
}
});
btn2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//創建一個Intent對象,用來停止服務
Intent stopIntent = new Intent(MainActivity.this,
Myservice.class);
//停止服務
stopService(stopIntent);
}
});
}
}
按鈕的點擊事件裏,我們構建出了一個 Intent 對象,並調用 startService()方法來啓動 MyService 這個服務。在 Stop Serivce 按鈕的點擊事件裏, 我們同樣構建出了一個Intent對象, 並調用stopService()方法來停止MyService這個服務。不用Activity去控制服務,只需要在 MyService 的任何一個位置調用 stopSelf()方法也能讓這個服務停止下來了。
2、服務和活動的基本通信
爲了讓活動和服務之間進行基本的通信,而不是活動發出一個命令之後就不能去控制服務怎麼運行,就需要使用到Service中的onBind()方法。
比如說目前我們希望在 MyService 裏提供一個下載功能,然後在活動中可以決定何時開始下載, 以及隨時查看停止下載。 實現這個功能的思路是創建一個專門的 Binder 對象來對下載功能進行管理
public class Myservice extends Service {
//實例化MyBinder類
private MyBinder myBinder = new MyBinder();
//創建MyBinder類,繼承Binder,在這裏面寫activity要service做的事,例如方法startDownload()和stopDownload()
class MyBinder extends Binder{
public void startDownload() {
// TODO Auto-generated method stub
Log.v("msg", "開始下載!");
}
public void stopDownload() {
// TODO Auto-generated method stub
Log.v("msg", "停止下載!");
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
Log.v("msg", "--onBind()--方法被調用");
//當Activity要控制Service時返回MyBinder實例,否則返回null
return myBinder;
}
// onCreate()方法會在服務創建的時候調用
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Log.v("msg", "--onCreate()--方法被調用");
}
//onStartCommand()方法會在每次服務啓動的時候調用
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Log.v("msg", "--onStartCommand()--方法被調用");
return super.onStartCommand(intent, flags, startId);
}
可以看到,這裏我們新建了一個 DownloadBinder 類,並讓它繼承自 Binder,然後在它的內部提供了開始下載以及查看下載進度的方法。當然這只是兩個模擬方法,並沒有實現真正的功能,我們在這兩個方法中分別打印了一行日誌。接着,在 MyService 中創建了 DownloadBinder 的實例,然後在 onBind()方法裏返回了這個實例,這樣 MyService 中的工作就全部完成了。
public class MainActivity extends Activity {
private Button btn3;
private Button btn4;
private Myservice.MyBinder myBinder;
//創建一個 ServiceConnection 的匿名類,在裏面重寫了onServiceConnected()方法和 onServiceDisconnected()方法
private ServiceConnection connection = new ServiceConnection() {
//當activity和service取消綁定時調用
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
Log.v("msg", "服務斷開連接");
}
//當activity和service成功綁定時調用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
Log.v("msg", "服務連接");
//向下轉型,得到MyBinder實例
myBinder = (MyBinder) service;
//調用MyBinder中的startDownload()方法
myBinder.startDownload();
//調用MyBinder中的stopDownload()方法
myBinder.stopDownload();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn3 = (Button) findViewById(R.id.btn_03);
btn4 = (Button) findViewById(R.id.btn_04);
btn3.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//創建Intent對象,用來綁定Service bindService()方法接收三個參數, 第一個參數就
//是剛剛構建出的 Intent 對象,第二個參數是前面創建出的 ServiceConnection 的實例,第三個
//參數則是一個標誌位,這裏傳入 BIND_AUTO_CREATE 表示在活動和服務進行綁定後自動創建服務
Intent bindIntent = new Intent(MainActivity.this,
Myservice.class);
//綁定service
bindService(bindIntent, connection, BIND_AUTO_CREATE);
}
});
btn4.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//解除Activity和Service的綁定
unbindService(connection);
}
});
}
}
可以看到,這裏我們首先創建了一個 ServiceConnection 的匿名類,在裏面重寫了onServiceConnected()方法和 onServiceDisconnected()方法,這兩個方法分別會在活動與服務成功綁定以及解除綁定的時候調用。在 onServiceConnected()方法中,我們又通過向下轉型得到了 DownloadBinder 的實例,有了這個實例,活動和服務之間的關係就變得非常緊密了。現在我們可以在活動中根據具體的場景來調用
DownloadBinder 中的任何 public 方法,即實現了指揮服務幹什麼,服務就去幹什麼的功能。這裏仍然只是做了個簡單的測試,在onServiceConnected()方法中調用了 DownloadBinder的 startDownload()和 stopDownload()方法。當然,現在活動和服務其實還沒進行綁定呢,這個功能是在 Bind Service 按鈕的點擊事件裏完成的。可以看到,這裏我們仍然是構建出了一個 Intent 對象,然後調用 bindService()方法將 MainActivity
和 MyService 進行綁定。bindService()方法接收三個參數, 第一個參數就是剛剛構建出的 Intent 對象,第二個參數是前面創建出的 ServiceConnection 的實例,第三個參數則是一個標誌位,這裏傳入 BIND_AUTO_CREATE 表示在活動和服務進行綁定後自動創建服務。這會使得 MyService 中的 onCreate()方法得到執行,但 onStartCommand()方法不會執行。然後如果我們想解除活動和服務之間的綁定該怎麼辦呢?調用一下 unbindService()方法就可以了,這也是
Unbind Service 按鈕的點擊事件裏實現的功能。
3、使用前臺服務
前臺服務的使用是爲了防止系統內存不足時,關閉後臺的服務。
前臺服務使用只需要在MyService的方法onCreate()中加入如下代碼即可
//下面代碼是使用前臺服務,防止服務在系統內存不足時被回收
Notification notification = new Notification(R.drawable.ic_launcher,"Notification comes", System. currentTimeMillis());
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,notificationIntent, 0);
notification.setLatestEventInfo(this, "This is title", "This is content", pendingIntent);
startForeground(1, notification);
4、使用IntentService
爲了防止程序在servcie中進行耗時操作,出現AND異常,可以使用IntentService來代替Service,這裏面開啓了子線程,可以用來進行耗時的操作。
public class MyIntentService extends IntentService {
public MyIntentService() {
// TODO Auto-generated constructor stub
super("MyIntentService");
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
protected void onHandleIntent(Intent intent) {
// TODO Auto-generated method stub
//在這裏處理具體的邏輯問題,不用擔心ANR,這是一個子線程,事情做完會自動調用onDestroy()方法
Log.v("msg","Thread id is " + Thread.currentThread().getId());
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.v("msg", "--onDestroy()--方法被調用");
}
}
這裏首先是要提供一個無參的構造函數,並且必須在其內部調用父類的有參構造函數。然後要在子類中去實現 onHandleIntent()這個抽象方法, 在這個方法中可以去處理一些具體的邏輯,而且不用擔心 ANR 的問題,因爲這個方法已經是在子線程中運行的了。這裏爲了證實一下, 我們在 onHandleIntent()方法中打印了當前線程的 id。 另外根據 IntentService 的特性,這個服務在運行結束後應該是會自動停止的,所以我們又重寫了
onDestroy()方法,在這裏也打印了一行日誌,以證實服務是不是停止掉了。
在 AndroidManifest.xml文件中進行註冊才能生效。
<service android:name="com.test.testservice.MyIntentService"></service>
看看MainActivity中的代碼,與Service的使用並沒什麼區別
public class MainActivity extends Activity {
private Button btn5;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn5 = (Button) findViewById(R.id.btn_05);
btn5.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
// 打印主線程的id
Log.v("msg", "Thread id is " + Thread.currentThread().getId());
//創建一個Intent對象
Intent intentService = new Intent(MainActivity.this, MyIntentService.class);
//開啓服務
startService(intentService);
}
});
}
}
以上代碼佈局非常簡單,就不給出
這些乃是作者看《第一行代碼》的筆記。另官方service介紹的鏈接:點擊打開鏈接