安卓服务Service

22 篇文章 1 订阅

1、Service概念及用途

2、Service生命周期

3、Service与Activity通信

4、IntentService

5、跨进程访问AIDL

6、关于服务的应用

 

一、Service概念及用途

1、Service(服务)是一个没有用户界面的在后台运行执行耗时操作的应用组件。

2、其他应用组件能够启动Service,并且当用户切换到另外的应用场景,Service将持续在后台运行。

3、一个组件能够绑定到一个service来交互,例如,一个service可能会处理网络操作,播放音乐,操作文件I/O或者与内容提供者(content provider)交互,所有这些活动都是在后台进行。

4、Service有两种状态,“启动的”和“绑定”

Service的种类(了解)

按运行地点分类:

其实remote服务还是很少见的,并且一般都是系统服务。

按运行类型分类:

后台服务我们可以自己创建 ONGOING 的 Notification 这样就成为前台服务吗?答案是否定的,前台服务是在做了上述工作之后需要调用 startForeground ( android 2.0 及其以后版本 )或 setForeground (android 2.0 以前的版本)使服务成为 前台服务。这样做的好处在于,当服务被外部强制终止掉的时候,ONGOING 的 Notification 任然会移除掉。

按使用方式分类:

以上面三种方式启动的服务其生命周期也有区别,将在随后给出。

类别

区别

 优点

缺点 

 应用

本地服务(Local)

该服务依附在主进程上

 服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要IPC,也不需要AIDL。相应bindService会方便很多。

 主进程被Kill后,服务便会终止。

 非常常见的应用如:HTC的音乐播放服务,天天动听音乐播放服务。

远程服务(Remote)

该服务是独立的进程,

 服务为独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。

 该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。

 一些提供系统服务的Service,这种Service是常驻的。

类别

区别

应用

前台服务

会在通知一栏显示 ONGOING 的 Notification,

当服务被终止的时候,通知一栏的 Notification 也会消失,这样对于用户有一定的通知作用。常见的如音乐播放服务。

后台服务

默认的服务即为后台服务,即不会在通知一栏显示 ONGOING 的 Notification。

当服务被终止的时候,用户是看不到效果的。某些不需要运行或终止提示的服务,如天气更新,日期同步,邮件同步等。

类别

区别

startService 启动的服务

主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService

bindService 启动的服务

该方法启动的服务要进行通信。停止服务使用unbindService

startService 同时也 bindService 启动的服务

停止服务应同时使用stepService与unbindService

Service 与 Thread 的区别

1). Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。

2). Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。因此请不要把 Service 理解成线程,它跟线程半毛钱的关系都没有!

二、生命周期

onCreate  onStart  onDestroy  onBind 

startService:

  多次启动服务,startid会上升,强行杀死带服务的进程,则Service的startid会加+;

1、一旦启动,service就在后台运行,即使启动它的应用组件已经被销毁了。

2、通常started状态的service执行单任务并且不返回任何结果给启动者。比如当下载或上传一个文件,当这项操作完成时,service应该停止它本身。

bindService:

  只能绑定一次,绑定之后不能再重新绑定,也不能取消绑定两次。

  绑定会和当前应用程序共存亡,当前绑定的Activity销毁,自己也会销毁

1、一个绑定的service提供一个允许组件与service交互的接口,可以发送请求、获取返回结果,还可以通过夸进程通信来交互(IPC)。

2、绑定的service只有当应用组件绑定后才能运行,多个组件可以绑定一个service,当调用unbind()方法时,这个service就会被销毁了。

startService和bindService一起使用

特别注意:

***:service与activity一样都存在与当前进程的主线程中,所以,一些阻塞UI的操作,比如耗时操作不能放在service里进行,比如另外开启一个线程来处理诸如网络请求的耗时操作。

1、你应当知道在调用 bindService 绑定到Service的时候,你就应当保证在某处调用 unbindService 解除绑定(尽管 Activity 被 finish 的时候绑定会自动解除,并且Service会自动停止);

2、你应当注意 使用 startService 启动服务之后,一定要使用 stopService停止服务

3、同时使用 startService 与 bindService 要注意到,Service 的终止,只需要unbindService,不管 startService 与 bindService 的调用顺序,调用 unbindService 服务再调用stop就会停止。

4、当在旋转手机屏幕的时候,当手机屏幕在“横”“竖”变换时,此时如果你的 Activity 如果会自动旋转的话,旋转其实是 Activity 的重新创建,因此旋转之前的使用 bindService 建立的连接便会断开(Context 不存在了),对应服务的生命周期与上述相同。

5、在 sdk 2.0 及其以后的版本中,对应的 onStart 已经被否决变为了 onStartCommand,不过之前的 onStart 任然有效。这意味着,如果你开发的应用程序用的 sdk 为 2.0 及其以后的版本,那么你应当使用 onStartCommand 而不是 onStart。

 

 1、先start再bind:  那么bind不会再执行oncreate方法,如果按back,只会取消绑定,不会stop服务。

      unbind->ondestroy

       先unbind再stop:  unbind  ondestroy

       先stop再unbind:执行stop的时候 不会执行destroy的方法,直到执行unbind的时候才会unbind和destroy方法

2、先bind再start: oncreate->bind->onstart  

          unbind->ondestroy

       先unbind再stop:  unbind  ondestroy

       先stop再unbind:执行stop的时候 不会执行destroy的方法,直到执行unbind的时候才会unbind和destroy方法

 

三、Service与Activity通信

Activity与Service通信  使用Intent

Service与Activity通信  使用 ServiceConnection

 

