一篇就够了系列之Service全解析

前言:

一篇就够了系列之Activity全解析中详细介绍了Activity的相关知识点,感兴趣的同学可以看看。本篇文章主要介绍下Service的一些学习感悟,希望能对大家有所帮助。
下面从以下四个部分开展:

  1. Service基础

  2. Service两种启动方式

  3. IntentService

  4. Service各种使用场景

Service基础

定义

Service是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件。(A Service is an application component representing either an application’s desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use)。相对于Activity可以进行操作而言,Service更像是一个在后台默默服务的角色,不可感知,但的的确确存在。作为Android四大组件之一,Service是需要在manifest中进行注册的。

作用

那么,Service可以用来做什么呢?App中最常用到Service的功能应该就是下载和音乐播放等了。包括我们集成第三方的推送服务等等。简单总结起来,Service主要是做不需要依赖UI,长时间运行的一些功能。

Service和Thread的区别

Thread:线程,程序执行的最小单位,是cpu分配资源的基本单位,每个进程可以有N个线程同时运行。
而通过Service的定义我们知道,它和Thread没有任何关联。更多的误解是来自于,Service这个单词的中文意义。实际上,和Activity一样,Service也是运行在主线程中(即UI线程),所以,虽然说,Service常用来执行长时间运行,耗时操作的代码,但是,此时的代码我们必须把其放在一个新的子线程中运行,这样才不回造成线程阻塞(ANR)。

Service的独特之处就在于其可以在程序处于后台的时候,仍然可以继续运行,此时的Activity会处于OnStop或者OnDestory状态,这样,我们的程序就达到了Activity无法执行的功能,Service的价值就体现了出来。

Service两种启动方式

Service的启动需要依赖Activity,并且有两种启动方式。

startService:
Activity代码:

public class ServiceActivity extends AppCompatActivity {

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

        //开启服务
        findViewById(R.id.tv_start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startService(new Intent(ServiceActivity.this,MyService.class));
            }
        });
        //停止服务
        findViewById(R.id.tv_stop).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopService(new Intent(ServiceActivity.this,MyService.class));
            }
        });
    }
}

Service代码:

public class MyService extends Service {

    //第一次进入会调用
    @Override
    public void onCreate() {
        Log.i("wy","oncreate");
        super.onCreate();
    }

    //每次进入都会调用
    @Override
    public int onStartCommand(Intent intent,  int flags, int startId) {
        Log.i("wy","onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.i("wy","onDestroy");
        super.onDestroy();
    }

    //bind启动会调用
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i("wy","onBind");
        return super.onBind(intent);
    }

}

以上代码可以简单总结几点:

  • startService和stopService都是Activity中的方法,并且都是通过Intent进行的跳转。
  • startService调用后,Service中会走onCreate和onStartCommand,如果继续调用startService,此时只有onStartCommand的方法会走,onCreate表示创建,既然已将创建过了对象,此时该方法不会继续走,即使我们把该Activity杀死(注意,不是App杀死),再次进入,仍然如此,说明Service不依赖于该Activity的存在而存在。
  • 只有调用stopService方法,才会走onDestroy,说明此时该Service已经杀死。
  • 事实上,我们可以在其他Activity中调用stopService方法关闭该Service,这也说明了这种启动方式,Service和Activity除了开启和关闭,没有其他任何关心

bindService

Activity代码:

public class ServiceActivity extends AppCompatActivity {

    private MyService.MyBinder mBinder;

    private ServiceConnection mServiceConnection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mBinder= (MyService.MyBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

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

        //开启服务
        findViewById(R.id.tv_bind).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                bindService(new Intent(ServiceActivity.this,MyService.class)
                ,mServiceConnection,BIND_AUTO_CREATE);
            }
        });
        //停止服务
        findViewById(R.id.tv_unbind).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                unbindService(mServiceConnection);
            }
        });
    }
}

Service代码:

public class MyService extends Service {

    private MyBinder mBinder=new MyBinder();

    public class MyBinder extends Binder{
        public void someMethod(){

        }

    }

    //第一次进入会调用
    @Override
    public void onCreate() {
        Log.i("wy","oncreate");
        super.onCreate();
    }

    //每次进入都会调用
    @Override
    public int onStartCommand(Intent intent,  int flags, int startId) {
        Log.i("wy","onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.i("wy","onDestroy");
        super.onDestroy();
    }

    //bind启动会调用
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i("wy","onBind");
        return mBinder;
    }

}

