浅谈Android四大组件之Service

1 介绍

Android中的服务,没有界面在后台长期运行的,四大组件之一,service 和activity 有血缘关系 service 辈分大一些 是activity的 叔叔
这里写图片描述

这里写图片描述

2 start方式开启服务的特点

  • Start方式开启服务,调用 oncreate onStart onDestroy
  • 进入设置 应用===>正在运行 可以找到 这个服务
  • 再次startservice 会调用 onstart 服务不会重新创建(调用onCreate)
  • 进入 apps==>running 找到这个服务 点击 停止
  • 也可以用代码 stopservice
  • 生命周期要比activity长,即 在activity中开启后,即使当前activity消亡,service也不会消亡。

代码手动开启服务并关闭:

 // 开启服务
    public void click(View v) {

        // 开启服务和 开启activity的方式 一模一样
        Intent service = new Intent();
        service.setClass(this, FirstService.class);
        startService(service);
    }

    // 停止服务
    public void click1(View v) {
        Intent service = new Intent();
        service.setClass(this, FirstService.class);
        stopService(service);
    }

FirstService 为继承Service类并在清单文件中注册。

  • 在Activity中开启服务和关闭服务为什么要在两个按钮点击事件中 new 两次而不是直接声明称全局变量?
    这是因为开启服务后服务生命周期要比activity生命周期长,比如,当点击第一个按钮后开启服务,这时点击返回按钮退出当前引用(销毁activity),此时系统中会有一个服务进程和一个服务在运行,当我们再点击当前应用时,再点击第二个按钮进行停止服务,此时就会报错,因为Intent声明为全局变量后初始化activity 在第二个按钮中intent为空,此时就会报空指针错误,因此这时需要在开启和关闭服务处分别new Intent.
  • 第一次开启服务后再没有停止服务情况下,再进行开启服务,此时onCreate不会调用第二次,而是直接运行onStartCommand.

2.1 start方式开启服务的案例(在服务中注册广播接收者)

通过在服务中注册广播接收者,实现监听屏幕的开启与关闭,广播注册使用动态注册

定义Service:

public class ScreenService extends Service {

    private ScreenReceiver receiver;

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
        // 服务中注册特殊的广播接收者
        // 和在activity的方式 一模一样
        // 记得在服务销毁的时候 注销
        // 不注销会漏气
        receiver = new ScreenReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction("android.intent.action.SCREEN_ON");
        filter.addAction("android.intent.action.SCREEN_OFF");
        registerReceiver(receiver, filter);//动态注册广播需要在 服务销毁的时候注销广播接收者
    }

    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();

        // 注销
        unregisterReceiver(receiver);
    }
}

定义广播接收者:

public class ScreenReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action.equals("android.intent.action.SCREEN_ON")) {
            System.out.println("屏幕亮了");
        }
        if (action.equals("android.intent.action.SCREEN_OFF")) {
            System.out.println("屏幕灭了");
        }
    }
}

在清单文件注册:

     <receiver android:name="cn.test.registbroadcast.ScreenReceiver">
            <intent-filter >
                <action android:name="android.intent.action.SCREEN_ON"/>
                <action android:name="android.intent.action.SCREEN_OFF"/>
            </intent-filter>
        </receiver>
        <service android:name="cn.test.registbroadcast.ScreenService">
       </service>

启动服务:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //启动服务
        startService(new Intent(this, ScreenService.class));

    }

3 bind方式开启服务的特点

为什么前面已经有start方式开启服务还要搞一个bind服务方式?
因为是为了调用服务里的方法。

  • bind方式开启 执行 oncreate onbind
  • 在 apps===>running 不能找到这个服务 隐形的服务
  • Bind 服务和activity就绑定在一起 如果 activity 退出 就会漏气 并且解除绑定
  • 手动 unbindservice (bind服务 只能执行一次,一般放在activity的oncreate中) onunbind onDestory
  • Bind服务 不是在后台长期运行 生命 很短 ,和activity 差不多 意思就是bind服务后在activity 销毁的时候要解绑服务。

