service相关

本篇仍以问题为驱动android

1、什么时Service?

Service是Android程序中四大基础组件之一,它和Activity同样都是Context的子类,只不过它没有UI界面,是在后台运行的组件。Service是Android中实现程序后台运行的解决方案,它很是适用于去执行那些不须要和用户交互并且还要求长期运行的任务。Service默认并不会运行在子线程中,它也不运行在一个独立的进程中,它一样执行在UI线程中,所以,不要在Service中执行耗时的操做,除非你在Service中建立了子线程来完成耗时操做。git

 

2、Service种类

按运行地点分类:github

按运行类型分类:编程

按使用方式分类:安全

 

3、Service生命周期

OnCreate()
系统在service第一次建立时执行此方法,来执行只运行一次的初始化工做。若是service已经运行,这个方法不会被调用。多线程

onStartCommand()
每次客户端调用startService()方法启动该Service都会回调该方法(屡次调用)。一旦这个方法执行,service就启动而且在后台长期运行。经过调用stopSelf()或stopService()来中止服务。架构

OnBind()
当组件调用bindService()想要绑定到service时(好比想要执行进程间通信)系统调用此方法(一次调用,一旦绑定后,下次再调用bindService()不会回调该方法)。在你的实现中,你必须提供一个返回一个IBinder来以使客户端可以使用它与service通信,你必须老是实现这个方法,可是若是你不容许绑定,那么你应返回null。异步

OnUnbind()
当前组件调用unbindService(),想要解除与service的绑定时系统调用此方法(一次调用,一旦解除绑定后,下次再调用unbindService()会抛出异常)。ide

OnDestory()
系统在service再也不被使用并要销毁时调用此方法(一次调用)。service应在此方法中释放资源,好比线程,已注册的侦听器,接收器等等.这是service收到的最后一个调用。工具

下面介绍三种不一样状况下Service的生命周期状况。

1.startService / stopService

生命周期顺序:onCreate->onStartCommand->onDestroy

若是一个Service被某个Activity 调用 Context.startService方法启动,那么不论是否有Activity使用bindService绑定或unbindService解除绑定到该Service,该Service都在后台运行,直到被调用stopService,或自身的stopSelf方法。固然若是系统资源不足,android系统也可能结束服务,还有一种方法能够关闭服务,在设置中,经过应用->找到本身应用->中止。

注意点:

①第一次 startService 会触发 onCreate 和 onStartCommand,之后在服务运行过程当中,每次 startService 都只会触发 onStartCommand

②不论 startService 多少次,stopService 一次就会中止服务

2.bindService / unbindService

生命周期顺序:onCreate->onBind->onUnBind->onDestroy

若是一个Service在某个Activity中被调用bindService方法启动,不论bindService被调用几回,Service的onCreate方法只会执行一次,同时onStartCommand方法始终不会调用。

当创建链接后,Service会一直运行,除非调用unbindService来接触绑定、断开链接或调用该Service的Context不存在了(如Activity被Finish——即经过bindService启动的Service的生命周期依附于启动它的Context),系统在这时会自动中止该Service。

注意点:

第一次 bindService 会触发 onCreate 和 onBind,之后在服务运行过程当中,每次 bindService 都不会触发任何回调

3.混合型(上面两种方式的交互)

当一个Service在被启动(startService)的同时又被绑定(bindService),该Service将会一直在后台运行,而且无论调用几回,onCreate方法始终只会调用一次,onStartCommand的调用次数与startService调用的次数一致(使用bindService方法不会调用onStartCommand)。同时,调用unBindService将不会中止Service,必须调用stopService或Service自身的stopSelf来中止服务。

在什么状况下使用 startService 或 bindService 或 同时使用startService 和 bindService?

①若是你只是想要启动一个后台服务长期进行某项任务那么使用 startService 即可以了。

②若是你想要与正在运行的 Service 取得联系,那么有两种方法,一种是使用 broadcast ,另外是使用 bindService ,前者的缺点是若是交流较为频繁,容易形成性能上的问题,而且 BroadcastReceiver 自己执行代码的时间是很短的(也许执行到一半,后面的代码便不会执行),然后者则没有这些问题,所以咱们确定选择使用 bindService(这个时候你便同时在使用 startService 和 bindService 了,这在 Activity 中更新 Service 的某些运行状态是至关有用的)。

