Service Context MVC 简介

2017-06-08 Mystery0 M 更多博文 » 博客 » GitHub »

Android Service Context MVC

原文链接 https://mystery00.github.io/2017/06/08/Service-Context-MVC-%E7%AE%80%E4%BB%8B/
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


service

概述

后台运行,不可见,没有界面。(在activity中完成的事物,在服务中也可以完成)

优先级别高于activity

应用场景:eg:

  1. 后台播放音乐
  2. 后台下载应用
  3. 记录GPS位置 监听某一特定的动作
  4. 处理数据,处理当前不一定及时需要展现给用户的数据
  5. 进入应用时加载本地资源(数据库等) 在后台操作提高交互性
  6. 全家桶唤醒
  7. ……

全家桶

生命周期

创建服务

要创建服务,您必须创建 Service 的子类(或使用它的一个现有子类)。在实现中,您需要重写一些回调方法,以处理服务生命周期的某些关键方面并提供一种机制将组件绑定到服务(如适用)。 应重写的最重要的回调方法包括:

onStartCommand() 当另一个组件(如 Activity)通过调用 startService() 请求启动服务时,系统将调用此方法。一旦执行此方法,服务即会启动并可在后台无限期运行。 如果您实现此方法,则在服务工作完成后,需要由您通过调用 stopSelf() 或 stopService() 来停止服务。(如果您只想提供绑定,则无需实现此方法。) onBind() 当另一个组件想通过调用 bindService() 与服务绑定(例如执行 RPC)时,系统将调用此方法。在此方法的实现中,您必须通过返回 IBinder 提供一个接口,供客户端用来与服务进行通信。请务必实现此方法,但如果您并不希望允许绑定,则应返回 null。 onCreate() 首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或 onBind()之前)。如果服务已在运行,则不会调用此方法。 onDestroy() 当服务不再使用且将被销毁时,系统将调用此方法。服务应该实现此方法来清理所有资源,如线程、注册的侦听器、接收器等。 这是服务接收的最后一个调用。 如果组件通过调用 startService() 启动服务(这会导致对 onStartCommand() 的调用),则服务将一直运行,直到服务使用 stopSelf() 自行停止运行,或由其他组件通过调用 stopService() 停止它为止。

如果组件是通过调用 bindService() 来创建服务(且未调用 onStartCommand()),则服务只会在该组件与其绑定时运行。一旦该服务与所有客户端之间的绑定全部取消,系统便会销毁它。

清单文件Manifest声明service 跟activity以及其它组件一样,你必须在你的应用的manifest文件中声明所有的service。要声明你的service,添加一个<service>标签到<application>标签。例如:

<application……>
        <activity ……>
        </activity>
        <service
            android:name=".MyService">
        </service>
</application>

启动服务

  1. start方式:通过startService启动 访问者与服务之间没有关连,即使访问者退出了,服务仍然运行。 调用create,onstartcommand方法。
  2. bind方式:通过bindService启动 访问者与服务绑定在了一起,访问者一旦退出,服务也就终止。

PS: 如果组件通过调用 startService() 启动服务(这会导致对 onStartCommand() 的调用),则服务将一直运行,直到服务使用 stopSelf() 自行停止运行,或由其他组件通过调用 stopService() 停止它为止。

应用组件(如 Activity)可以通过调用 startService() 方法并传递 Intent 对象 (指定服务并包含待使用服务的所有数据)来启动服务。服务通过onStartCommand() 方法接收此 Intent。

两种方式启动服务的区别: 通过startService()和stopService()启动关闭服务。适用于服务和访问者之间没有交互的情况。如果服务和访问者之间需要方法调用或者传递参数,侧需要使用bindService()和unbindService()方法启动关闭服务。

采用Context.bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onBind()方法,这个时候访问者和服务绑定在一起。一旦该服务与所有客户端之间的绑定全部取消,系统便会销毁它。

如果访问者要与服务进行通信,那么,onBind()方法必须返回Ibinder对象。如果访问者退出了,系统就会先调用服务的onUnbind()方法,接着调用onDestroy()方法。如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法并不会导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。如果访问者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,调用该方法也会导致系统调用服务的onUnbind()-->onDestroy()方法。