仔细观察可以发现:
- bindService调用,首先会走:oncreate,然后调用onBind,而onStartCommand并不会走,说明这个方法是startActivity这种启动方式特有的。
- bindService(new Intent(ServiceActivity.this,MyService.class),mServiceConnection,BIND_AUTO_CREATE);需要传入三个参数,第一个是Intent,第二个是ServiceConnection,该对象是个interface,有两个抽象方法,其中会回调出IBinder对象,通过MyService代码可以发现,有了IBinder对象,就相当于获取到Service视力,可以调用其中的public的方法,实现了在Activity中调用Service的方法。
- 销毁Activity或者调用unbindService,都会走onDestory方法,这也就切合Bind(绑定)这个词汇,说明该Service和Activity已经绑定在一起,是一对一的关系。

IntentService

可以发现,上面两种方式,各有利弊,如果我们想开启一个任务在后台运行,执行完毕后结束该Service而不需要主动结束。Android中就要这个一个类:IntentService
这是一继承自Service的借口,内部利用Handler机制实现不同线程间交流通信,然后调用stopSelf结束该Service,直接上源码:

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

    //Handler对象
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            //调用我们自己实现的方法,也是需要继承重写的方法
            onHandleIntent((Intent)msg.obj);
            //结束对应startid的任务,全部结束后销毁该Service
            stopSelf(msg.arg1);
        }
    }
    //onStartCommand中调用
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

    //初始化HandlerThread对象,代码是HanderThread对象的标准写法,意义是在子线程中创建了一个Handler,也就是ServiceHandler对象(一般默认生成的Handler对象都是在主线程中)
    @Override
    public void onCreate() {
        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    //在onStartCommand中调用
    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }
    //每次点击startService就会调用该方法
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }
    //Service销毁调用,mServiceLooper.quit(),释放内存,必须
    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }
    //工作线程,可以进行耗时操作
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}

我们的代码:

public class MyIntentService extends IntentService {
    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public MyIntentService() {

        super("MyIntentService");
        Log.i("intentservice","construct");
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        Log.i("intentservice","onHandleIntent");
        try
        {
            //模拟上传耗时
            Thread.sleep(5000);

        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }


    @Override
    public void onCreate() {
        Log.i("intentservice","onCreate");
        super.onCreate();
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Log.i("intentservice","onstart"+startId);
        super.onStart(intent, startId);
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        Log.i("intentservice","onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i("intentservice","onDestroy");
    }

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

连续6下点击startService,Log为:

construct
onCreate
onStartCommand
onstart1
onHandleIntent
onStartCommand
onstart2
onStartCommand
onstart3
onStartCommand
onstart4
onStartCommand
onstart5
onStartCommand
onstart6
onHandleIntent
onHandleIntent
onHandleIntent
onHandleIntent
onHandleIntent
onDestroy

大家可以尝试运行,打印Log加深理解

Service各种使用场景及tips

  • IntentService:很明显,这种service的用途会很广泛,比如我们进行图片下载,退出应用时一些状态的保存,甚至是启动页中需要初始化的一些耗时的代码
  • startService和bindService可以混用,只需要记住一点:startService只是启动一个Service,与启动者没有关联,杀死必须要调用stopService或者是stopself,bindService依赖于调用者,当调用者销毁后,它也会跟着销毁。
  • service的调用者有Activity,Service和ContentProvider
  • 在后台运行的service在系统资源紧张的情况下还是会被系统回收,为了提高优先级,我们可以使用前置Service,比如我们骑共享单车的的通知栏:
    @Override
    public void onCreate() {
        Log.i("wy","oncreate");
        super.onCreate();

        //获取NotificationManager实例
        NotificationManager notifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        //实例化NotificationCompat.Builde并设置相关属性
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                //设置小图标
                .setSmallIcon(R.mipmap.ic_launcher)
                //设置通知标题
                .setContentTitle("最简单的Notification")
                //设置通知内容
                .setContentText("只有小图标、标题、内容");
        //设置通知时间,默认为系统发出通知的时间,通常不用设置
        //.setWhen(System.currentTimeMillis());
        //通过builder.build()方法生成Notification对象,并发送通知,id=1
        Notification notification=builder.build();
        notifyManager.notify(1, notification);


        startForeground(1, notification);

    }

效果图为:

这里写图片描述

Notication的知识点可以翻墙看Google官方文档Notification,全中文

差不多就这些了,期待大家的留言!
一篇就够了系列之Activity全解析

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值