③若是你的服务只是公开一个远程接口,供链接上的客服端(android 的 Service 是C/S架构)远程调用执行方法。这个时候你能够不让服务一开始就运行,而只用 bindService ,这样在第一次 bindService 的时候才会建立服务的实例运行它,这会节约不少系统资源,特别是若是你的服务是Remote Service,那么该效果会越明显(固然在 Service 建立的时候会花去必定时间,你应当注意到这点)。

 

4、Service与Activity怎么实现通讯

1.Binder:

  • 多个客户端能够所有链接到该服务。可是,系统只会在第一个客户端绑定时调用您的服务的onBind()方法来检索IBinder。系统而后将相同的IBinder传递给绑定的任何其余客户端,而无需再次调用onBind()。
  • 当最后一个客户端解除绑定服务时,系统会销毁该服务(除非该服务也由startService()启动)。
  • 实现绑定服务时,最重要的部分是定义onBind()回调方法返回的接口。您能够经过几种不一样的方法来定义服务的IBinder接口,如下部分将讨论每种技术。

(1)扩展Binder类

简述:若是您的Service对您本身的应用程序是私有的,而且与客户端在相同的进程中运行(这是常见的),则应该经过扩展Binder类并建立其实例,onBind()返回该实例。 客户端收到Binder,可使用它直接访问Binder实现或甚至Service中可用的公共方法。

实现以下:

经过 Binder 接口的形式实现,当 Activity 绑定 Service 成功的时候 Activity 会在 ServiceConnection 的类 的 onServiceConnected()回调方法中获取到 Service 的 onBind()方法 return 过来的 Binder 的子类,而后经过对象调用方法。
  这里以音乐播放service为例
  1. 新建一个继承自Service的类MusicService,而后在AndroidManifest.xml里注册这个Service
  2. Activity里面使用bindService方式启动MyService,也就是绑定了MyService
    (到这里实现了绑定,Activity与Service通讯的话继续下面的步骤)
  3. 新建一个继承自Binder的类MusicBinder(通常为service内部类)
  4. 在MusicService里实例化一个MusicBinder对象mBinder,并在onBind回调方法里面返回这个mBinder对象
  5. 第2步bindService方法须要一个ServiceConnection类型的参数,在ServiceConnection里能够取到一个IBinder对象,就是第4步onBinder返回的mBinder对象(也就是在Activity里面拿到了Service里面的mBinder对象)
  6. 在Activity里面拿到mBinder以后就能够调用这个binder里面的方法了(也就是能够给Service发消息了),须要什么方法在MyBinder类里面定义实现就好了。若是须要Service给Activity发消息的话,经过这个binder注册一个自定义回调便可。
public class MusicService extends Service {
    //实现一个播放音乐的servicepublic MediaPlayer mediaPlayer;private MusicBinder mBinder = new MusicBinder(this);

