Service是android中四大組件之一,重要性僅次于Activity堰汉,Android文檔對他的描述如下:
Service組件表示在不影響用戶的情況下執(zhí)行耗時操作或者提供其他應(yīng)用使用的功能辽社。
在android中所有的組件都運行在主線程,使用service的時候翘鸭,還需要吧耗時的操作另開啟一個線程滴铅。但是使用Service,更適合管理耗時的操作,因為service有著不同的生命周期就乓。比如說應(yīng)用中播放音樂汉匙,通常由Service控制拱烁。
啟動Service
Service 可以通過兩種方式啟動:Context.startService()或者Context.bindService();
Context.startService()和啟動activity的方法類似:
Intent i = new Intent(ServiceActivity.this, ServiceA.class);
startService(i);
使用這種方式啟動Service后,Service分別會調(diào)用onCreate()和onStartCommand()方法噩翠。
停止Service的方法:
Intent i = new Intent(ServiceTestActivity.this, ServiceA.class);
stopService(i);
也可以調(diào)用Service的stopSelf()方法進行停止戏自。
service銷毀的時候會調(diào)用他的onDestory()方法,在這里進行釋放資源的操作伤锚。
需要注意的是多次啟動Service擅笔,onCreate()方法不會多次調(diào)用,只有在第一次啟動的時候會調(diào)用(或者把Service銷毀重新start),但是onStartCommand()方法會多次調(diào)用屯援。
第二種方式:Context.bindService()
Intent i = new Intent(ServiceTestActivity.this, ServiceA.class);
bindService(i,connection,BIND_AUTO_CREATE);
解除綁定方法:
Intent i = new Intent(ServiceTestActivity.this, ServiceA.class);
unbindService(connection);
這種方式啟動Service的時候猛们,生命周期方法如下:
bindService->onCreate->onBind->unbindService->onUnbind->onDestroy
如果沒有調(diào)用unbindService方法,當(dāng)activity銷毀的時候此Service也能銷毀玄呛,但是會發(fā)生內(nèi)存泄露阅懦,會報如下錯誤:
Activity example.ylh.com.service_demo.ServiceTestActivity has leaked ServiceConnection example.ylh.com.service_demo.ServiceTestActivity$1@513a0eb that was originally bound here
······
所以為了防止內(nèi)存泄露和二,還是老老實實的unbind吧徘铝。
bindService啟動的時候,需要傳兩個參數(shù)惯吕,第一個是intent惕它,第二個是ServiceConnection,這個是什么東西呢废登?
我們知道Service啟動之后淹魄,Service額就開始運行了,但是怎么和Activity交互呢堡距,這個時候就需要ServiceConnection了甲锡,ServiceConnection是一個接口:
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG,"onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG, "onServiceDisconnected");
}
};
onServiceConnected方法的調(diào)用時機是在Service的onBind之后,表示service和activity綁定成功羽戒,建立關(guān)聯(lián)缤沦。
onServiceDisconnected方法表示Service和activity關(guān)聯(lián)失敗,沒有綁定易稠,一般不會調(diào)用缸废。
onServiceConnected方法有兩個參數(shù),第二個參數(shù)是一個IBinder驶社,這個IBinder就是Service的onBind方法的返回值企量,所以我們可以通過onBind的返回值和onServiceConnected方法,讓activity和Service關(guān)聯(lián)起來亡电,下邊是一個典型案例:
activity的xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn1"
android:text="start"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn2"
android:text="stop"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn3"
android:text="action"/>
</LinearLayout>
</RelativeLayout>
activity代碼:
package example.ylh.com.service_demo;
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.View;
import example.ylh.com.R;
/**
* Created by yanglihai on 2017/8/17.
*/
public class ServiceTestActivity extends Activity {
public static final String TAG = ServiceTestActivity.class.getSimpleName();
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = ((ServiceA.MyBinder) service).getService();
Log.e(TAG,"onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG, "onServiceDisconnected");
}
};
private ServiceA mService ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.service_test_activity);
findViewById(R.id.btn1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(ServiceTestActivity.this, ServiceA.class);
bindService(i,connection,BIND_AUTO_CREATE);
}
});
findViewById(R.id.btn2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(ServiceTestActivity.this, ServiceA.class);
unbindService(connection);
}
});
findViewById(R.id.btn3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mService.doSomething();
}
});
}
}
service的代碼:
package example.ylh.com.service_demo;
import android.app.Service;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
/**
* Created by yanglihai on 2017/8/17.
*/
public class ServiceA extends Service {
static final String TAG = ServiceA.class.getSimpleName();
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "oncreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy");
}
@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
Log.e(TAG, "bindService");
return super.bindService(service, conn, flags);
}
@Override
public void unbindService(ServiceConnection conn) {
super.unbindService(conn);
Log.e(TAG, "unBindService");
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "onUnbind");
return super.onUnbind(intent);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind" );
return mbinder;
}
public void doSomething(){
Log.e(TAG, "doSomething");
}
private MyBinder mbinder = new MyBinder();
public class MyBinder extends Binder{
public ServiceA getService(){
return ServiceA.this;
}
}
}
在onServiceConnected方法中届巩,通過強轉(zhuǎn)拿到binder,在通過getService()拿到Service的實例份乒,就可以進行你想要的操作了恕汇。
前臺Service
當(dāng)Service啟動之后零酪,如果我們不去調(diào)用停止方法,Service會一直運行在后臺拇勃,但是當(dāng)系統(tǒng)內(nèi)存不足的時候可能會殺死我們的Service四苇,為了避免被系統(tǒng)殺死,可以把Service設(shè)置成前臺服務(wù)方咆,通過調(diào)用Service.startForeground()來實現(xiàn)月腋。
先上代碼:
package example.ylh.com.service_demo;
import android.app.Notification;
import android.app.Service;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
import example.ylh.com.R;
/**
* Created by yanglihai on 2017/8/17.
*/
public class ServiceA extends Service {
static final String TAG = ServiceA.class.getSimpleName();
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "oncreate");
Notification.Builder builder = new Notification.Builder(this);
builder.setSmallIcon(R.mipmap.btn_home_vedio);
builder.setContentTitle("視頻通知");
builder.setContentText("someone send you a video");
Notification notification = builder.build();
startForeground(2,notification);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy");
}
}
在onCreate中,創(chuàng)建了一個通知瓣赂,用來告訴用戶后臺有操作在運行榆骚。startForeground()的第一個參數(shù)是一個int型的id,需要注意的是這個id不能為0煌集,否則不能創(chuàng)建前臺服務(wù)妓肢。
在這個Service運行期間,通知欄會有一個通知苫纤,直到Service停止或者調(diào)用StopForeground(true)碉钠,通知就能消失。
補充一點卷拘,不論哪種啟動方式喊废,Service也需要在manifest文件中聲明:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="example.ylh.com" >
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".service_demo.ServiceA" />
</application>
</manifest>