## 第六天.AndroidService ##
### 6.1Service概述 ###
#### 6.1.1 Service概念及用途 ####
服務是運行在后臺的一段代碼。
不是進程,也不是線程。
可以運行在它自己的進程,也可以運行在其他應用程序進程的上下文(context)里面,這取決于自身的需要。
Android中的服務,它與Activity不同,它是不能與用戶交互的,不能自己啟動的,運行在后臺的程序。
媒體播放器的服務,當用戶退出媒體選擇用戶界面,仍然希望音樂依然可以繼續播放,這就是由服務(service)來保證當用戶界面關閉時音樂繼續播放的。
比如當我們一個應用的數據是通過網絡獲取的,不同時間的數據是不同的,這時候我們可以用Service在后臺定時更新,而不用每打開應用的時候在去獲取。
### 6.2 Service生命周期 ####
+ onCreate()
在服務被創建時調用,該方法只會被調用一次,無論調用多少次startService()或bindService()方法,服務也只被創建一次。
+ onStart()
只有采用Context.startService()方法啟動服務時才會回調該方法。該方法在服務開始運行時被調用。多次調用startService()方法盡管不會多次創建服務,但onStart() 方法會被多次調用。
+ onDestroy()
服務被終止時調用。
+ onBind()
只有采用Context.bindService()方法啟動服務時才會回調該方法。該方法在調用者與服務綁定時被調用,當調用者與服務已經綁定,多次調用Context.bindService()方法并不會導致該方法被多次調用。
+ onUnbind()
只有采用Context.bindService()方法啟動服務時才會回調該方法。該方法在調用者與服務解除綁定時被調用。
startService后,即使調用startService的進程結束了Service仍然還存在,直到有進程調用stopService,或者Service自己自殺(stopSelf())。
bindService后,Service就和調用bindService的進程同生共死了,也就是說當調用bindService的進程死了,那么它bind的Service也要跟著被結束,當然期間也可以調用unbindservice讓Service結束。
兩種方式混合使用時,比如說你startService了,我bindService了,那么只有你stopService了而且我也unbindservice了,這個Service才會被結束。
### 6.3啟動與停止Service ###
#### 6.3.1 Service開發步驟 ####
第一步:繼承Service類
```
public class MyService extends Service {
}
```
第二步:在AndroidManifest.xml文件中的節點里對服務進行配置:
服務不能自己運行,使用startService()方法啟用服務,調用者與服務之間沒有關連,即使調用者退出了,服務仍然運行。使用bindService()方法啟用服務,調用者與服務綁定在了一起,調用者一旦退出,服務也就終止,大有“不求同時生,必須同時死”的特點。
如果打算采用Context.startService()方法啟動服務,在服務未被創建時,系統會先調用服務的onCreate()方法,接著調用onStart()方法。如果調用startService()方法前服務已經被創建,多次調用startService()方法并不會導致多次創建服務,但會導致多次調用onStart()方法。采用startService()方法啟動的服務,只能調用Context.stopService()方法結束服務,服務結束時會調用onDestroy()方法。
如果打算采用Context.bindService()方法啟動服務,在服務未被創建時,系統會先調用服務的onCreate()方法,接著調用onBind()方法。這個時候調用者和服務綁定在一起,調用者退出了,系統就會先調用服務的onUnbind()方法,接著調用onDestroy()方法。如果調用bindService()方法前服務已經被綁定,多次調用bindService()方法并不會導致多次創建服務及綁定(也就是說onCreate()和onBind()方法并不會被多次調用)。如果調用者希望與正在綁定的服務解除綁定,可以調用unbindService()方法,調用該方法也會導致系統調用服務的onUnbind()-->onDestroy()方法。
#### 6.3.2 采用startService()啟動服務 ####
采用Context.startService()方法啟動服務的代碼如下:
```
public class HelloActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
......
Button button =(Button) this.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
Intent intent = new Intent(HelloActivity.this, SMSService.class);
startService(intent);
}});
}
}
```
#### 6.3.3 采用bindService()啟動服務 ####
采用Context.startService()方法啟動服務的代碼如下:
```
public class HelloActivity extends Activity {
ServiceConnection conn = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
}
public void onServiceDisconnected(ComponentName name) {
}
};
public void onCreate(Bundle savedInstanceState) {
Button button =(Button) this.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
Intent intent = new Intent(HelloActivity.this, SMSService.class);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
//unbindService(conn);//解除綁定
}});
}
}
```
#### 6.3.4 Service服務演示 ####
1. 新建一個Android工程ServiceDemo
2. 修改main.xml代碼,增加二個按鈕
3. 新建一個Service,命名為MyService.java
4. 新建ServiceDemo.java
5. 配置AndroidManifest.xml
6. 執行上述工程, 用Logcat查看日志
7. 按HOME鍵進入Settings(設置)àApplications(應用)àRunningServices(正在運行的服務)
**main.xml**
```
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="@+id/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<Button
android:id="@+id/startservice"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="startService" />
<Button
android:id="@+id/stopservice"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="stopService" />
</LinearLayout>
```
**MyService.java**
````
public class MyService extends Service {
//定義個一個Tag標簽
private static final String TAG = "MyService";
//一個Binder類,用在onBind() 方法里,這樣Activity那邊可以獲取到
private MyBinder mBinder = new MyBinder();
public IBinder onBind(Intent intent) {
Log.e(TAG, "start IBinder~~~");
return mBinder;
}
public void onCreate() {
Log.e(TAG, "start onCreate~~~");
super.onCreate();
}
public void onStart(Intent intent, int startId) {
Log.e(TAG, "start onStart~~~");
super.onStart(intent, startId);
}
```
```
public void onDestroy() {
Log.e(TAG, "start onDestroy~~~");
super.onDestroy();
}
public boolean onUnbind(Intent intent) {
Log.e(TAG, "start onUnbind~~~");
return super.onUnbind(intent);
}
public String getSystemTime(){
Time t = new Time();
t.setToNow();
return t.toString();
}
public class MyBinder extends Binder{
MyService getService()
{
return MyService.this;
}
} }
```
**ServiceDemo.java**
```
public class ServiceDemo extends Activity implements OnClickListener {
private MyService mMyService;
private TextView mTextView;
private Button startServiceButton;
private Button stopServiceButton;
private Context mContext;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setupViews();
}
```
```
public void setupViews(){
mContext = ServiceDemo.this;
mTextView = (TextView)findViewById(R.id.text);
startServiceButton = (Button)findViewById(R.id.startservice);
stopServiceButton = (Button)findViewById(R.id.stopservice);
startServiceButton.setOnClickListener(this);
stopServiceButton.setOnClickListener(this);
}
```
```
public void onClick(View v) {
if(v == startServiceButton){
Intent i = new Intent();
i.setClass(ServiceDemo.this, MyService.class);
mContext.startService(i);
}else if(v == stopServiceButton){
Intent i = new Intent();
i.setClass(ServiceDemo.this, MyService.class);
mContext.stopService(i);
}
}
}
```
**AndroidManifest.xml**
```
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lxt008"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".ServiceDemo"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MyService" android:exported="true"></service>
</application>
<uses-sdk android:minSdkVersion="7" />
</manifest>
```
### 6.4Notification通知 ###
如果需要查看消息,可以拖動狀態欄到屏幕下方即可查看消息。
發送消息的代碼如下:
```
//獲取通知管理器
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
int icon = android.R.drawable.stat_notify_chat;
long when = System.currentTimeMillis();
//新建一個通知,指定其圖標和標題
//第一個參數為圖標,第二個參數為標題,第三個為通知時間
Notification notification = new Notification(icon, null, when);
Intent openintent = new Intent(this, OtherActivity.class);
//當點擊消息時就會向系統發送openintent意圖
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, openintent, 0);
notification.setLatestEventInfo(this, “標題”, “我是內容", contentIntent);
mNotificationManager.notify(0, notification);
```
#### 6.4.1 Android中的通知(Notification) ####
### 6.5案例分析 ###
參考案例:NotificationDemo
[源代碼下載](http://www.apkbus.com/forum.php?mod=viewthread&tid=83334)