停止服务

系统不会停止或销毁service,除非内存不够用了,并且service在onStartCommand()返回后会继续运行.所以,service必须调用stopSelf()停止自己或由另一个组件调用stopService()来停止它。

一旦通过stopSelf()或stopService()发出了停止请求,系统就会尽可能快地销毁service.

然而,同时使用 startService 与 bindService 要注意到,Service 的终止,需要unbindService与stopService同时调用,才能终止 Service,不管 startService 与 bindService 的调用顺序,如果先调用 unbindService 此时服务不会自动终止,再调用 stopService 之后服务才会停止,如果先调用 stopService 此时服务也不会终止,而再调用 unbindService 或者 之前调用 bindService 的 Context 不存在了(如Activity 被 finish 的时候)之后服务才会自动停止。

注意:你的应用在完成工作后停止它所有的service是非常重要的.这可以避免浪费系统资源和消耗电量.如果需要,其它的组件可以调用stopService()停止service.即使你为service启用了绑定,你也必须自己停止service,甚至它收到了对onStartCommand()的调用也这样。

Context

概念

它描述的是一个应用程序环境的信息,即上下文。 该类是一个抽象(abstract class)类,Android提供了该抽象类的具体实现类(后面我们会讲到是ContextIml类)。 通过它我们可以获取应用程序的资源和类,也包括一些应用级别操作,例如:启动一个Activity,发送广播,接收Intent等。

Context相关类的继承关系

Context的类型以及在四大组件中的实现

  • Application - 是一个运行在你的应用进程中的单例。在Activity或者Service中,它可以通过getApplication()函数获得,或者人和继承于context的对象中,通过getApplicationContext()方法获得。不管你是通过何种方法在哪里获得的,在一个进程内,你总是获得到同一个实例。

  • Activity/Service - 继承于ContextWrapper,它实现了与context同样API,但是代理这些方法调用到内部隐藏的Context实例,即我们所知道的基础context。任何时候当系统创建一个新的Activity或者Service实例的时候,它也创建一个新的ContextImpl实例来做所有的繁重的工作。每一个Activity和Service以及其对应的基础context,对每个实例来说都是唯一的。

  • BroadcastReciver - 它本身不是context,也没有context在它里面,但是每当一个新的广播到达的时候,框架都传递一个context对象到onReceive()。这个context是一个ReceiverRestrictedContext实例,它有两个主要函数被禁掉:registerReceiver()和bindService()。这两个函数在BroadcastReceiver.onReceive()不允许调用。每次Receiver处理一个广播,传递进来的context都是一个新的实例。

  • ContentProvider - 它本身也不是一个Context,但是它可以通过getContext()函数给你一个Context对象。如果ContentProvider是在调用者的的本地(例如,在同一个应用进程),getContext()将返回的是Application单例。然而,如果调用这和ContentProvider在不同的进程的时候,它将返回一个新创建的实例代表这个Provider所运行的包。

经验法则

绝大多数情况下,使用在你的所工作的组建内部能够直接获取的Context。只要这个引用没有超过这个组建的生命周期,你可以安全的保存这个引用。一旦你要保存一个context的引用,它超过了你的Activity或者Service的生命周期范围,甚至是暂时的,你就需要转换你的引用为Application context。

实例

浅论一下context : 在语句 AlertDialog.Builder builder = new AlertDialog.Builder(this); 中,要求传递的 参数就是一个context,在这里我们传入的是this,那么这个this究竟指的是什么呢? 这里的this指的是Activity.this,是这个语句所在的Activity的this,是这个Activity 的上下文。网上有很多朋友在这里传入this.getApplicationContext(),这是不对的。 AlertDialog对象是依赖于一个View的,而View是和一个Activity对应的。 于是,这里涉及到一个生命周期的问题,this.getApplicationContext()取的是这个应用程序的Context,Activity.this取的是这个Activity的Context,这两者的生命周期是不同 的,前者的生命周期是整个应用,后者的生命周期只是它所在的Activity。而AlertDialog应 该是属于一个Activity的,在Activity销毁的时候它也就销毁了,不会再存在;但是,如果传 入this.getApplicationContext(),就表示它的生命周期是整个应用程序,这显然超过了它 的生命周期了。 所以,在这里我们只能使用Activity的this。

