1、Service的基本用法
首先看一下如何在项目中定义一个服务,在这个项目中新增一个名为 MyService 的类,并让它继承自 Service。这样的话一个服务就定义好了。既然是定义一个服务,自然应该在服务中去处理一些事情了,那处理事情的逻辑应该写在哪里呢?这时就可以重写 Service 中的另外一些方法。OnCreate()、onStartCommand()、onDestory()。这三个方法是最常用的方法。其中 onCreate()方法会在服务创建的时候调用,onStartCommand()方法会在每次服务启动的时候调用,onDestroy()方法会在服务销毁的时候调用。
通常情况下,如果我们希望服务一旦启动就立刻去执行某个动作,就可以将逻辑写在onStartCommand()方法里。而当服务销毁时,我们又应该在 onDestroy()方法中去回收那些不再使用的资源。
public class Myservice extends Service {
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
Log.v("msg", "--onBind()--方法被调用");
return null;
}
// onCreate()方法会在服务创建的时候调用
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Log.v("msg", "--onCreate()--方法被调用");
}
//onStartCommand()方法会在每次服务启动的时候调用
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Log.v("msg", "--onStartCommand()--方法被调用");
return super.onStartCommand(intent, flags, startId);
}
//onDestroy()方法会在服务销毁的时候调用
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.v("msg", "--onDestroy()--方法被调用");
}
}
另外需要注意,每一个服务都需要在 AndroidManifest.xml文件中进行注册才能生效。
<service android:name="com.test.testservice.Myservice"></service>
以上操作一个服务就定义好了,接下来去MainActivity中去启动和停止这个服务
public class MainActivity extends Activity {
private Button btn1;
private Button btn2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1 = (Button) findViewById(R.id.btn_01);
btn2 = (Button) findViewById(R.id.btn_02);
btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//创建一个Intent对象,用来启动服务
Intent stratIntent = new Intent(MainActivity.this,
Myservice.class);
//启动服务
startService(stratIntent);
}
});
btn2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//创建一个Intent对象,用来停止服务
Intent stopIntent = new Intent(MainActivity.this,
Myservice.class);
//停止服务
stopService(stopIntent);
}
});
}
}
按钮的点击事件里,我们构建出了一个 Intent 对象,并调用 startService()方法来启动 MyService 这个服务。在 Stop Serivce 按钮的点击事件里, 我们同样构建出了一个Intent对象, 并调用stopService()方法来停止MyService这个服务。不用Activity去控制服务,只需要在 MyService 的任何一个位置调用 stopSelf()方法也能让这个服务停止下来了。
2、服务和活动的基本通信
为了让活动和服务之间进行基本的通信,而不是活动发出一个命令之后就不能去控制服务怎么运行,就需要使用到Service中的onBind()方法。
比如说目前我们希望在 MyService 里提供一个下载功能,然后在活动中可以决定何时开始下载, 以及随时查看停止下载。 实现这个功能的思路是创建一个专门的 Binder 对象来对下载功能进行管理
public class Myservice extends Service {
//实例化MyBinder类
private MyBinder myBinder = new MyBinder();
//创建MyBinder类,继承Binder,在这里面写activity要service做的事,例如方法startDownload()和stopDownload()
class MyBinder extends Binder{
public void startDownload() {
// TODO Auto-generated method stub
Log.v("msg", "开始下载!");
}
public void stopDownload() {
// TODO Auto-generated method stub
Log.v("msg", "停止下载!");
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
Log.v("msg", "--onBind()--方法被调用");
//当Activity要控制Service时返回MyBinder实例,否则返回null
return myBinder;
}
// onCreate()方法会在服务创建的时候调用
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Log.v("msg", "--onCreate()--方法被调用");
}
//onStartCommand()方法会在每次服务启动的时候调用
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Log.v("msg", "--onStartCommand()--方法被调用");
return super.onStartCommand(intent, flags, startId);
}
可以看到,这里我们新建了一个 DownloadBinder 类,并让它继承自 Binder,然后在它的内部提供了开始下载以及查看下载进度的方法。当然这只是两个模拟方法,并没有实现真正的功能,我们在这两个方法中分别打印了一行日志。接着,在 MyService 中创建了 DownloadBinder 的实例,然后在 onBind()方法里返回了这个实例,这样 MyService 中的工作就全部完成了。
public class MainActivity extends Activity {
private Button btn3;
private Button btn4;
private Myservice.MyBinder myBinder;
//创建一个 ServiceConnection 的匿名类,在里面重写了onServiceConnected()方法和 onServiceDisconnected()方法
private ServiceConnection connection = new ServiceConnection() {
//当activity和service取消绑定时调用
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
Log.v("msg", "服务断开连接");
}
//当activity和service成功绑定时调用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
Log.v("msg", "服务连接");
//向下转型,得到MyBinder实例
myBinder = (MyBinder) service;
//调用MyBinder中的startDownload()方法
myBinder.startDownload();
//调用MyBinder中的stopDownload()方法
myBinder.stopDownload();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn3 = (Button) findViewById(R.id.btn_03);
btn4 = (Button) findViewById(R.id.btn_04);
btn3.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//创建Intent对象,用来绑定Service bindService()方法接收三个参数, 第一个参数就
//是刚刚构建出的 Intent 对象,第二个参数是前面创建出的 ServiceConnection 的实例,第三个
//参数则是一个标志位,这里传入 BIND_AUTO_CREATE 表示在活动和服务进行绑定后自动创建服务
Intent bindIntent = new Intent(MainActivity.this,
Myservice.class);
//绑定service
bindService(bindIntent, connection, BIND_AUTO_CREATE);
}
});
btn4.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//解除Activity和Service的绑定
unbindService(connection);
}
});
}
}
可以看到,这里我们首先创建了一个 ServiceConnection 的匿名类,在里面重写了onServiceConnected()方法和 onServiceDisconnected()方法,这两个方法分别会在活动与服务成功绑定以及解除绑定的时候调用。在 onServiceConnected()方法中,我们又通过向下转型得到了 DownloadBinder 的实例,有了这个实例,活动和服务之间的关系就变得非常紧密了。现在我们可以在活动中根据具体的场景来调用 DownloadBinder 中的任何 public 方法,即实现了指挥服务干什么,服务就去干什么的功能。这里仍然只是做了个简单的测试,在onServiceConnected()方法中调用了 DownloadBinder的 startDownload()和 stopDownload()方法。当然,现在活动和服务其实还没进行绑定呢,这个功能是在 Bind Service 按钮的点击事件里完成的。可以看到,这里我们仍然是构建出了一个 Intent 对象,然后调用 bindService()方法将 MainActivity 和 MyService 进行绑定。bindService()方法接收三个参数, 第一个参数就是刚刚构建出的 Intent 对象,第二个参数是前面创建出的 ServiceConnection 的实例,第三个参数则是一个标志位,这里传入 BIND_AUTO_CREATE 表示在活动和服务进行绑定后自动创建服务。这会使得 MyService 中的 onCreate()方法得到执行,但 onStartCommand()方法不会执行。然后如果我们想解除活动和服务之间的绑定该怎么办呢?调用一下 unbindService()方法就可以了,这也是 Unbind Service 按钮的点击事件里实现的功能。
3、使用前台服务
前台服务的使用是为了防止系统内存不足时,关闭后台的服务。
前台服务使用只需要在MyService的方法onCreate()中加入如下代码即可
//下面代码是使用前台服务,防止服务在系统内存不足时被回收
Notification notification = new Notification(R.drawable.ic_launcher,"Notification comes", System. currentTimeMillis());
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,notificationIntent, 0);
notification.setLatestEventInfo(this, "This is title", "This is content", pendingIntent);
startForeground(1, notification);
4、使用IntentService
为了防止程序在servcie中进行耗时操作,出现AND异常,可以使用IntentService来代替Service,这里面开启了子线程,可以用来进行耗时的操作。
public class MyIntentService extends IntentService {
public MyIntentService() {
// TODO Auto-generated constructor stub
super("MyIntentService");
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
protected void onHandleIntent(Intent intent) {
// TODO Auto-generated method stub
//在这里处理具体的逻辑问题,不用担心ANR,这是一个子线程,事情做完会自动调用onDestroy()方法
Log.v("msg","Thread id is " + Thread.currentThread().getId());
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.v("msg", "--onDestroy()--方法被调用");
}
}
这里首先是要提供一个无参的构造函数,并且必须在其内部调用父类的有参构造函数。然后要在子类中去实现 onHandleIntent()这个抽象方法, 在这个方法中可以去处理一些具体的逻辑,而且不用担心 ANR 的问题,因为这个方法已经是在子线程中运行的了。这里为了证实一下, 我们在 onHandleIntent()方法中打印了当前线程的 id。 另外根据 IntentService 的特性,这个服务在运行结束后应该是会自动停止的,所以我们又重写了 onDestroy()方法,在这里也打印了一行日志,以证实服务是不是停止掉了。
在 AndroidManifest.xml文件中进行注册才能生效。
<service android:name="com.test.testservice.MyIntentService"></service>
看看MainActivity中的代码,与Service的使用并没什么区别
public class MainActivity extends Activity {
private Button btn5;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn5 = (Button) findViewById(R.id.btn_05);
btn5.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
// 打印主线程的id
Log.v("msg", "Thread id is " + Thread.currentThread().getId());
//创建一个Intent对象
Intent intentService = new Intent(MainActivity.this, MyIntentService.class);
//开启服务
startService(intentService);
}
});
}
}
以上代码布局非常简单,就不给出
这些乃是作者看《第一行代码》的笔记。另官方service介绍的链接:点击打开链接