关于Service你一定要知道的

       Service是Android四大组件之一,主要用于执行需要长时间运行的任务或者处理一些耗时的逻辑。Service可以在程序退出后,在后台继续运行。

一、Service的基本用法

启动Service的方法和启动Activity很类似,都需要借助Intent来实现,构建出一个Intent对象,调用startService()方法来启动Service。然后同样构建出了一个Intent对象,并调用stopService()方法来停Service。当启动一个Service的时候,会调用该Service中的onCreate()和onStartCommand()方法。

启动Service:

Intent startIntent =newIntent(this,MyService.class);

startService(startIntent);

关闭service:

Intent pauseIntent =newIntent(this,MyService.class);

stopService(pauseIntent);

       onCreate()方法只会在Service第一次被创建的时候调用,如果当前Service已经被创建过了,不管怎样调用startService()方法,onCreate()方法都不会再执行,只会执行onStartCommand()方法。启动Service之后,就可以在onCreate()或onStartCommand()方法里去执行一些具体的逻辑了。

       项目中的每一个Service都必须在AndroidManifest.xml中注册。

二、Service和Activity通信

      Service中有一个onBind()方法,这个方法就是用来和Activity通信的。通常会新增了一个类继承自Binder类,然后在这个类里写我们的逻辑,再通过onBind()方法将这个类的实例返回到activity中。因此service类应该是这样的:

public class MyService extends Service {

public static final String TAG ="MyService";

private MyBinder mBinder =new MyBinder();

@Override

public void onCreate() {

super.onCreate();

Log.i(TAG,"onCreate() executed");

}

@Override

public int onStartCommand(Intent intent,int flags,int startId) {

Log.i(TAG,"onStartCommand() executed");

return super.onStartCommand(intent, flags, startId);

}

@Override

public void onDestroy() {

super.onDestroy();

Log.i(TAG,"onDestroy() executed");

}

@Override

publicI Binder onBind(Intent intent) {

return mBinder;

}

class MyBinder extends Binder {

public void startDownload() {

Log.i("TAG","startDownload() executed");

}

}

}

在activity里与service关联上,首先创建一个ServiceConnection的匿名类,在里面重写了onServiceConnected()方法和onServiceDisconnected()方法,这两个方法会在Activity与Service建立关联和解除关联的时候调用。在onServiceConnected()方法中,通过向下转型得到了MyBinder的实例,即我们在service里返回的Binder的子类的实例。在Activity中根据具体的场景来调用Binder的子类中的任何public方法,即Activitys可以指挥Service干什么Service就去干什么。代码:

private ServiceConnection connection = new ServiceConnection() {

@Override

public void onServiceDisconnected(ComponentName name) {

}

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

myBinder = (MyService.MyBinder) service;

myBinder.startDownload();

}

};


Activity和Service的关联由bindService()方法来完成。构建出一个Intent对象,然后调用bindService()方法将Activity和Service进行关联。bindService()方法接收三个参数,第一个参数是Intent对象,第二个参数ServiceConnection的实例,第三个参数是一个标志位,这里传入BIND_AUTO_CREATE表示在Activity和Service建立关联后自动创建Service,这会使得MyService中的onCreate()方法得到执行,但onStartCommand()方法不会执行。

关联:

Intent bindIntent =newIntent(this, MyService.class);

bindService(bindIntent, connection, BIND_AUTO_CREATE);

解除关联:

unbindService(connection);

注意,任何一个Service在整个应用程序范围内都是通用的,即MyService不仅可以和MainActivity建立关联,还可以和任何一个Activity建立关联,而且在建立关联时它们都可以获取到相同的MyBinder实例。

三、销毁Service

stopService()只会让Service停止,unbindService只会让Service和Activity解除关联,一个Service必须要在既没有和任何Activity关联又处理停止状态的时候才会被销毁。

四、Service和Thread的关系

Service和Thread之间没有任何关系!Thread是用来开启一个子线程,在Thread里执行一些耗时操作就不会阻塞主线程的运行。实际上,Service是运行在主线程里的。可以这样检验:

在activity里打印当前线程编号:

Log.i("MyService","MainActivity thread id is "+ Thread.currentThread().getId());

在service里打印当前service的线程编号:

Log.i("MyService","MyService thread id is "+ Thread.currentThread().getId());

Android的后台就是指,它的运行是完全不依赖UI的。即使Activity被销毁,或者程序被关闭,只要进程还在,Service就可以继续运行。比如说一些应用程序,始终需要与服务器之间始终保持着心跳连接,就可以使用Service来实现。你可能又会问,前面不是刚刚验证过Service是运行在主线程里的么?在这里一直执行着心跳连接,难道就不会阻塞主线程的运行吗?当然会,但是我们可以在Service中再创建一个子线程,然后在这里去处理耗时逻辑就没问题了。
一个比较标准的Service就可以写成:

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

new Thread(new Runnable() {

@Override

public void run() {

// 开始执行后台任务

}

}).start();

return super.onStartCommand(intent, flags, startId);

}

class MyBinder extends Binder {

public void startDownload() {

new Thread(new Runnable() {

@Override

public void run() {

// 执行具体的下载任务

}

}).start();

}

}


五、创建前台Service

Service几乎都是在后台运行的。因为Service的系统优先级是比较低的,当系统出现内存不足时,就有可能会回收掉正在后台运行的Service。如果希望Service一直保持运行状态,而不会由于系统内存不足的原因导致被回收,可以考虑使用前台Service。前台Service和普通Service最大的区别就在于,它会一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果。方法就是在service里设置一下:

public class MyService extends Service {

public static final String TAG = "MyService";

private MyBinder mBinder = new MyBinder();

@Override

public void onCreate() {

super.onCreate();

// 在API11之后构建Notification的方式

Notification.Builder builder = new Notification.Builder

(this.getApplicationContext()); //获取一个Notification构造器

Intent nfIntent = new Intent(this, MainActivity.class);

builder.setContentIntent(PendingIntent.

getActivity(this, 0, nfIntent, 0)) // 设置PendingIntent

.setLargeIcon(BitmapFactory.decodeResource(this.getResources(),

R.mipmap.ic_large)) // 设置下拉列表中的图标(大图标)

.setContentTitle("下拉列表中的Title") // 设置下拉列表里的标题

.setSmallIcon(R.mipmap.ic_launcher) // 设置状态栏内的小图标

.setContentText("要显示的内容") // 设置上下文内容

.setWhen(System.currentTimeMillis()); // 设置该通知发生的时间

Notification notification = builder.build(); // 获取构建好的Notification

notification.defaults = Notification.DEFAULT_SOUND; //设置为默认的声音

startForeground(1, notification);

Log.d(TAG, "onCreate() executed");

}

.........

}

首先在MyService的onCreate()方法中创建了一个Notification对象,然后调用了它的setLatestEventInfo()方法来为通知初始化布局和数据,并在这里设置了点击通知后就打开MainActivity。然后调用startForeground()方法就可以让MyService变成一个前台Service,并会将通知的图片显示出来。

你可能感兴趣的:(关于Service你一定要知道的)