Service基础知识

Service是什么?

Service是一个一种能够长时间在后台运行并没有用户界面的应用组件。

Service和Thread的区别

Service翻译成中文就是“服务”,也许有人会认为服务就是能在后台执行耗时操作的,那就大错特错了,Service是运行在主线程的,如果超过20秒还未处理完成则Android系统就会报ANR错误,即应用未响应。
下面我们来验证一下,首先在Android Studio中创建一个MainActivity,再创建一个Service,在MainActivity中启动Service,并打印它们各自的所在的线程。

public class MainActivity extends BaseActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void setContentView() {
        setContentView(R.layout.activity_main);
        //这里打印所在线程
        Log.d(TAG, "Thread is" + Thread.currentThread().getName());

    }

    @Override
    protected void initView() {

    }



    @Override
    protected void initData() {
        Intent intent = new Intent(MainActivity.this,MyService.class);
        startService(intent);
    }
}
public class MyService extends Service {
    private static final String TAG = "MyService";
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        //这里打印所在线程
        Log.d(TAG, "Thread is" + Thread.currentThread().getName());
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

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

运行后的结果如下图。


2018-01-14_140359.png

可以看出Service确实是运行在主线程中的,那么我们就不应该在Service中执行耗时的操作了,应该在子线程中执行耗时的操作。

Service的启动方式

Service一共有两种启动方式,一个是startService,另一个是bindService

startService方法启动

这种方式启动service比较简单和启动一个activity差不多,步骤如下:

  1. 创建一个service,并在AndroidManifest文件中进行注册(使用Android Studio自动生成的可忽略)
  2. 在Activity中创建Intent intent = new Intent(MainActivity.this,MyService.class); startService(intent);
    具体代码如下:
public class MainActivity extends BaseActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void setContentView() {
        setContentView(R.layout.activity_main);
        Log.d(TAG, "Thread is " + Thread.currentThread().getName());

    }

    @Override
    protected void initView() {

    }



    @Override
    protected void initData() {
        //启动服务
        Intent intent = new Intent(MainActivity.this,MyService.class);
        startService(intent);
    }
}

启动服务后依次会调用service中的onCreate->onStartCommand方法,其中onCreate只会调用一次,如果重新启动service的话,会重新调用onStartCommand方法。

onStartCommand方法的返回值

onStartCommand是有返回值的,返回值类型为int

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

通过看源码可以发现返回值有两个类型,分别是START_STICKY_COMPATIBILITY和START_STICKY

  1. START_STICKY_COMPATIBILITY:如果返回该值则不保证服务被杀死后会重新启动。
  2. START_STICKY:如果返回该值则服务在启动后被杀死会重新启动,会重新调用onStartCommand方法。
public @StartResult int onStartCommand(Intent intent, @StartArgFlags int flags, int startId) {
        onStart(intent, startId);
        return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
    }

默认返回的是START_STICKY。

在service内部给activity创建启动服务的方法

在看Tinker的源码过程中发现,可以在service内部给activity创建启动服务的方法,代码如下,这样的好处就是提高了代码的封装性。

 //对外提供启动servcie方法
    public static void runService(Context context) {
        try {
            Intent intent = new Intent(context, MyService.class);
            context.startService(intent);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

bindService方法启动

bindService启动的service会将service与activity绑定,activity销毁了service也就停止了,步骤如下:

  1. 创建BindService服务端,继承自Service类,并在类中创建一个实现IBinder接口的实例对象并提供公共方法给客户端来调用。
  2. 从onBind方法回调方法返回此Binder实例
  3. 在客户端中,从onServiceConnected回调方法接收Binder,并使用提供的方法调用绑定服务。
    代码如下:
public class MyService extends Service {
    private static final String TAG = "MyService";
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // 返回IBinder对象
        return new MyBinder();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "Thread is " + Thread.currentThread().getName());
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }
    //给客户端提供服务的实例,从而可以来调用服务里的方法
    public class MyBinder extends Binder {

        public MyService getService(){
            return MyService.this;
        }
    }
    public void execute(){
        Log.d(TAG, "activity 调用 service 里的方法成功");
    }
}

public class MainActivity extends BaseActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void setContentView() {
        setContentView(R.layout.activity_main);
        Log.d(TAG, "Thread is " + Thread.currentThread().getName());

    }

    @Override
    protected void initView() {

    }



    @Override
    protected void initData() {
        Intent intent = new Intent(MainActivity.this,MyService.class);
        //绑定服务
        bindService(intent,serviceConnection,BIND_AUTO_CREATE);
    }

    ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //服务连接成功调用
            Log.d(TAG, "service 连接成功");
            MyService myService = ((MyService.MyBinder)service).getService();
            myService.execute();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            //服务断开连接调用

        }
    };
}

运行结果如下图。


2018-01-14_144844.png

bindService执行的服务里方法的顺序如下:
onCreate->onBind->(Activity)onServiceConnected
通过绑定服务我们可以完成activity和service之间的通信,当然也可以使用广播。
欢迎大家来我的博客逛逛:http://yangchendev.top/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容