Intent intent = new Intent(MainActivity.this, MyService.class);
startService(intent);
Intent intent = new Intent(MyService.SERVICE_INTENT);
startService(intent);
// @value public static final String SERVICE_INTENT = "com.example.service_ex.SERVICE_INTENT";
<service
android:name=".MyService"
android:enabled="true"
android:permission="com.example.MY_SERVICE_PERMISSION">
<intent-filter>
<action android:name="com.example.service_ex.SERVICE_INTENT"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
stopService(new Intent(MainActivity.this ,MyService.class));
// stopService(new Intent(MyService.SERVICE_INTENT));
stopService(new Intent().setAction(MyService.SERVICE_INTENT));
stopSelf(startId);
或者stopSelf();
public class MyService extends Service{
public static final String SERVICE_INTENT = "com.example.service_ex.SERVICE_INTENT";
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate()
{
Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show();
//即是放在onCreate中,Service也是会按onCreate--onStartCommand--onDestory顺序执行
//stopSelf();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show();
//内部调用自终止
// stopSelf(startId);
return Service.START_STICKY;
}
@Override
public void onDestroy()
{
Toast.makeText(this, "ENDService", Toast.LENGTH_SHORT).show();
}
}
/**
* Called by the system every time a client explicitly starts the service by calling
* {@link android.content.Context#startService}, providing the arguments it supplied and a
* unique integer token representing the start request. Do not call this method directly.
*
* <p>For backwards compatibility, the default implementation calls
* {@link #onStart} and returns either {@link #START_STICKY}
* or {@link #START_STICKY_COMPATIBILITY}.
*
* <p>If you need your application to run on platform versions prior to API
* level 5, you can use the following model to handle the older {@link #onStart}
* callback in that case. The <code>handleCommand</code> method is implemented by
* you as appropriate:
*
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService.java
* start_compatibility}
*
* <p class="caution">Note that the system calls this on your
* service's main thread. A service's main thread is the same
* thread where UI operations take place for Activities running in the
* same process. You should always avoid stalling the main
* thread's event loop. When doing long-running operations,
* network calls, or heavy disk I/O, you should kick off a new
* thread, or use {@link android.os.AsyncTask}.</p>
*
* @param intent The Intent supplied to {@link android.content.Context#startService},
* as given. This may be null if the service is being restarted after
* its process has gone away, and it had previously returned anything
* except {@link #START_STICKY_COMPATIBILITY}.
* @param flags Additional data about this start request. Currently either
* 0, {@link #START_FLAG_REDELIVERY}, or {@link #START_FLAG_RETRY}.
* @param startId A unique integer representing this specific request to
* start. Use with {@link #stopSelfResult(int)}.
*
* @return The return value indicates what semantics the system should
* use for the service's current started state. It may be one of the
* constants associated with the {@link #START_CONTINUATION_MASK} bits.
*
* @see #stopSelfResult(int)
*/
publicint onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
}
从Android官方文档中,我们知道onStartCommand有4种返回值:
START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。
START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。
模拟实现:在运行Service后将其kill掉再重启,观察其startID及Intent参数实参值如下:
1. START_STICKY
可以看出,再次调用 onCreate、onStartCommand,并且 startId = 2, 但是 intent = null
2. START_NOT_STICKY
这次并没有重启。
3. START_STICKY_COMPATIBILITY
只调用了oncreate 方法,没有调用 onStartCommand
4. START_REDELIVER_INTENT
可以看出,再次调用 onCreate、onStartCommand,并且 startId = 1, 但是 intent 不为 null
说明该 int 可以保留上次的 startId 与 intent
一个绑定服务是客户端与服务端之间的一个接口。一个绑定服务允许组件和其进行绑定,并通过这个绑定服务,可以接受请求,发送请求,甚至完成进程间的通信。绑定服务的生命周期以来其绑定的客户端,并非无限期的运行下去。
一个绑定服务,就是一个实现了类Service,并允许其它应用程序与其绑定及与之交互的的组件。提供一个绑定服务,你必须实现onBind()方法,这个方法返回一个IBinder对象,这个对象就是定义用来客户端与服务交互的接口。
客户端通过bindService()方法绑定服务。另外,客户端还必须提供一个ServiceConnection的实现对象,用以监控与服务Service间的连接情况。bindService()无返回值,但系统在客户端与服务端连接之间,会调用在ServiceConnect对象中的onServiceConnected()方法,并传递一个客户端与服务端可以交互的IBinder接口。
多个客户端同时连接Service时,系统只在第一个客户端连接时调用你的onBind()方法并返回一个IBinder对象,系统在其他客户端进行连接时返回相同的IBinder对象,而不再去调用onBind().
当最后一个客户端调用与服务解除绑定时,系统将销毁服务,除非这个服务启动时,也调用了startService()方法.
有3种方式进行服务绑定:
1、 继承Binder类
如果你的服务只针对你自己的应用程序,且与客户端处于同一个进程当中,那么可以使用继承这种方式。此时,你应该创建一个继续与Binder接口的类,并实现其onBind(),然后返回一个你创建的服务的实例。然后客户端就可以接收到Binder,并可以使用这个Binder访问Binder的public方法及Service的public方法。
2、 使用信使者Messenger
如果你的Service要求跨越不同的进程,那么你需要为你的Service创建一个Messenger成员,同时定义一个可以响应不同类型消息Messge对象Handler对象。
Hander对象是为Messenger对象提供基础的,这样Hander就可以共享一个IBinder对象给客户端了,并允许客户端使用Message对象给服务发送命令。此外,客户端也可以定义一个自己的Messenger,这样客户端就可以将消息发送到服务端了。
3、 使用AIDL
比较复杂的一种,在Messenger基础上支持多线程并发处理。使用AIDL(Android Interface Definition Language),使得Service可以跨应用绑定,AIDL使用系统级的原语定义了Service的接口,允许Android跨进程传递对象。
1、继承Binder类方式实现:
自定义MyBindService继承Service:
/*绑定形式的Service*/
public class MyBindService extends Service{
//为client提供使用的Binder
public final IBinder binder = new MyBinder();
public class MyBinder extends Binder
{
MyBindService getServiceInstance()
{
return MyBindService.this;
}
}
/*Service生命周期*/
@Override
public void onCreate() {
Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show();
}
@Override
public IBinder onBind(Intent intent){
Toast.makeText(this, "onBind", Toast.LENGTH_SHORT).show();
//stopSelf();//使用stopSelf貌似没用
return binder;
}
@Override
public boolean onUnbind(Intent intent) {
Toast.makeText(this, "onUnbind", Toast.LENGTH_SHORT).show();
return false;
}
@Override
public void onDestroy() {
Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show();
}
/*提供相应服务*/
public String provideService()
{
return "provideService";
}
}
public class MainActivity extends Activity {
private Button myBind, myUnBind , myUse;
//标志是否绑定,判断myBindService=null的方法行不通
private booleanmBind;
private MyBindService myBindService;
//用以处理client和service
private ServiceConnection mConnection = new ServiceConnection() {
//调用bindService时系统会调用此函数
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//在这里获取MyBindService实例,则可以在Activity中调用Service中的方法
myBindService = ((MyBindService.MyBinder)service).getServiceInstance();
mBind = true;
}
//当Service意外断开时接收
@Override
public void onServiceDisconnected(ComponentName name) {
myBindService = null;
mBind = false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myBind = (Button) findViewById(R.id.myBind);
myUnBind = (Button) findViewById(R.id.myUnBind);
myUse = (Button) findViewById(R.id.myUse);
/*************************绑定Service形式******************************/
myBind.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, MyBindService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
/**bind执行流程 onCreate()--onBind(),onBind中需要返回IBinder的实例
bindService调用过程中会自动调用ServiceConnection。onServiceConnected()获得对应的Service实例
通过Service实例调用其提供的服务,并加以控制*/
}
});
myUnBind.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
/*如果Service没有bind,调用此函数程序将会崩溃
故应当先作判断*/
if (mBind) {
unbindService(mConnection);
//unBind执行流程 onUnbind--onDestory
mBind = false;
}
else {
Toast.makeText(MainActivity.this, "请先bind", Toast.LENGTH_SHORT).show();
}
}
});
myUse.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mBind && myBindService != null) {
Toast.makeText(MainActivity.this, myBindService.provideService(), Toast.LENGTH_SHORT).show();
}
}
});
}
}
public class MessengerService extends Service {
/** 自定义消息类型 */
static final intMSG_SAY_HELLO = 1;
/**自定义Handler来处理来自client的messages*/
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
caseMSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "MessengerService!",Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
/**
* 为IncomingHandler创建Messenger
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());
/**
* When binding to the service, we return an interface to our messenger
* for sending messages to the service.
*/
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
在clients端使用得:
public class MainActivity extends Activity {
private Button myMessengerBind, myMessengerUnBind, myMessengerUse;
private Messenger messenger;
private booleanmBindFlag;
private ServiceConnection mMessengerConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
messenger = new Messenger(service);
mBindFlag = true;
}
public void onServiceDisconnected(ComponentName className) {
messenger = null;
mBindFlag = false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myMessengerBind = (Button) findViewById(R.id.myMessengerBind);
myMessengerUnBind = (Button) findViewById(R.id.myMessengerUnBind);
myMessengerUse = (Button) findViewById(R.id.myMessengerUse);
myMessengerBind.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, MessengerService.class);
bindService(intent, mMessengerConnection, Context.BIND_AUTO_CREATE);
}
});
myMessengerUnBind.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mBindFlag) {
unbindService(mMessengerConnection);
//unBind执行流程 onUnbind--onDestory
mBindFlag = false;
}
else {
Toast.makeText(MainActivity.this, "请先bind", Toast.LENGTH_SHORT).show();
}
}
});
myMessengerUse.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(mBindFlag)
{
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
try {
messenger.send(msg);
} catch (Exception e) {
}
}
}
});
}
}
看一下Messenger的源码:
/**
* Reference to a Handler, which others can use to send messages to it.
* This allows for the implementation of message-based communication across
* processes, by creating a Messenger pointing to a Handler in one process,
* and handing that Messenger to another process.
*/
public final class Messenger implements Parcelable {
private final IMessenger mTarget;
/**
* Create a new Messenger pointing to the given Handler. Any Message
* objects sent through this Messenger will appear in the Handler as if
* {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had
* been called directly.
*
* @param target The Handler that will receive sent messages.
*/
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
/**
* Send a Message to this Messenger's Handler.
*
* @param message The Message to send. Usually retrieved through
* {@link Message#obtain() Message.obtain()}.
*
* @throws RemoteException Throws DeadObjectException if the target
* Handler no longer exists.
*/
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
/**
* Retrieve the IBinder that this Messenger is using to communicate with
* its associated Handler.
*
* @return Returns the IBinder backing this Messenger.
*/
public IBinder getBinder() {
return mTarget.asBinder();
}
/**
* Comparison operator on two Messenger objects, such that true
* is returned then they both point to the same Handler.
*/
public boolean equals(Object otherObj) {
if (otherObj == null) {
return false;
}
try {
return mTarget.asBinder().equals(((Messenger)otherObj)
.mTarget.asBinder());
} catch (ClassCastException e) {
}
return false;
}
public int hashCode() {
return mTarget.asBinder().hashCode();
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, intflags) {
out.writeStrongBinder(mTarget.asBinder());
}
public static final Parcelable.Creator<Messenger> CREATOR
= new Parcelable.Creator<Messenger>() {
public Messenger createFromParcel(Parcel in) {
IBinder target = in.readStrongBinder();
return target != null ? new Messenger(target) : null;
}
public Messenger[] newArray(int size) {
return new Messenger[size];
}
};
/**
* Convenience function for writing either a Messenger or null pointer to
* a Parcel. You must use this with {@link #readMessengerOrNullFromParcel}
* for later reading it.
*
* @param messenger The Messenger to write, or null.
* @param out Where to write the Messenger.
*/
public static void writeMessengerOrNullToParcel(Messenger messenger,
Parcel out) {
out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder() : null);
}
/**
* Convenience function for reading either a Messenger or null pointer from
* a Parcel. You must have previously written the Messenger with
* {@link #writeMessengerOrNullToParcel}.
*
* @param in The Parcel containing the written Messenger.
*
* @return Returns the Messenger read from the Parcel, or null if null had
* been written.
*/
public static Messenger readMessengerOrNullFromParcel(Parcel in) {
IBinder b = in.readStrongBinder();
return b != null ? new Messenger(b) : null;
}
/**
* Create a Messenger from a raw IBinder, which had previously been
* retrieved with {@link #getBinder}.
*
* @param target The IBinder this Messenger should communicate with.
*/
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
}
3、使用AIDL实现进程间通信IPC
http://blog.csdn.net/wangkuifeng0118/article/details/7277680
进程生命周期:
当service运行在低内存的环境时,将会kill掉一下存在的进程。因此进程的优先级将会很重要:
1、 如果service当前正在执行onCreate、onStartCommand、onDestroy方法,主进程将会成为前台进程来保证代码可以执行完成避免被kill
2、 如果service已经启动了,那么主进程将会比其他可见的进程的重要性低,但比其他看不见的进程高。因为只有少部分进程始终是用户可见的,因此除非在极度低内存的时候,不然 service是不会被kill的。
3、 如果有客户端关联到service,那么service永远比客户端重要。也就是说客户端可见,那么service也可见(我理解这里的可见并不是可以看到,而是重要性,因为可见往往就表示重要性高)。
4、 Service可以使用startForeground API将service放到前台状态。这样在低内存时被kill的几率更低,但是文档后面又写了,如果在极度极度低内存的压力下,该service理论上还是会被kill掉。但这个情况基本不用考虑。
当然如果service怎么保持还是被kill了,那你可以通过重写onStartCommand返回变量来设置它的启动方式。比如:START_STICKY、START_REDELIVER_INTENT等等,前面已经讨论了它们的作用,这里就不再累赘了
另外:
service 的onCreate和onStartCommand 是运行在主线程的,所以如果里面有处理耗时间的任务。两种处理:
1、 请将它们都挪到新的线程里。
2、 用系统提供的IntentService,它继承了Service,它处理数据是用自身新开的线程。