    public MusicService() {
        mediaPlayer = new MediaPlayer();
        try {
            mediaPlayer.setDataSource("/storage/emulated/0/netease/cloudmusic/Music/雷军 - Are You OK.MP3");
            mediaPlayer.prepare();
            mediaPlayer.setLooping(true);
        } catch (Exception e) {

        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {return super.onStartCommand(intent, flags, startId);
    }

public void playOrPause() {
        if (mediaPlayer.isPlaying()) {
            mediaPlayer.pause();
        } else {
            mediaPlayer.start();
        }
    }

    public void stop() {
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            try {
                mediaPlayer.reset();
                mediaPlayer.setDataSource(Environment.getExternalStorageState() 
+ "/storage/emulated/0/netease/cloudmusic/Music/雷军 - Are You OK.MP3"); mediaPlayer.prepare(); mediaPlayer.seekTo(0); } catch (Exception e) { } } } public class MusicBinder extends Binder { MusicService musicService; private OnTestListener mListener; public MusicBinder(MusicService service) { this.musicService = service; } public MusicService getService() { return musicService; } public void playOrPause() { musicService.playOrPause(); mListener.onTest(musicService.mediaPlayer.isPlaying() ? "play" : "pause"); } public void stop() { musicService.stop(); mListener.onTest("stop"); } // MyBinder 里面提供一个注册回调的方法 public void setOnTestListener(OnTestListener listener) { this.mListener = listener; } } //自定义一个回调接口 public interface OnTestListener { void onTest(String str); } }

 activity代码以下:

public class MusicActivity extends Activity implements MusicService.OnTestListener {

    private MusicService.MusicBinder mBinder;
    private MusicService mService;
    private ServiceConnection sc = new MusicServiceConnection();
    private TextView textView;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_btns);
        init();
    }

    private void init() {
        textView = (TextView) findViewById(R.id.tv_music);
        findViewById(R.id.btn_1).setOnClickListener(v -> {
            //绑定Service
            Intent intent = new Intent(this, MusicService.class);
            startService(intent);
            bindService(intent, sc, Context.BIND_AUTO_CREATE);

        });

        findViewById(R.id.btn_2).setOnClickListener(v -> {
            //解除绑定
            unbindService(sc);
        });
        findViewById(R.id.btn_3).setOnClickListener(v -> {
            //也能够直接经过binder获取的service实例,操做播放暂停方法
//            mService.playOrPause();
            //经过binder实例操做binder内部的service方法
            mBinder.playOrPause();
        });
        findViewById(R.id.btn_4).setOnClickListener(v -> {
//            mService.stop();
            mBinder.stop();
        });
    }

    @Override
    public void onTest(String str) {
        //接口回调,提供给service向activity的通讯,实现双向通讯
        textView.setText(str);
    }

    class MusicServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            mBinder = (MusicService.MusicBinder) iBinder;
            mService = mBinder.getService();
            mBinder.setOnTestListener(MusicActivity.this);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mService = null;
        }
    }
}
 
(2)使用Messenger:(进程间通讯)

简述:若是须要Service 和客户端位于不一样的进程,则可使用Messenger为服务建立一个interface。 以这种方式,服务定义响应不一样类型的Message对象的Handler。 该Handler是Messenger的基础,能够与客户端共享IBinder,容许客户端使用Message对象向服务发送命令。 此外,客户端能够定义本身的Messenger,所以服务能够发回消息。

这是执行进程间通讯(IPC)的最简单的方法,由于Messenger将全部请求排队到单个线程中,以便使用者没必要将服务设计为线程安全。

它引用了一个Handler对象,以便others可以向它发送消息(使用mMessenger.send(Message msg)方法)。该类容许跨进程间基于Message的通讯(即两个进程间能够经过Message进行通讯),在服务端使用Handler建立一个Messenger,客户端持有这个Messenger就能够与服务端通讯了。一个Messeger不能同时双向发送,两个就就能双向发送了
 
直接在onServiceConnected回调中像本地服务同样转换会报强转错误

 

使用:若是您须要服务与远程进程通讯,那么可使用Messenger为服务提供接口。这种技术容许执行进程间通讯(IPC),而无需使用AIDL。

如下是Messenger使用以下:

A、Service实现一个Handler,接收客户端发送的消息。

B、Handler用于建立一个Messenger对象(这是对Handler的引用)。

C、Messenger建立一个IBinder,Service将IBinder 从onBind()返回给客户端。

D、客户端使用IBinder来实例化Messenger (引用服务的Handler),客户端利用Messenger将Message对象发送到服务。

E、Service接收 Message在其Handler的handleMessage()方法中进行处理。

 

service实现代码

a. service建立Handler对象。

  * 处理来自客户端的消息
    */
    private Handler mHandler = new Handler() {
    //建立Handler对象
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(getApplicationContext(), "hello,remote service", Toast.LENGTH_SHORT).show();
                    //经过message对象获取客户端传递过来的Messenger对象。
                    Messenger messenger = msg.replyTo;
                    if (messenger != null) {
                        Message messg = Message.obtain(null, MSG_SAY_HELLO);
                        try {
                            //向客户端发送消息
                            messenger.send(messg);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case MSG_MUSIC_PLAY:
                    //播放/暂停音乐
                    playOrPause();
                    break;
                case MSG_MUSIC_STOP:
                    //中止播放
                    stop();
                    break;
                default:
                    break;
            }
        }
    };

 

b.建立Messenger对象

    //建立Mesenger 对象
    public Messenger mMessenger;

 

