[Android每日精彩]Service

Q1.知道Service吗,它有几种启动方式?

Service是一个专门在后台处理长时间任务的Android组件,它没有UI。
当应用程序被挂到后台的时候,问了保证应用某些组件仍然可以工作,Service不是独立的进程,
也不是独立的线程,它是依赖于应用程序的主线程的,也就是说,在更多时候不建议在Service中编写
耗时的逻辑和操作,否则会引起ANR。
它有两种启动方式,startService和bindService。

Q1.1如果不适合直接在service中做耗时操作,那对于耗时逻辑我们应该怎么处理?

当我们编写的耗时逻辑,不得不被service来管理的时候,就需要引入IntentService。 --> Q6

Q2.这两种启动方式的区别?

1.startService只是启动Service,启动它的组件(如Activity)和Service并没有关联,
只有当Service调用stopSelf或者其他组件调用stopService服务才会终止。
2.bindService方法启动Service,其他组件可以通过回调获取Service的代理对象和Service交互,
而这两方也进行了绑定,当启动方销毁时,Service也会自动进行unBind操作,当发现所有绑定
都进行了unBind时才会销毁Service

Q2.1什么时候使用startService,什么时候使用bindService?

启动状态,主要用于执行后台计算;
绑定状态,主要用于其它组件和Service的交互

Q3.两种启动方式对Service生命周期函数影响?

service_life.png

Q4.Service的onCreate回调函数可以做耗时的操作吗?

不可以,因为Service的onCreate是在主线程(ActivityThread)中调用的,耗时操作会阻塞UI。

Q5.如果需要做耗时的操作,你会怎么做?

1.线程和Handler方式 
2.Q1.1使用IntentService --> Q6

Q6.是否知道IntentService,在什么场景下使用IntentService?

当我们编写的耗时逻辑,不得不被service来管理的时候,就需要引入IntentService,
IntentService是继承Service的,那么它包含了Service的全部特性,
当然也包含service的生命周期,那么与service不同的是,IntentService在执行onCreate操作
的时候,内部开了一个线程,去你执行你的耗时操作。

Q6.1IntentService的原理

IntentService中提供了这么一个方法:
protected abstract void onHandleIntent(Intent intent);
这是一个抽象方法,也就是说具体的实现需要被延伸到子类。

onHandleIntent()方法是什么时候被调用的呢?让我们具体看IntentService的内部实现:
private final class ServiceHandler extends Handler {  
    public ServiceHandler(Looper looper) {  
        super(looper);  
    }  
  
    @Override  
    public void handleMessage(Message msg) {  
        onHandleIntent((Intent)msg.obj);  
        stopSelf(msg.arg1);  
    }  
}  
  
public IntentService(String name) {  
    super();  
    mName = name;  
}  
  
public void setIntentRedelivery(boolean enabled) {  
    mRedelivery = enabled;  
}  
  
@Override  
public void onCreate() {  
   
    super.onCreate();  
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");  
    thread.start();  
  
    mServiceLooper = thread.getLooper();  
    mServiceHandler = new ServiceHandler(mServiceLooper);  
}  
  
@Override  
public void onStart(Intent intent, int startId) {  
    Message msg = mServiceHandler.obtainMessage();  
    msg.arg1 = startId;  
    msg.obj = intent;  
    mServiceHandler.sendMessage(msg);  
}  
IntentService在执行onCreate的方法的时候,其实开了一个线程HandlerThread,并获得了当前
线程队列管理的looper,并且在onStart的时候,把消息置入了消息队列:
@Override  
public void handleMessage(Message msg) {  
       onHandleIntent((Intent)msg.obj);  
       stopSelf(msg.arg1);  
}  
在消息被handler接受并且回调的时候,执行了onHandlerIntent方法,该方法的实现是子类去做的。
我们可以得出这样的结论:IntentService是通过Handler looper message的方式实现了一个
多线程的操作,同时耗时操作也可以被这个线程管理和执行,同时不会产生ANR的情况。

Q6.2使用intentService与service有什么不同呢?(好处)

1.直接 创建一个默认的工作线程,该线程执行所有的intent传递给onStartCommand()以区别于
应用程序的主线程
2.直接创建一个工作队列,来逐个发送intent给onHandleIntent()
多线程
3.当请求完成后自己会调用stopSelf(),所以你就不用调用该方法了
4.提供的默认实现onBind()返回null,所以也不需要重写这个方法
5.默认实现的onStartCommand()的目的是将intent插入到工作队列中

我们需要做的就是实现onHandlerIntent()方法,还有,构造函数是必需的,而且必须调用
超IntentService(字符串) ,因为工作线程的构造函数必须使用一个名称
  public HelloIntentService() {
      super("HelloIntentService");
  }
那么它为什么不用stopself()方法呢?因为handlerMessage方法里当处理完请求后就会调用
stopself()方法了,外界就不用调用了:
@Override  
public void handleMessage(Message msg) {  
       onHandleIntent((Intent)msg.obj);  
       stopSelf(msg.arg1);  
}

Q7.工作场景:如果一个应用要从网络上下载MP3文件,并在Activity上展示进度条,这个Activity要求是可以转屏的。那么在转屏时Actvitiy会重启,如何保证下载的进度条能正确展示进度呢?

错误方法:
(1)在转屏前将进度缓存,转屏后再读出来。
(2)使用android:configChanges设置,让转屏时Activity不销毁和重建
针对第1个方案,我会继续问他将进度值存在哪里? 转屏的过程中,我们知道Activity的重建
算是比较耗时的,会可能会有几百毫秒以上,那么这时候下载线程仍然在工作,进度肯定和保存时的进度
不一致了,如何处理这个问题呢?
第2个方案,大家可以自己展开思考,实际的项目中可能会需要额外做一些事情来处理ContentView
的横竖布局的问题。

如果使用Service来解决这个问题,看似是比较完美的,不过就会涉及Activity(UI)和 Service
的交互问题

Q7.1工作场景:如果我们有一个后台服务,是每隔一段时间请求一次服务器,类似于心跳服务,只是没有心跳服务那么频繁,例如每2个小时执行一次连接服务器操作,这样的话,我们的应用可能已经退出了,而我们仍需要这个服务时开启的,如何实现呢?

链接

思路:重写一个IntentService,仿效系统的IntentService,只是让线程执行完毕的时候,
不再销毁这个Service(也就是删掉源码中的stopSelf语句,那么就不会出现销毁这个Service了),
那么这样这个Service就能够长时间运行下去,同时不用独立创建AsyncTask和Runable了,同时
可以直接在onHandleIntent中执行一些长时间的联网操作了

Q8.对Service的认识,什么时候选择使用service(使用场景)?

当我们知道了Service的用途,心中有一个Service相关的概念时,针对实际的场景还是要做具体的分析
再决定是否使用Service。因为Service仍然是在主线程中调用,还是要开线程才能处理长时间的工作,
Service和UI的交互也让这个方式变得不那么简便。如果你只需要在当前界面去做一些耗时操作,
界面退出或改变时,工作也要停止,那么这时直接使用Thread(或者AsyncTask, ThreadHandler)
会更合适你
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,874评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,151评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,270评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,137评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,116评论 5 370
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,935评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,261评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,895评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,342评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,854评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,978评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,609评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,181评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,182评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,402评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,376评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,677评论 2 344

推荐阅读更多精彩内容