转载请注明出处:http://blog.csdn.net/l1028386804/article/details/47207467
Service通常总是称之为“后台服务”,其中“后台”一词是相对于前台而言的,具体是指其本身的运行并不依赖于用户可视的UI界面,因此,从实际业务需求上来理解,Service的适用场景应该具备以下条件:
1.并不依赖于用户可视的UI界面(当然,这一条其实也不是绝对的,如前台Service就是与Notification界面结合使用的);2.具有较长时间的运行特性。
一般而言,从Service的启动方式上,可以将Service分为Started Service和Bound Service。无论哪种具体的Service启动类型,都是通过继承Service基类自定义而来。在使用Service时,要想系统能够找到此自定义Service,无论哪种类型,都需要在AndroidManifest.xml中声明,语法格式如下:
<service android:enabled=["true" | "false"]
android:exported=["true" | "false"]
android:icon="drawable resource"
android:isolatedProcess=["true" | "false"]
android:label="string resource"
android:name="string"
android:permission="string"
android:process="string" >
. . .
</service>其中,android:exported属性上一篇博文中对此已进行详尽描述,android:name对应Service类名,android:permission是权限声明,android:process设置具体的进程名称。需要注意的是Service能否单独使用一个进程与其启动方式有关,本后下面会给出具体说明。其他的属性此处与其他组件基本相同,不再过多描述。 Started Service相对比较简单,通过context.startService(Intent serviceIntent)启动Service,context.stopService(Intent serviceIntent)停止此Service。当然,在Service内部,也可以通过stopSelf(...)方式停止其本身。
下面代码片段显示的是一个最基本的Started Service的自定义方式:
package com.lyz.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
/**
* @author liuyazhuang
*
*/
public class MyService extends Service {
public static final String TAG = "MyService";
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.w(TAG, "in onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.w(TAG, "in onStartCommand");
Log.w(TAG, "MyService:" + this);
String name = intent.getStringExtra("name");
Log.w(TAG, "name:" + name);
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.w(TAG, "in onDestroy");
}
}其中,onBind(...)函数是Service基类中的唯一抽象方法,子类都必须重写实现,此函数的返回值是针对Bound Service类型的Service才有用的,在Started Service类型中,此函数直接返回 null 即可。onCreate(...)、onStartCommand(...)和onDestroy()都是Started Service相应生命周期阶段的回调函数。package com.lyz.service;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.lyz.service.activity.R;
/**
* 程序入口
* @author liuyazhuang
*
*/
public class MainActivity extends Activity {
public static final String TAG = "MainActivity";
private Button startServiceBtn;
private Button stopServideBtn;
private Button goBtn;
private Intent serviceIntent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startServiceBtn = (Button) findViewById(R.id.start_service);
stopServideBtn = (Button) findViewById(R.id.stop_service);
goBtn = (Button) findViewById(R.id.go);
startServiceBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
serviceIntent = new Intent(MainActivity.this, MyService.class);
startService(serviceIntent);
}
});
stopServideBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stopService(serviceIntent);
}
});
goBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, BActivity.class);
startActivity(intent);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.w(TAG, "in onDestroy");
}
}如上代码片段,1.onCreate(Client首次startService(..)) >> onStartCommand >> onStartCommand - optional ... >> onDestroy(Client调用stopService(..))
注:onStartCommand(..)可以多次被调用,onDestroy()与onCreate()想匹配,当用户强制kill掉进程时,onDestroy()是不会执行的。
2.对于同一类型的Service,Service实例一次永远只存在一个,而不管Client是否是相同的组件,也不管Client是否处于相同的进程中。
3.Service通过startService(..)启动Service后,此时Service的生命周期与Client本身的什么周期是没有任何关系的,只有Client调用stopService(..)或Service本身调用stopSelf(..)才能停止此Service。当然,当用户强制kill掉Service进程或系统因内存不足也可能kill掉此Service。
4.Client A 通过startService(..)启动Service后,可以在其他Client(如Client B、Client C)通过调用stopService(..)结束此Service。
5.Client调用stopService(..)时,如果当前Service没有启动,也不会出现任何报错或问题,也就是说,stopService(..)无需做当前Service是否有效的判断。
6.startService(Intent serviceIntent),其中的intent既可以是显式Intent,也可以是隐式Intent,当Client与Service同处于一个App时,一般推荐使用显示Intent。当处于不同App时,只能使用隐式Intent。
当Service需要运行在单独的进程中,AndroidManifest.xml声明时需要通过android:process指明此进程名称,当此Service需要对其他App开放时,android:exported属性值需要设置为true(当然,在有intent-filter时默认值就是true)。
<service
android:name=".MyService"
android:exported="true"
android:process=":MyCorn" >
<intent-filter>
<action android:name="com.example.androidtest.myservice" />
</intent-filter>
</service>
当Client调用startService(Intent serviceIntent)启动Service时,Client可以将参数通过Intent直接传递给Service。Service执行过程中,如果需要将参数传递给Client,一般可以通过借助于发送广播的方式(此时,Client需要注册此广播)。
相对于Started Service,Bound Service具有更多的知识点。Bound Service的主要特性在于Service的生命周期是依附于Client的生命周期的,当Client不存在时,Bound Service将执行onDestroy,同时通过Service中的Binder对象可以较为方便进行Client-Service通信。Bound Service一般使用过程如下:
1.自定义Service继承基类Service,并重写onBind(Intent intent)方法,此方法中需要返回具体的Binder对象;
2.Client通过实现ServiceConnection接口来自定义ServiceConnection,并通过bindService (Intent service, ServiceConnection sc, int flags)方法将Service绑定到此Client上;
3.自定义的ServiceConnection中实现onServiceConnected(ComponentName name, IBinder binder)方法,获取Service端Binder实例;
4.通过获取的Binder实例进行Service端其他公共方法的调用,以完成Client-Service通信;
5.当Client在恰当的生命周期(如onDestroy等)时,此时需要解绑之前已经绑定的Service,通过调用函数unbindService(ServiceConnection sc)。
在Bound Service具体使用过程中,根据onBind(Intent intent)方法放回的Binder对象的定义方式不同,又可以将其分为以下三种方式,且每种方式具有不同的特点和适用场景:
这是Bound Service中最常见的一种使用方式,也是Bound Service中最简单的一种。
局限:Clinet与Service必须同属于同一个进程,不能实现进程间通信(IPC)。否则则会出现类似于“android.os.BinderProxy cannot be cast to xxx”错误。
下面通过代码片段看下具体的使用:
package com.lyz.service;
/**
* @author liuyazhuang
*
*/
public class MyBindService extends Service {
public static final String TAG = "MyBindService";
private MyBinder mBinder = new MyBinder();
public class MyBinder extends Binder {
MyBindService getService() {
return MyBindService.this;
}
}
@Override
public void onCreate() {
super.onCreate();
Log.w(TAG, "in onCreate");
}
@Override
public IBinder onBind(Intent intent) {
Log.w(TAG, "in onBind");
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.w(TAG, "in onUnbind");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.w(TAG, "in onDestroy");
}
}package com.lyz.service;
/**
* @author liuyazhuang
*
*/
public class BActivity extends Activity {
public static final String TAG = "BActivity";
private Button bindServiceBtn;
private Button unbindServiceBtn;
private Button startIntentService;
private Intent serviceIntent;
private ServiceConnection sc = new MyServiceConnection();
private MyBinder mBinder;
private MyBindService mBindService;
private boolean mBound;
private class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
Log.w(TAG, "in MyServiceConnection onServiceConnected");
mBinder = (MyBinder) binder;
mBindService = mBinder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
Log.w(TAG, "in MyServiceConnection onServiceDisconnected");
mBound = false;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.b);
bindServiceBtn = (Button) findViewById(R.id.bind_service);
unbindServiceBtn = (Button) findViewById(R.id.unbind_service);
startIntentService = (Button) findViewById(R.id.start_intentservice);
bindServiceBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(BActivity.this, MyBindService.class);
bindService(intent, sc, Context.BIND_AUTO_CREATE);
}
});
unbindServiceBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
excuteUnbindService();
}
});
startIntentService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(BActivity.this, MyIntentService.class);
startService(intent);
}
});
}
private void excuteUnbindService() {
if (mBound) {
unbindService(sc);
mBound = false;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.w(TAG, "in onDestroy");
excuteUnbindService();
}
}首次点击bindServiceBtn进行bindService(..)时,依次回调顺序如下:1 MyBindService(13457): in onCreate 2 MyBindService(13457): in onBind 3 BActivity(13457): in MyServiceConnection onServiceConnected再次点击bindServiceBtn按钮时,发现没有任何输出,说明MyBindService没有进行任何回调。
1 MyBindService(13457): in onUnbind 2 MyBindService(13457): in onDestroy注:在四大基本组件中,需要注意的的是BroadcastReceiver不能作为Bound Service的Client,因为BroadcastReceiver的生命周期很短,当执行完onReceive(..)回调时,BroadcastReceiver生命周期完结。而Bound Service又与Client本身的生命周期相关,因此,Android中不允许BroadcastReceiver去bindService(..),当有此类需求时,可以考虑通过startService(..)替代。
Messenger,在此可以理解成”信使“,通过Messenger方式返回Binder对象可以不用考虑Clinet - Service是否属于同一个进程的问题,并且,可以实现Client - Service之间的双向通信。极大方便了此类业务需求的实现。
局限:不支持严格意义上的多线程并发处理,实际上是以队列去处理
下面直接看下具体的使用:
package com.lyz.service;
/**
* @author liuyazhuang
*
*/
public class MyMessengerService extends Service {
public static final String TAG = "MyMessengerService";
public static final int MSG_FROM_CLIENT_TO_SERVER = 1;
public static final int MSG_FROM_SERVER_TO_CLIENT = 2;
private Messenger mClientMessenger;
private Messenger mServerMessenger = new Messenger(new ServerHandler());
@Override
public IBinder onBind(Intent intent) {
Log.w(TAG, "in onBind");
return mServerMessenger.getBinder();
}
class ServerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
Log.w(TAG, "thread name:" + Thread.currentThread().getName());
switch (msg.what) {
case MSG_FROM_CLIENT_TO_SERVER:
Log.w(TAG, "receive msg from client");
mClientMessenger = msg.replyTo;
// service发送消息给client
Message toClientMsg = Message.obtain(null, MSG_FROM_SERVER_TO_CLIENT);
try {
Log.w(TAG, "server begin send msg to client");
mClientMessenger.send(toClientMsg);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
}
@Override
public boolean onUnbind(Intent intent) {
Log.w(TAG, "in onUnbind");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.w(TAG, "in onDestroy");
super.onDestroy();
}
}package com.lyz.service;
/**
* @author liuyazhuang
*
*/
public class CActivity extends Activity {
public static final String TAG = "CActivity";
private Button bindServiceBtn;
private Button unbindServiceBtn;
private Button sendMsgToServerBtn;
private ServiceConnection sc = new MyServiceConnection();
private boolean mBound;
private Messenger mServerMessenger;
private Handler mClientHandler = new MyClientHandler();
private Messenger mClientMessenger = new Messenger(mClientHandler);
private class MyClientHandler extends Handler {
@Override
public void handleMessage(Message msg) {
if (msg.what == MyMessengerService.MSG_FROM_SERVER_TO_CLIENT) {
Log.w(TAG, "reveive msg from server");
}
}
}
private class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
Log.w(TAG, "in MyServiceConnection onServiceConnected");
mServerMessenger = new Messenger(binder);
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
Log.w(TAG, "in MyServiceConnection onServiceDisconnected");
mBound = false;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.c);
bindServiceBtn = (Button) findViewById(R.id.bind_service);
unbindServiceBtn = (Button) findViewById(R.id.unbind_service);
sendMsgToServerBtn = (Button) findViewById(R.id.send_msg_to_server);
bindServiceBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(CActivity.this, MyMessengerService.class);
bindService(intent, sc, Context.BIND_AUTO_CREATE);
}
});
unbindServiceBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
excuteUnbindService();
}
});
sendMsgToServerBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sayHello();
}
});
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(CActivity.this, MyAlarmBroadcastReceiver.class);
sendBroadcast(intent);
}
}, 3 * 1000);
}
public void sayHello() {
if (!mBound)
return;
// Create and send a message to the service, using a supported 'what' value
Message msg = Message.obtain(null, MyMessengerService.MSG_FROM_CLIENT_TO_SERVER, 0, 0);
// 通过replyTo把client端的Messenger(信使)传递给service
msg.replyTo = mClientMessenger;
try {
mServerMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
private void excuteUnbindService() {
if (mBound) {
unbindService(sc);
mBound = false;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.w(TAG, "in onDestroy");
excuteUnbindService();
}
}其中,需要注意的几点是:一般情况下,Messenger这种方式都是可以满足需求的,当然,通过自定义AIDL方式相对更加灵活。
这种方式需要自己在项目中自定义xxx.aidl文件,然后系统会自动在gen目录下生成相应的接口类文件,接下来整个的流程与Messenger方式差别不大,网上也有不少实例,在此不再具体给出。
注:无论哪种方式的Bound Service,在进行unbind(..)操作时,都需要注意当前Service是否处于已经绑定状态,否则可能会因为当前Service已经解绑后继续执行unbind(..)会导致崩溃。这点与Started Service区别很大(如前文所述:stopService(..)无需做当前Service是否有效的判断)。
Local Service:不少人又称之为”本地服务“,是指Client - Service同处于一个进程;
Remote Service:又称之为”远程服务“,一般是指Service处于单独的一个进程中。
其他使用上上文中基本上都有所述。
1.Service本身都是运行在其所在进程的主线程(如果Service与Clinet同属于一个进程,则是运行于UI线程),但Service一般都是需要进行”长期“操作,所以经常写法是在自定义Service中处理”长期“操作时需要新建线程,以免阻塞UI线程或导致ANR;
2.Service一旦创建,需要停止时都需要显示调用相应的方法(Started Service需要调用stopService(..)或Service本身调用stopSelf(..), Bound Service需要调用unbindService(..)),否则对于Started Service将处于一直运行状态,对于Bound Service,当Client生命周期结束时也将因此问题。也就是说,Service执行完毕后,必须人为的去停止它。
IntentService是系统提供给我们的一个已经继承自Service类的特殊类,IntentService特殊性是相对于Service本身的特性而言的:
1.默认直接实现了onBind(..)方法,直接返回null,并定义了抽象方法onHandlerIntent(..),用户自定义子类时,需要实现此方法;
2.onHandlerIntent(..)主要就是用来处于相应的”长期“任务的,并且已经自动在新的线程中,用户无语自定义新线程;
3.当”长期“任务执行完毕后(也就是onHandlerIntent(..)执行完毕后),此IntentService将自动结束,无需人为调用方法使其结束;
4.IntentService处于任务时,也是按照队列的方式一个个去处理,而非真正意义上的多线程并发方式。
下面是一个基本的继承自IntentService的自定义Service:
package com.lyz.service;
/**
* @author liuyazhuang
*
*/
public class MyIntentService extends IntentService {
public static final String TAG = "MyIntentService";
public MyIntentService() {
super(TAG);
}
public MyIntentService(String name) {
super(name);
}
@Override
protected void onHandleIntent(Intent intent) {
Log.w(TAG, "in onHandleIntent");
Log.w(TAG, "thread name:" + Thread.currentThread().getName());
}
}
Android中Service接口中还提供了一个称之为”前台Service“的概念。通过Service.startForeground (int id, Notification notification)方法可以将此Service设置为前台Service。在UI显示上,notification将是一个处于onGoing状态的通知,使得前台Service拥有更高的进程优先级,并且Service可以直接notification通信。
下面是一个简单的前台Service使用实例:
package com.lyz.service;
/**
* @author liuyazhuang
*
*/
public class MyService extends Service {
public static final String TAG = "MyService";
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.w(TAG, "in onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.w(TAG, "in onStartCommand");
Log.w(TAG, "MyService:" + this);
String name = intent.getStringExtra("name");
Log.w(TAG, "name:" + name);
Notification notification = new Notification(R.drawable.ic_launcher, "test", System.currentTimeMillis());
Intent notificationIntent = new Intent(this, DActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntesnt, 0);
notification.setLatestEventInfo(this, "title", "content", pendingIntent);
startForeground(1, notification);
return START_REDELIVER_INTENT;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.w(TAG, "in onDestroy");
}
}版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/l1028386804/article/details/47207467