public RemoteMusicService() {
        mediaPlayer = new MediaPlayer();
        try {
            mediaPlayer.setDataSource("/storage/emulated/0/netease/cloudmusic/Music/雷军 - Are You OK.MP3");
            mediaPlayer.prepare();
            mediaPlayer.setLooping(true);
        } catch (Exception e) {

        }
        mMessenger = new Messenger(mHandler);
    }

 

c.onBind()返回IBinder对象

 
    
private MusicBinder mBinder = new MusicBinder(this);
 @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        //经过Mesenger对象获取IBinder实例,并返回
        return mMessenger.getBinder();
    }

 

d.服务端接收客户端发送的消息,并在Handler对象的hanleMessage方法中进行处理。

 

完整service代码以下

public class RemoteMusicService extends Service {
    //实现一个播放音乐的service
    public static final int MSG_SAY_HELLO = 101;
    public static final int MSG_MUSIC_PLAY = 102;
    public static final int MSG_MUSIC_STOP = 103;
    public MediaPlayer mediaPlayer;
    /**
     * 处理来自客户端的消息
    */
    private Handler mHandler = new Handler() {
    //建立Handler对象
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(getApplicationContext(), "hello,remote service", Toast.LENGTH_SHORT).show();
                    //经过message对象获取客户端传递过来的Messenger对象。
                    Messenger messenger = msg.replyTo;
                    if (messenger != null) {
                        Message messg = Message.obtain(null, MSG_SAY_HELLO);
                        try {
                            //向客户端发送消息
                            messenger.send(messg);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case MSG_MUSIC_PLAY:
                    //播放/暂停音乐
                    playOrPause();
                    break;
                case MSG_MUSIC_STOP:
                    //中止播放
                    stop();
                    break;
                default:
                    break;
            }
        }
    };
    //建立Mesenger 对象
    public Messenger mMessenger;
    private MusicBinder mBinder = new MusicBinder(this);

    public RemoteMusicService() {
        mediaPlayer = new MediaPlayer();
        try {
            mediaPlayer.setDataSource("/storage/emulated/0/netease/cloudmusic/Music/雷军 - Are You OK.MP3");
            mediaPlayer.prepare();
            mediaPlayer.setLooping(true);
        } catch (Exception e) {

        }
        mMessenger = new Messenger(mHandler);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        //经过Mesenger对象获取IBinder实例,并返回
        return mMessenger.getBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    public void playOrPause() {
        if (mediaPlayer.isPlaying()) {
            mediaPlayer.pause();
        } else {
            mediaPlayer.start();
        }
    }

    public void stop() {
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            try {
                mediaPlayer.reset();
                mediaPlayer.setDataSource(Environment.getExternalStorageState() + "/storage/emulated/0/netease/cloudmusic/Music/雷军 - Are You OK.MP3");
                mediaPlayer.prepare();
                mediaPlayer.seekTo(0);
            } catch (Exception e) {
            }
        }
    }

    public class MusicBinder extends Binder {
        RemoteMusicService musicService;

        public MusicBinder(RemoteMusicService service) {
            this.musicService = service;
        }

        public void playOrPause() {
            musicService.playOrPause();
        }

        public void stop() {
            musicService.stop();
        }

    }
}
View Code

 

 

AndroidManifest文件

 <service
            android:name=".service.musicService.RemoteMusicService"
            android:enabled="true"
            android:exported="true"
            android:icon="@drawable/ic_menu_camera"
            android:label="music"
            android:process=":music" />

exported要设置为true,不然别的进程不能使用该Service

 

客户端activity实现

a.绑定Service

b. 链接成功回调

实现ServiceConnection,必须覆盖两个回调方法:

findViewById(R.id.btn_5).setOnClickListener(v -> {
            Intent intent = new Intent(this, RemoteMusicService.class);    
            bindService(intent, new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                    // 当与服务端链接成功时,回调该方法。
                    //经过IBinder参数获取Messenger
                    mRemoteMessenger = new Messenger(iBinder);
                    textView.setText("connected");
                }

                @Override
                public void onServiceDisconnected(ComponentName componentName) {
                    mRemoteMessenger = null;
                    textView.setText("disconnected");
                }
            }, Context.BIND_AUTO_CREATE);
            textView.setText("connecting");
        });

c. 向服务端发送消息 
Message属性replyTo不是必须的,若是但愿Service向客户端发送消息则须要。

