随笔4

  • Service 在后台运行, 没有界面. 

      在一个应用程序中, 我们通过 AndroidManifest.xml 中的 <service> 配置服务, 注意它跟<Activity> 是同级的.

<manifest .....> <application ....> <activity ..> ........... </activity> <activity ..> ........... </activity> <service android:name=".CountService" /> <service ...> <intent-filter> .......... </intent-filter> </service> </application> </manifest>

      在同一个应用程序中, 每个 Activity 和 Service 都是在 Main Thread 中运行的, 不存在多开一个线程(自己写个例子, 调试一下就很清楚了). 当然, 如果Service 里面的操作是耗时长的, 那在Service 里面手动开多一条线程执行这些耗时长的操作. 还有另一个办法是使用 IntentService 类, 它是Service 类的子类, 拥有自己的线程.

 

 

      虽然是 Service 运行时是看不到界面的, 但是它有两个方法 startForeground(int, Notification) 和 stopForeground (boolean) (1.5才有的)分别设置 Service 的 前台状态和取消 Service 的前台状态. 可能你会说了, Service 不是没有界面吗, 那什么是他的前台呢? 通过 Notification 对象, 我们可以把在前台的 Service 显示在状态栏上. 前台到后台, 就是一个优先级的变化, 优先级低的, 在资源不足的情况下, 很有可能给杀掉.

 

 

    在应用程序中, 如果它启动了一些Service, 在Service 没停止前, 应用程序是关闭不了的. 我测试的时候是这种情况.

 

 

    Service 有两种生命周期, 这两种生命周期是通过不同的方式启动的

  • Context.startService()-> onCreate() -> onStartCommand(Intent, int, int) -> Context.stopService()或 stopSelf() -> onDestroy() 
  • Context.bindService()-> onCreate() -> onBind(Intent) -> Context.unbindService() -> onUnbind() -> onDestroy()

     多次调用 startService() 是不违法的(但是此举将导致 onStartCommand() 会被多次调用), 不管调用多少次startService () ,只需要调用一次 stopService () 或 stopSelf() 就可以停止service .

      Services 可以使用 stopSelf(int startId) 来确保自己不会被停止, 直到 startId 对应的Intent 被处理.

      如果没有startService,而调用stopservice不会出错.
      如果没有bindservice而调用unbindservice就会出错.

 

 

       他们的一些用途

  • startService 不用跟其他组件(如Activity) 交互. Service 类的 onBind(Intent) 方法可以不予理会.
  • bindService  跟应用程序内部的其他组件交互. Service 类 的 onBind(Intent) 方法必须返回一个 Binder 对象, 并且必须有一个 ServiceConnection 对象,
  • bindService 跟其他应用程序的组件交互. 研究不多, 貌似和第二个很像.

      刚开始, 看了网上广为流传的 CountService 例子和官方的 LocalService 等例子, 看 CountService 例子前部分, 我觉得使用 Service 很简单. 但是转到中间部分, 多了接口, 多个 binder 类, 多个什么connection, 代码一下子多了很多, 像我这种能力低下的人一看, 傻眼了.

      ICountService 出现了, CountService 实现它, ServiceBinder也实现它! 咋那么眼熟呢? 代理模式?????? serviceConnection服务连接, 哇, 难道跟数据库一样, 建立连接再操作吗? 

      带着疑问, 在看看官方的例子, LocalService 用于startService 和 bindService, 它的 onBind() 返回了一个 Binder对象, 这里没有用到接口, 第一个疑问算是解开了! LocalService 例子的 ServiceConnection 对象没做啥操作, 但是在它的 onServiceConnected() 方法竟然把 LocalService 对象传了过来, 有点乱来呢! 再看回 CountService 的例子, ServiceConnection 对象 的 onServiceConnected() 方法竟然也把 CountService 对象传了过来, 再看清一点, 原来不是 CountService 对象, 是接口 ICountService 的实现对象. 

 

      到这里有点豁然开朗了, Binder 对象是Service 和 Activity 交互中Service的信息和服务的提供者, 而 ServiceConnection 对象是 Service 和 Activity交互的一条连接通道, 它提供了一个地方--onServiceConnected 让两个组件进行交互, 并定义其交互规则.

       把 Binder 和 ServiceConnection 类的作用搞清楚后, 把这两者过滤一下, 我们发现startService 和 bindService 其他地方基本都一样了.

 

 

      bindService很像观察者模式 , 被观察者是Service, Binder对象是其notifyObservers(Object arg)方法中的参数;观察者是Activity, ServiceConnection 发挥了update()方法的功能, Context.bindService() 方法等同于 被观察者.addObserver(Observer o).

      跟传统观察者模式不同的地方是, 这里是观察者主动去观察, 而不是被动观察. 再想想, 如果需要被动观察的效果, 又要怎么做呢?

 

      ServiceConnection 的回调方法onServiceDisconnected() 在连接正常关闭的情况下是不会被调用的, 该方法只在Service 被破坏了或者被杀死的时候调用. 例如, 系统资源不足, 要关闭一些Services, 刚好连接绑定的 Service 是被关闭者之一,  这个时候 onServiceDisconnected() 就会被调用.

 

 

 

 

你可能感兴趣的:(随笔4)