总结

getApplicationContext() 返回应用的上下文,生命周期是整个应用,应用摧毁它才摧毁。

Activity.this 返回当前activity的上下文,生命周期只是它所在的Activity,activity 摧毁他就摧毁

getBaseContext() 返回由构造函数指定或setBaseContext()设置的上下文。

MVC模型

mvc模型简介 MVC模式(Model–view–controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。 MVC模式最早由Trygve Reenskaug在1978年提出 ,是施乐帕罗奥多研究中心(Xerox PARC)在20世纪80年代为程序语言Smalltalk发明的一种软件架构。MVC模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。除此之外,此模式通过对复杂度的简化,使程序结构更加直观。软件系统通过对自身基本部分分离的同时也赋予了各个基本部分应有的功能。

  • 控制器(Controller)- 负责转发请求,对请求进行处理。
  • 视图(View) - 界面设计人员进行图形界面设计。
  • 模型(Model) - 程序员编写程序应有的功能(实现算法等等)、数据库专家进行数据管理和数据库设计(可以实现具体的功能)。

在android中最典型的MVC就是listview的显示 M:model指你要显示的数据,如封装数据的cursor,array等等 V:view:就是listView用来显示封装好的数据 C:controller:就是adaptor,用来控制数据如何向listview中显示,如arrayadaptor,cursoradaptor等等

MVC好处:从用户的角度出发,用户可以根据自己的需求,选择自己合适的浏览数据的方式。比如说,对于一篇在线文档,用户可以选择以HTML网页的方式阅读,也可以选择以pdf的方式阅读。从开发者的角度,MVC把应用程序的逻辑层与界面是完全分开的,最大的好处是:界面设计人员可以直接参与到界面开发,程序员就可以把精力放在逻辑层上。而不是像以前那样,设计人员把所有的材料交给开发人员,由开发人员来实现界面。在Eclipes工具中开发Android采用了更加简单的方法,设计人员在DroidDraw中设计界面,以XML方式保存,在Eclipes中直接打开就可以看到设计人员设计的界面。

视图层(View):一般采用XML文件进行界面的描述,使用的时候可以非常方便的引入。当然,如何你对Android了解的比较的多了话,就一定可以想到在Android中也可以使用JavaScript+HTML等的方式作为View层,当然这里需要进行Java和JavaScript之间的通信,幸运的是,Android提供了它们之间非常方便的通信实现。

在Android SDK中的数据绑定,也都是采用了与MVC框架类似的方法来显示数据。在控制层上将数据按照视图模型的要求(也就是Android SDK中的Adapter)封装就可以直接在视图模型上显示了,从而实现了数据绑定。比如显示Cursor中所有数据的ListActivity,其视图层就是一个ListView,将数据封装为ListAdapter,并传递给ListView,数据就在ListView中现实。

2.MVC与Android SDK

MVC的基本原理就是通过Controller连接View和Model。也就是说,当View中显示的数据发生变化时,就会通知Controller,而不是直接通知Model,这时Controller接到View的通知后,会在Model中采取相应的动作来修改数据,使用MVC模式可以将数据和显示部分分离,这样修改一方时不会影响另一方,更有利于程序的维护。

在Android SDK中使用MVC的组件非常多,例如,列表控件ListView,GridView,Spinner等都采用MVC模式与数据交互,在Android中MVC中的V就是组件,M就代表着各种数据源,C代表Adapter类,包括BaseAdapter,SimpleAdapter,SimpleCursorAdapter,ArrayAdapter,CursorAdapter等。他们分别对应不同的数据源,这些Adapter都需要使用getView方法返回当前列表项显示的View对象,当Model发生改变的时候调用BaseAdapter.notifyDataSetChanged方法通知组件数据发生变化,这时Adapter会调用getView方法重新显示内容。总之无论是数据还是组件发生变化,都要通过Adapter这个桥梁来达到同步的目的。

参考文章

Android Service详解

android四大组件--android service详解

推荐文章

Android Context 上下文 你必须知道的一切

Android Context完全解析,你所不知道的Context的各种细节

框架模式 MVC 在Android中的使用