private void sendMsg(int what) {
        if (mRemoteMessenger == null) return;    //建立消息,设置what属性
        Message msg = Message.obtain(null, what);    //replyTo不是必须的,若是但愿Service向客户端发送消息则须要设置。
        msg.replyTo = mMessenger;
        try {        //发送消息
            mRemoteMessenger.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

d. 接收Service的回复

 private Messenger mRemoteMessenger;
    private Handler mHandler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    textView.setText("hello");
                    break;
                default:
                    break;
            }
        }
    };
    private Messenger mMessenger = new Messenger(mHandler);

e. 解除绑定

须要断开与服务的链接时,请调用unbindService()。

 

完整客户端activity代码以下

public class MusicActivity extends Activity {
private TextView textView;
    private Messenger mRemoteMessenger;
    private Handler mHandler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    textView.setText("hello");
                    break;
                default:
                    break;
            }
        }
    };
    private Messenger mMessenger = new Messenger(mHandler);

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_btns);
        init();
    }

    private void init() {
        textView = (TextView) findViewById(R.id.tv_music);
        findViewById(R.id.btn_5).setOnClickListener(v -> {
            Intent intent = new Intent(this, RemoteMusicService.class);    
            bindService(intent, new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                    // 当与服务端链接成功时,回调该方法。
                    //经过IBinder参数获取Messenger
                    mRemoteMessenger = new Messenger(iBinder);
                    textView.setText("connected");
                }

                @Override
                public void onServiceDisconnected(ComponentName componentName) {
                    mRemoteMessenger = null;
                    textView.setText("disconnected");
                }
            }, Context.BIND_AUTO_CREATE);
            textView.setText("connecting");
        });
        findViewById(R.id.btn_6).setOnClickListener(v -> {
            sendMsg(MSG_SAY_HELLO);
        });
        findViewById(R.id.btn_7).setOnClickListener(v -> {
            sendMsg(MSG_MUSIC_PLAY);
        });
        findViewById(R.id.btn_8).setOnClickListener(v -> {
            sendMsg(MSG_MUSIC_STOP);
        });
    }

    private void sendMsg(int what) {
        if (mRemoteMessenger == null) return;    //建立消息,设置what属性
        Message msg = Message.obtain(null, what);    //replyTo不是必须的,若是但愿Service向客户端发送消息则须要设置。
        msg.replyTo = mMessenger;
        try {        //发送消息
            mRemoteMessenger.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

}
 
View Code

 

 

(3)使用AIDL:

简述:AIDL(Android Interface Definition Language)执行全部的工做,将对象分解为基元,操做系统能够在进程之间了解和编组它们以执行IPC。 以前使用的Messenger技术其实是基于AIDL做为其底层结构。 如上所述,Messenger在单个线程中建立全部客户端请求的队列,所以服务一次接收一个请求。 可是,若是您但愿您的服务同时处理多个请求,则能够直接使用AIDL。 在这种状况下,您的服务必须可以进行多线程并创建线程安全。

要直接使用AIDL,您必须建立一个定义编程接口的.aidl文件。 Android SDK工具使用此文件生成一个实现接口并处理IPC的抽象类,而后您能够在服务中扩展它。

注意:大多数应用程序不该该使用AIDL建立绑定的服务,由于它可能须要多线程功能,并可能致使更复杂的实现。所以,AIDL不适用于大多数应用程序。

aidl 比较适合当客户端和服务端不在同一个应用下的场景。
(4)经过广播进行交互
(5)使用rxBus(轻量级通讯,缺点,发生错误难以debug)

5、IntentService有什么优势(与Service区别)

IntentService是Service的子类,是一个异步的,会自动中止的服务,很好解决了传统的Service中处理完耗时操做忘记中止并销毁Service的问题

  • 会建立独立的worker线程来处理全部的Intent请求;
  • 会建立独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题;
  • 全部请求处理完成后,IntentService会自动中止,无需调用stopSelf()方法中止Service;
  • 为Service的onBind()提供默认实现,返回null;
  • 为Service的onStartCommand提供默认实现,将请求Intent添加到队列中;
  • IntentService不会阻塞UI线程,而普通Serveice会致使ANR异常
  • Intentservice若未执行完成上一次的任务,将不会新开一个线程,是等待以前的任务完成后,再执行新的任务,等任务完成后再次调用stopSelf()

 

 

 

简单实现

相关文章
相关标签/搜索