Android四大组件-服务

Android服务

android 的服务有点类似windows的服务,没有界面,在后台长时间运行,如果我们这种需求的话我们就可以使用服务来实现。

服务的典型应用场景: 播放音乐,下载等,如果要在一个广播接收者中执行一些耗时的操作,可以将此操作转交给服务来执行。

服务也有自己的生命周期,但是要是相对Activity要少了许多。

服务的生命周期

图片来自于官方文档

https://developer.android.google.cn/images/service_lifecycle.png

使用服务

如果你想要使用服务,那么必须要有一个来继承【Service 】类,并且在清单文件中配置他。

配置服务:在清单文件中对服务进行配置

<!--配置一个服务,与Activity的配置基本相同,都可以具有Intent-Filter-->
<service android:name=".MyService">
    <intent-filter>
        <action android:name="MyAction" />
    </intent-filter>
</service>

建立服务类: 新建一个类继承自Service

public class MyService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

startService 的方式开始服务

  • 一旦开启就会长久的存在,就算是没有界面了那么也会在后台运行,没有界面的时候就会是一个服务进程,如果没有特殊的情况下次进程是不会被结束的,除非 用户手动停止或者调用onStop() 方法。
  • 可以多次开启,如果点击按钮开启服务多次点击按钮的话就会执行多次的onStartCommand方法,但是onCreate方法仅仅执行一次。
  • 用户可以再设置中查看通过此方式开启的服务
public class MainActivity extends AppCompatActivity {
    private Intent intentService;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intentService = new Intent(this, PhoneListenerService.class);
    }
      //开启个服务
    public void click(View v) {
        this.startService(this.intentService);
    }
      //停止服务
    public void click2(View v) {
        this.stopService(this.intentService);
    }

bindService 的方式开启服务

  • 一般在Activity中开启,如果activity销毁了那么通过此方式绑定服务也会跟着销毁在activity销毁之前要先解绑服务
  • 这种方式开启的服务用户在设置中是无法看到的。
public class Main1Activity extends AppCompatActivity {

    private Intent serviceIntent;
    private MyServiceConnection conn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main1);

        serviceIntent = new Intent(this, MyService.class);
        conn = new MyServiceConnection();
    }
    //绑定一个服务
    public void click3(View v) {
        this.bindService(this.serviceIntent, this.conn, BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(this.conn);
    }
}

class MyServiceConnection implements ServiceConnection {
    //当服务连接成功后会调用此方法
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        LogHelper.Logi("连接到服务");
    }
      //当失去连接的时候回调用此方法
    @Override
    public void onServiceDisconnected(ComponentName name) {
        LogHelper.Logi("取消连接");
    }
}

为什么要有Bind方式开启服务

下面我们有这么个需求,我要调用服务里面的方法。

正常的调用方式

服务代码

public class MyService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        LogHelper.LogI("onBind");
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        LogHelper.LogI("onCreate");
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        LogHelper.LogI("onDestory");
    }
    
      //我想在activity中调用的方法
    public void showToast() {
        Toast.makeText(this.getApplicationContext(), "Toast", Toast.LENGTH_SHORT).show();
    }
}

调用代码

public class Main1Activity extends AppCompatActivity {


    private Intent serviceIntent;
    private MyServiceConnection conn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main1);

        serviceIntent = new Intent(this, MyService.class);
        conn = new MyServiceConnection();
        //绑定服务
        bindService(this.serviceIntent, conn, BIND_AUTO_CREATE);
    }

    /*
    * 直接通过new出来对象的方式来调用服务中的方法
    * */
    public void click(View v) {
        new MyService().showToast();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(this.conn);
    }
}

class MyServiceConnection implements ServiceConnection {

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {

    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
}

总结

这样的方式调用service中的方法,就会直接挂掉.....,因为如果这样直接new出来的服务类的话,系统就会将他当成一个普通的java类来处理,在普通的java类中是不能获得上下文对象的,所以就不能弹出吐司,如果没有涉及的上下文的方法,那么这样是可以执行的。

解决办法

通过一个中间人来调用我们想要调用的方法

服务端代码

public class MyService extends Service {
    /*
    * 通过bind方式开启服务 会执行onCreate()->onBind()方法
    * 此方法返回我们需要的中间人,来调用服务中的方法
    * */
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        LogHelper.LogI("onBind");

        return new MyBinder();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        LogHelper.LogI("onCreate");
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        LogHelper.LogI("onDestory");
    }