public String getTime(){

        String time = new Date().toString();

        return time;

    }

    class MyBinder extends Binder{

        public MyService getMyService(){

            return MyService.this;

        }

    }

    @Override

    public IBinder onBind(Intent intent) {

        Log.i("msg", "onBind");

        return new MyBinder();

    }

 

ServiceConnection conn = new  ServiceConnection() {

        @Override

        public void onServiceDisconnected(ComponentName name) {

            Log.i("msg", "onServiceDisconnected");

        }

        @Override

        public void onServiceConnected(ComponentName name, IBinder service) {

            Log.i("msg", "onServiceConnected");

            MyBinder  myBinder = (MyBinder)service;

            MyService myService = myBinder.getMyService();

            Log.i("msg", myService.getTime());

        }

    };

 

四、IntentService

1、IntentService是继承于Service并处理异步请求的一个类

2、在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样

3、当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。

4、启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行

5、每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。

6、所有请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求。

优点:省去了在Service中手动开线程的麻烦,第二,当操作完成时,我们不用手动停止Service,第三,it's so easy to use!

 

public class MyIntentService extends IntentService {

    public MyIntentService() {

        super("name");

    }  

    @Override

    public void onCreate() {

        Log.i("msg", "onCreate ");

        super.onCreate();

    }

    @Override

    protected void onHandleIntent(Intent intent) {

        Log.i("msg", "onHandleIntent");

        try {

            Thread.sleep(15000);

        } catch (InterruptedException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

    }

}

startService(new Intent(this,MyIntentService.class));

        startService(new Intent(this,MyIntentService.class));

说明:onHandleIntent里面是可以执行耗时操作,并且是以队列的形式一个一个执行

 

五、AIDL跨进程之间的访问

 

Server

1、建立一个aidl的文件  建立在包里面,如果自动在gen里面生命一个IPerson的java文件,则正确   这个java文件是最终继承了BInder对象

2、写一个类继承IPerson,然后实现里面的方法

3、写一个Service类  ,把onBInder方法的返回值设置成Person对象,注册

 

package com.bwf.a75_serviceaidl_server;

 interface IPerson {

    void setAge(int age);

    void setName(String name);

    String show();

}

 

public class Person extends IPerson.Stub{

    private String name;

    private int age;

    @Override

    public void setAge(int age) throws RemoteException {

        this.age = age;

    }

    @Override

    public void setName(String name) throws RemoteException {

        // TODO Auto-generated method stub

        this.name = name;

    }

    @Override

    public String show() throws RemoteException {

        Log.i("msg", "name: "+name+"  age: "+age);

        return "name: "+name+"  age: "+age;

    }

}

 

    @Override

    public IBinder onBind(Intent intent) {

        return new Person();

    }

   <service android:name="com.bwf.a75_serviceaidl_server.MyService" android:exported="true">

            <intent-filter >

                <action android:name="com.bwf.service"/>

                <category android:name="android.intent.category.DEFAULT"/>

            </intent-filter>

        </service>

 

2、Client

1、建一个和Server一样的包名,然后再把IPersonjava类复制过来

2、

 

private IPerson per;

    private ServiceConnection conn = new ServiceConnection() {

        @Override

        public void onServiceDisconnected(ComponentName name) {

            // TODO Auto-generated method stub

        }

        @Override

        public void onServiceConnected(ComponentName name, IBinder service) {

            Log.i("msg", "onServiceConnected");

            per = IPerson.Stub.asInterface(service);

            try {

                per.setAge(30);

                per.setName("Tom");

                Log.i("msg", "onServiceConnected "+per.show());

            } catch (RemoteException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

        }

    };

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        Intent intent = new Intent();

        intent.setAction("com.bwf.service");

        bindService(intent, conn, Context.BIND_AUTO_CREATE);

    }

    @Override

    protected void onDestroy() {

        unbindService(conn);

        super.onDestroy();

    }

 

六、应用:使用服务播放音乐

 

public class MyService extends Service {

    private MediaPlayer media;

    @Override

    public void onCreate() {

        Log.i("msg", "onCreate");

        media = MediaPlayer.create(this, R.raw.aw);

        media.setLooping(false);

        try {

            media.prepare();//准备

        } catch (IllegalStateException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        } catch (IOException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

        super.onCreate();

    }

    @Override

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

        Log.i("msg", "onStartCommand: "+intent.getStringExtra("info"));

        switch (intent.getIntExtra("oop", 0)) {

        case 1://开始音乐

            if(media != null && !media.isPlaying() ){

                media.start();//播放

            }

            break;

        case 2://重头开始

            if(media != null){    

                media.seekTo(0);

//                media.stop();

//                media = MediaPlayer.create(this, R.raw.aw);

//                try {

//                    media.prepare();

//                } catch (IllegalStateException e) {

//                    // TODO Auto-generated catch block

//                    e.printStackTrace();

//                } catch (IOException e) {

//                    // TODO Auto-generated catch block

//                    e.printStackTrace();

//                }

//                media.start();

            }

            break;

        case 3://暂停

            if(media != null && media.isPlaying()){

                media.pause();

            }

            break;

        default:

            break;

        }

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

    }

    @Override

    public IBinder onBind(Intent intent) {

        Log.i("msg", "onBind");

        return null;

    }

    @Override

    public boolean onUnbind(Intent intent) {

        Log.i("msg", "onUnbind");

        return super.onUnbind(intent);

    }

    @Override

    public void onDestroy() {

        Log.i("msg", "onDestroy");

        if(media != null){

            media.stop();

            media.release();//释放

            media = null;

        }

        super.onDestroy();

    }

}

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

休以希

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值