为了更好理解service, 大家可以下载示例代码,下载
android service组件用来完成android后台任务,也就是在后台默默的干自己的事,好多恶意的软件也都是通过此方法在用户的电脑上的悄悄做坏事,可以将activity比作饭店的服务员,service比作厨房的大厨,服务员直接和用户打交道,而大厨在后厨为用户烧菜。
大家也许会好奇,为什么一定要用service,我直接在activity的oncreate等函数直接启动一个线程不就好了,为什么要这么麻烦还要新建立一个service类, 假如我们在onCreate函数中启动一个线程,希望循环的处理一些消息
@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
Log.e(TAG, "onStart is called");
new Thread(new Runnable() {
@Override
public void run() {
while(true) {
// TODO Auto-generated method stub
Log.e(TAG, "create by activity");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
}
好了,现在我们在activity中通过onStart启动一个线程,假如你要播放音乐吧,当这个activity destory的时候,你要销毁该线程吧,所以你要干的事也就终止了,音乐停止了,如果你不去销毁,那问题又来了,当activity 重新create的时候,有再一次创建了线程,又一个播放音乐的线程起来了,Service解决了这个问题。
启动一个service的流程如图所示,通过在activity调用startService, service会后先判断,这个service派生类是否已经处于运行状态,如果不是,调用重载函数onCreate进行Service的创建,如果已经创建,则直接调用onStartCommand函数,也就是不同activity多次start 该service后只有onStartCommand会多次执行,onCreate只会在最初时执行一次。
启动一个Service的示例代码如下
1.创建一个Service类
package com.example.android.test;
import android.app.Service;
public class MainActivityService extends Service{
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Log.e(TAG, "service on Create");
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while(true) {
Log.e(TAG, "created by ServiceonCreate");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Log.e(TAG, "service on onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.e(TAG, "service on onDestroy");
// TODO Auto-generated method stub
super.onDestroy();
}
}
然后需要在androidManifest.xml中添加该Service的声明
<service android:name="MainActivityService"></service>
然后在activity中可以通过startService启动该类
package com.example.android.test;
import android.os.Bundle;
import android.os.IBinder;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity implements OnClickListener{
Button StartService;
Button StopService;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
StartService = (Button) findViewById(R.id.startService);
StopService = (Button) findViewById(R.id.stopService);
StartService.setOnClickListener(this);
StopService.setOnClickListener(this);
}
/*当发生单击事件时,android会回调该函数*/
@Override
public void onClick(View v) {
switch(v.getId()) {
/*单击这个按钮会启动一个server, 我在service中启动了一个线程,循环打印log*/
case (R.id.startService) :
Log.e(TAG, "startService is clicked");
Intent startIntent = new Intent(this, MainActivityService.class);
startService(startIntent);
break;
/*单击这个按钮会停止service, 当然如果绑定了服务,必须要进行unbind后,service才会真正的执行onDestroy*/
case (R.id.stopService) :
Log.e(TAG, "stopService is clicked");
Intent stopIntent = new Intent(this, MainActivityService.class);
stopService(stopIntent);
break;
default :
break;
}
}
}
Service类解决了activity destroy后线程无法继续运行的问题,Service可以在后台默默执行自己的任务,而不用去计较activity状态的变化,从程序来看StartService也只是相当于一个开关的作用,相当于activity通过发送一条命令告诉service你可以去执行某个任务,activity不能直接去调用service内部提供的接口,这显然是不够的,bind函数提供了activity去调用service内部接口的方法。
bind service首先应该通过一个binder 为基类的派生类,在里面可以定义向activity暴露的接口,然后重新onbinder函数,在onbinder函数内向activity返回在service定义的binder派生类
package com.example.android.test;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class MainActivityService extends Service{
public static final String TAG = "MyService";
private MyBinder mBinder = new MyBinder();
class MyBinder extends Binder {
public void privateService() {
Log.e(TAG, "runnging in background");
new Thread(new Runnable() {
@Override
public void run() {
while(true) {
// TODO Auto-generated method stub
Log.e(TAG, "create by binder");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
}
}
/*bindservice时会通过该重载函数将service类的成员暴露给activity*/
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return mBinder;
}
}
在activity类内,需要定义一个ServiceConnetion变量,通过传入的参数启动或停止service提供特定服务,代码如下
/*serviceConnection 类提供了访问server的状态,通过serverConnection可以控制Server启动或停止某些任务
* 和其他的回调函数一样,这个类被应用程序的主线程调用*/
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
/*bindService成功后会调用这个函数,IBinder service就是在MainActivityService中返回的MyBinder类*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
myBinder = (MainActivityService.MyBinder) service;
myBinder.privateService();
}
};
最后在activity内,通过调用bind, unbind实现启动或停止service的某些服务。
package com.example.android.test;
import android.os.Bundle;
import android.os.IBinder;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity implements OnClickListener{
Button StartService;
Button StopService;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BindService = (Button) findViewById(R.id.bindService);
UnBindService = (Button) findViewById(R.id.unbindService);
BindService.setOnClickListener(this);
UnBindService.setOnClickListener(this);
}
/*当发生单击事件时,android会回调该函数*/
@Override
public void onClick(View v) {
switch(v.getId()) {
/*绑定一个服务,执行bindService时,将会在service类中将绑定的类返回给回调类mServiceConneciton,
* 也就是将Service类中的一些接口暴露给了activity, 实现activity对Service的控制*/
case (R.id.bindService) :
Log.e(TAG, "bindService is clicked");
Intent bindIntent = new Intent(this, MainActivityService.class);
bindService(bindIntent, mServiceConnection, BIND_AUTO_CREATE);
break;
/*解除绑定,首先会调用mServiceConnetion中的onServiceDisconnected重载函数,只有unbinderService, stopservice
* 同时执行时,才会调用Service类中的onDestory重载函数*/
case (R.id.unbindService) :
Log.e(TAG, "unbindService is clicked");
unbindService(mServiceConnection);
default :
break;
}
}
}
下图为service的声明周期,当用户直接bindService也能导致service的create, 但不会执行onStartCommand函数,需要支持,当StartService与bindService同时执行时,只有当stopService与unbindService都被执行后,Service才能执行ondestory函数完成对service的销毁。