    //我们想要调用的方法
    public void showToast() {
        Toast.makeText(this.getApplicationContext(), "Toast", Toast.LENGTH_SHORT).show();
    }

    /*
    * 定义中间人
    * 间接的调用我们想要调用的方法
    * */
    public class MyBinder extends Binder {

        public void callShowToast() {
            showToast();
        }
    }
}

Activity代码

public class Main1Activity extends AppCompatActivity {


    private Intent serviceIntent;
    private MyServiceConnection conn;
    private MyService.MyBinder callBinder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main1);

        serviceIntent = new Intent(this, MyService.class);
        conn = new MyServiceConnection();
        //绑定服务
        bindService(this.serviceIntent, conn, BIND_AUTO_CREATE);
    }
    /*
    * 通过定义的中间人来调用方法
    * */
    public void click(View v) {
        this.callBinder.callShowToast();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(this.conn);
    }


    public class MyServiceConnection implements ServiceConnection {
        /*
        * 当连接到服务的时候就会执行此方法,在这个方法拿到我们的中间人用来调用我们想要调用的方法
        * service参数就是我们想要的中间人
        * */
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            callBinder = (MyService.MyBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }
}

混合方式绑定服务

现在有一种情况,如果我要做一个音乐盒的功能那么我必须在所有界面都退出了还能播放那么这时候,我们一定是要有一个startService方式开启的服务来一直播放音乐, 但是我得需要调用服务中的方法来控制音乐的播放和暂停等,这就需要混合方式开启服务了。

混合方式开启服务的步骤

  • startService()
  • bindService()
  • unbiasedServices()
  • stopService()
Demo 音乐播放器 案例

服务的代码

public class MusicService extends Service {
    private boolean isPlay = true;
    private boolean isDestroy = false;

    public MusicService() {

    }

    @Override
    public IBinder onBind(Intent intent) {
        LogHelper.LogI("onBind");
        return new MyBinder();
    }

    @Override
    public void onCreate() {

        LogHelper.LogI("onCreate!");
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        LogHelper.LogI("onStart");
        playMusic();
        return super.onStartCommand(intent, flags, startId);
    }

    //在服务被销毁的时候,结束线程
    @Override
    public void onDestroy() {
        LogHelper.LogI("onDestory");
        this.isDestroy = true;
        super.onDestroy();
    }

    //开启线程不停的播放音乐
    public void playMusic() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (!isDestroy)
                    if (isPlay) {
                        LogHelper.LogI("Play Music!");
                        SystemClock.sleep(1000);
                    }
            }
        }).start();
    }

    //暂停音乐播放
    public void stopMusic() {
        this.isPlay = false;
        LogHelper.LogI("暂停播放音乐!");
    }

    //继续播放音乐
    public void continueMusic() {
        this.isPlay = true;
        LogHelper.LogI("继续播放音乐!");
    }
 
 
    //用来调用服务的方法的中间人
    private class MyBinder extends Binder implements IMusicControlAble {
        @Override
        public void callStopMusic() {
            stopMusic();
        }

        @Override
        public void callContinueMusic() {
            continueMusic();
        }
    }
}

IMusicControlAble接口代码

public interface IMusicControlAble {
    //暂停音乐播放
    public void callStopMusic();
    //继续播放音乐
    public void callContinueMusic();
}

MainActivity的代码

public class Main1Activity extends AppCompatActivity {

    private Intent intentMusicService;
    private MyServiceConnection connMusicService;
    private IMusicControlAble musicControl;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main1);

        intentMusicService = new Intent(this, MusicService.class);
        connMusicService = new MyServiceConnection();

        this.bindService(this.intentMusicService, this.connMusicService, BIND_AUTO_CREATE);
        this.startService(this.intentMusicService);
    }

    public void click(View v) {
        Button btn = (Button) v;
        switch (btn.getText().toString()) {
            case "暂停":
                this.musicControl.callStopMusic();
                btn.setText("播放");
                break;
            case "播放":
                this.musicControl.callContinueMusic();
                btn.setText("暂停");
                break;
        }
    }
    //接触对服务的绑定
    @Override
    protected void onDestroy() {
        this.unbindService(this.connMusicService);
        super.onDestroy();
    }
    
 
    public class MyServiceConnection implements ServiceConnection {

        //拿到用来控制音乐状态的接口
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            musicControl = (IMusicControlAble) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }
}
posted @ 2017-06-15 16:28  鲁迅认识的那只猹  阅读(195)  评论(0编辑  收藏  举报