3.1 bind方式开启服务案列(普通方法)

步骤:

  • 创建服务
  • 开启服务 bindservice
  • 在服务中创建代理对象 mybind
  • 在代理对象中创建一个方法调用服务里的方法,代理对象里的方法要和服务里的方法参数和返回值要一样,代理对象里的方法不要和服务里的方法名字重复。
  • 把代理对象在onbind()返回回去
  • 在myserviceconn 中onServiceConnected 可以接收到返回的代理对象
public class BanzhengService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub

        //返回代理人对象
        return new MyBinder();
    }

    public void banZheng(int money){
        if (money>=500) {
            System.out.println("大兄弟,明天来拿证..");
        }else{
            System.out.println("小伙子,今天比较忙,下次再说吧");
        }
    }

    //代理对象
    //Binder 是Ibinder 的实现类
    class MyBinder extends Binder{

        //创建和服务中一样 参数一样的  返回值  不一样 的方法名的 方法
        public void callbanzheng(int money){
            banZheng(money);
        }
    }
}

在activity中开启服务:

public class MainActivity extends Activity {
    private MyBinder binder;
    private MyServiceConn conn;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent service=new Intent();
        service.setClass(this, BanzhengService.class);
        conn = new MyServiceConn();
        bindService(service, conn, BIND_AUTO_CREATE);
    }

    //点击办证
    public void click(View v){
        binder.callbanzheng(49999999);
    }

    class MyServiceConn implements ServiceConnection{
        //当服务连接成功的时候调用
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

            binder = (MyBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub

        }

    }
    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        //解绑 服务
        unbindService(conn);
    }
}

注意:服务需要在清单文件里注册(这里就不贴上代码了)

3.2 bind方式开启服务案例(抽取接口方式)

通过抽取接口方式,我们可以在服务中指定向外部曝露相应的方法,这样更符合面向对象编程:

定义含有指定方法的接口:

public interface Iservice {
    public void callbanzheng(int money);
    public void calldaqiu();
}

再定义服务:

public class BanzhengService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub

        //返回代理人对象
        return new MyBinder();
    }

    public void banZheng(int money){
        if (money>=500) {
            System.out.println("大兄弟,明天来拿证..");
        }else{
            System.out.println("小伙子,今天比较忙,下次再说吧");
        }
    }

    public void daqiu(){
        System.out.println("打球");
    }

    //代理对象
    //Binder 是Ibinder 的实现类
    private class MyBinder extends Binder implements Iservice{

        //创建和服务中一样 参数一样的  返回值  不一样 的方法名的 方法
        public void callbanzheng(int money){
            banZheng(money);
        }
        public void calldaqiu(){
            daqiu();
        }
    }
}

在activity中bind服务并调用相应的服务中的方法:

public class MainActivity extends Activity {
    private Iservice iservice;
    private MyServiceConn conn;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //1 创建一个接口
        //2 让mybinder 实现 接口
        //3 接口中  写入 想要暴露的方法
        //4在activity  获取的 就是接口
        //5 使用接口调用代理人对象暴露出来的方法
        Intent service=new Intent();
        service.setClass(this, BanzhengService.class);
        conn = new MyServiceConn();
        bindService(service, conn, BIND_AUTO_CREATE);
    }

    //点击办证
    public void click(View v){
        iservice.callbanzheng(588);
    }

    class MyServiceConn implements ServiceConnection{
        //当服务连接成功的时候调用
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

        iservice = (Iservice) service;
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }
    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        //解绑 服务
        unbindService(conn);
    }
 }

4 混合开启服务

顾名思义,我们可以选择start方式开启服务也可以同时选择bind方式开启服务,当时要注意以下:

先 start 还是 先bind 没有影响但是必须要先 unbind 才能stop

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值