今天复习了一下Service的使用,在这里做一个总结。
Service与Activity类似运行在程序后台没有显示界面的一种服务。它的启动方式分为两种:1、使用startService(Intent intent) 2、使用bindService(Intent Intent,ServiceConnection service,int bind)方法。Service还提供了IntentService来实现一个异步的、能够自动停止的服务。同时,service服务结合消息通知、广播机制等,实现一些有趣的例子。一下是详细说明:
创建服务
1、 创建一个服务
创建一个服务类,继承自Service。在AndroidMenifest中注册该服务。
public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
}
service类中有onCreate()、onStartCommand()和onDestroy()方法。onCreate方法是服务创建时候调用的,并且只调用一次。onStartCommands()方法是服务启动的时候调用的。
onDestroy()方法是服务销毁的时候调用。如果我们希望服务一旦启动就立刻去执行某个动作,就可以将逻辑写在onStartCommand()方法里。而当服务销毁时,我们又应该在 onDestroy()方法中去回收那些不再使用的资源。
在AndroidMenifest.xml文件中注册服务
<service
android:name=".service.MyService"
android:enabled="true"
android:exported="true"></service>
2、 启动服务
点击“开启服务”按钮调用startService()方法启动服务
mIntent = new Intent(this, MyService.class);
startService(mIntent);
3、 关闭服务
点击“关闭服务”按钮时调用stopService()方法关闭服务。
Log.i("Tag","关闭服务");
stopService(mIntent);
服务与活动进行通信
描述:在MyService中提供一个下载功能,然后在活动中可以决定何时开始下载,以及随时查看下载进度。实现这个功能的思路是创建一个专门的Binder对象来对下载功能进行管理。
代码展示:
1、在MyService中定义一个Binder。并在onBind方法中返回该Binder
private DownloadBinder mBinder = new DownloadBinder();
class DownloadBinder extends Binder{
public void startDownload(){
Log.i(TAG,"开始执行下载任务..");
}
public int getProgress(){
Log.i(TAG,"获取下载进度..");
return 0;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
2、在Activity中创建一个ServiceConnection类,并且实现onServiceConnection方法。
private MyService.DownloadBinder downloadBinder;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
downloadBinder = (MyService.DownloadBinder) service;
downloadBinder.startDownload();
downloadBinder.getProgress();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
4、 分别设置“绑定服务”和“解绑服务”两个按钮,并且实现绑定服务和解绑服务。
case R.id.bind_btn:
Log.i("Tag", "绑定服务");
bindIntent = new Intent(this,MyService.class);
bindService(bindIntent,serviceConnection,BIND_AUTO_CREATE); //绑定服务
break;
case R.id.unbind_btn:
Log.i("Tag", "解除服务");
unbindService(serviceConnection); //解除绑定
break;
说明:
当调用了 startService()方法后,又去调用 stopService()方法,这时服务中的 onDestroy()
方法就会执行,表示服务已经销毁了。类似地,当调用了 bindService()方法后,又去调用
unbindService()方法,onDestroy()方法也会执行,这两种情况都很好理解。但是需要注意,
我们是完全有可能对一个服务既调用了 startService()方法,又调用了 bindService()方法的,
这种情况下该如何才能让服务销毁掉呢?根据 Android 系统的机制,一个服务只要被启动或者被绑定了之后,就会一直处于运行状态,必须要让以上两种条件同时不满足,服务才能被销毁。所以,这种情况下要同时调用 stopService()和 unbindService()方法,onDestroy()方法才会执行。
服务的更多应用
使用前台服务
前台服务和普通服务最大的区别就在于,它会一直有一个正在运
行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的
效果。当然有时候你也可能不仅仅是为了防止服务被回收掉才使用前台服务的,有些项目由
于特殊的需求会要求必须使用前台服务,比如说墨迹天气,它的服务在后台更新天气数据的
同时,还会在系统状态栏一直显示当前的天气信息。
private void startNotification() {
Notification.Builder builder = new Notification.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setTicker("显示通知");
builder.setContentTitle("通知");
builder.setWhen(System.currentTimeMillis());
builder.setAutoCancel(true); //打开程序后图标消失
Intent mIntent = new Intent(this,MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,mIntent,0);
builder.setContentIntent(pendingIntent);
Notification notification = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
notification = builder.build();
}
startForeground(1,notification);
}
IntentService服务
为了可以简单地创建一个异步的、会自动停止的服务,Android 专门提供了一个
IntentService 类。
1、创建IntentService类,实现相关方法。
public class MyIntentService extends IntentService {
private static final String TAG="MyIntentService";
public MyIntentService(){
super("name");
}
public MyIntentService(String name) {
super(name);
}
@Override
protected void onHandleIntent(Intent intent) {
Log.i(TAG,"当前线程id:"+Thread.currentThread().getId());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG,"IntentService 服务销毁");
}
}
2、设置点击事件,开启IntentService服务。
Log.i("Main","当前主线程id:"+Thread.currentThread().getId());
mIntent = new Intent(this,MyIntentService.class);
startService(mIntent);
后台执行的定时任务(实例)
运用广播知识和Service服务来制作一个后台永久运行的服务类程序。这个程序在后台中每隔1个小时打印一次数据。
思路:
1、 创建一个LongRunService服务,在onStartCommand()方法中设置多线程执行主要任务。
那么首先我们来看一下 Alarm 机制的用法吧,其实并不复杂,主要就是借助了
AlarmManager类来实现的。这个类和 NotificationManager有点类似,都是通过调用 Context的getSystemService()方法来获取实例的, 只是这里需要传入的参数是 Context.ALARM_SERVICE。public class
LongRunningService extends Service {
private static final String TAG="LongRunningService";
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
//后台中执行的具体逻辑。这里只是打印时间
Log.i(TAG,"当前时间:"+new Date().toString());
}
}).start();
//设置一定的时间来进行激活
alarmTimer();
return super.onStartCommand(intent, flags, startId);
}
private void alarmTimer(){
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
int anMinute = 60 * 1000; //设置一分钟。
long triggerAtTime = SystemClock.elapsedRealtime()+anMinute;
Intent i = new Intent(this, AlarmBroadCastReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(this,0,i,0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//设置精确时间,Android4.4 API19之后使用setExact
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime,pi);
}else{
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime,pi);
}
}
}
2、 创建一个AlarmBroadCastReceiver广播。在1中的AlarmManager中设置后台任务,每间隔1分钟,就会发送一次广播,从而激活这个服务。
public class AlarmBroadCastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent mIntent = new Intent(context, LongRunningService.class);
context.startService(mIntent);
}
}
3、 在Activity中启动一次服务。
Log.i("Main","启动后台定时任务");
mIntent = new Intent(this,LongRunningService.class);
startService(mIntent);
以上代码后期会放在github中:https://github.com/hpulzl/name