Android基础篇:

2017-02-09  本文已影响0人  誰許誰天荒

1.Android简介:

   对于android,首先我们要知道它是一种基于liunx的自由开源的操作系统,它的开发语言是java,开发工具可以选择Eclipse和android studio。每一个android应用程序都拥有一个独立的Dalvik虚拟机实例(也叫dvm,是Google公司自己设计用于andriod平台的java虚拟机), 应用程序都在它自己的进程中运行,而每一个dvm都是在liunx的一个进程,独立的进程可以防止在虚拟机崩溃的时候所有程序都会关闭。另外我们需要AndroidSDK工具将我们的代码和资源文件编译成一个apk,才能在android设备上安装。

2.Android的优点和不足:

优点:

(1)开放性,开源,免费,可定制

(2)挣脱运营商束缚

(3)丰富的硬件选择

(4)不收任何限制的开发商

(5)无缝结合的Google应用

缺点:

(1)安全问题

(2)同质化严重

(3)运营商对Android手机仍然有影响

(4)山寨化严重

(5)过度依赖开发商,缺乏标准配置

  1. Android三大模块:应用组件,清单文件,资源文件

    Android是由应用组件,清单文件和资源文件这三块构成的。
    

(1)应用组件:

   首先是应用组件,android有四大组件,分别是Activity,Service,ContentProvider,BroadcastReceiver。这些组件都有自己的生命周期方法,我们可以通过重写他们的生命周期方法来管理和使用它们。另外,这些组件要想使用,就必须在清单文件里面注册,才能被系统识别。Activity是用户与app交互的桥梁,也是用户可见的东西,关于activity详见下面的Activity篇。Service是app在后台运行的组件,它没有界面,所以也可以称它为"不可见的activity"它用来执行长时间的操作,它可以在activity中开启,开启服务有两种方式,一种是通过startService()直接开启,这种开启方式即使是activity销毁,服务也不会停止。另外一种方式是通过bindService()绑定服务,服务可以被多个组件进行绑定,只要一个组件绑定服务,绑定的服务会运行,但是只有所有绑定服务的组件全部取消绑定的时候,服务才会被销毁。绑定服务还有一个好处,那就是可以在绑定服务的组件中调用服务里面的方法。此外,还有一个特别好用的类IntentService,通过这个类开启服务有两个好处,一个是它会另外开启一个线程,另外一个是不用手动stopService,它在处理完所有请求后会自动停止服务。

    内容提供者ContentProvider可以看做是一个数据的一个封装,它可以实现跨进程通信,一个进程可以通过它访问甚至修改另外一个进程中存储的数据。广播是android中传输信息的机制,只要是发送广播的action和接收广播的action相同,接受者就能够接收这个广播,然后做出一系列处理,比如在服务中要通知activity更新UI就可以使用广播。发送广播是用sendBroadcast这个方法来发送的。而广播接受者则是要先进行注册,注册广播接受者有两种方式,一种是静态注册,一种是动态注册,静态注册就是在xml中指定,而动态注册则是在程序中注册,它们的作用范围不一样,动态注册只是在程序运行过程中起作用,而静态注册则是不管你的程序有没有启动都会起作用。

四大组件之中,Activity,Service,广播接收者这三个组件都是通过Intent进行通信的。可以通过将Intent传递到startActivity(),startActivityForResult(),startService(),bindService(),sendBroadcast()来进行各组件之间的通信。

(2)清单文件:

   上面已经提到,android四大组件都要在清单文件进行注册才能够使用,那是因为android系统是通过清单文件确认组件存在的。清单文件不仅仅只有声明组件的作用,还有其他用途,比如,声明应用所需的最低API级别,声明应用所需要的软件和硬件的功能。Android提供一种安全机制就是在app中加入一些权限,而这些权限的声明也是在清单文件中。

(3)资源文件:

   我们在进行android开发的时候,除了代码,还需要一些资源,比如说图片,视频等。这些资源对应相应的目录,这些目录可以进行屏幕的适配。除此之外,android对于项目中的每一项资源,SDK都会定义一个唯一的整形ID,我们通常把它们叫做R文件,我们可以利用这些资源ID来引用这些应用资源。

Activity篇:

**1. ** 什么是activity:

   关于activity,首先我们要知道它是什么,它其实是android的一个应用组件,是用户与我们的应用程序最直接的交互手段。更直白一点来说,它其实就是一个屏幕,它能显示一些我们可以看得到的控件,响应用户对屏幕所做的操作。通常一个app是由多个activity组成的,因此app中要有一个主activity,它是我们的应用程序第一次启动时呈现给用户的界面。Activity的数据结构采用的是堆栈的形式即"先进后出"。,当一个新的activity启动的时候,会进栈,当一个activity销毁的时候会从栈顶弹出。此外,activity作为一个用户组件,有很多状态,比如创建,启动,停止,销毁等等,我们可以通过回调activity的生命周期方法来改变它的状态(如何做下文会阐述)。
  1. 怎么使用activity:

    既然我们知道了什么是activity,我们必须要知道怎么使用activity,在开始使用之前,我们要先创建一个activity,java是面向对象的语言,丰富的类机制使我们的开发变得简单,activity既然是android的一个组件,因此android给我们提供了Activity这个类,我们要写自己的activity,继承它就可以了,但是这还不够,我们必须在我们的清单文件中声明我们的activity,这样系统才能访问它。在声明activity的时候,android:name是唯一的必须要指定的特性,其他的特性比如这个activity的风格或者主题都可以自己指定。
    
    接下来我们要就可以通过回调activity的几个生命周期方法对activity进行管理,也就是上文所说的改变它的状态。onCreate()方法是必须要实现的方法,它是用来创建activity的,在这个方法里,我们可以进行一些初始化的操作,将布局文件xml绑定到这个activity中。通过setContentView()方法。实现布局绑定之后我们就可以找到布局中带有id标识的控件,来响应用户操作。onStart()方法是用来启动activity,onResume()方法是将activity对用户可见,从数据结构上说是将这个activity置于栈顶。并具有用户输入焦点。onPause()是用来将activity转入后台,此时activity是可见的,但是没有用户的输入焦点。onStop()方法是将activity不可见。onDestroy()是用来销毁activity的。我们知道了走完每个生命周期方法之后activity所处的状态,就可以通过重写这些生命周期方法来达到我们管理activity的目的。
    
    很多情况下我们需要各个activity协同合作才能完成一个app的功能,这个时候activity必须要实现通信,例如activity之间的跳转,activity之间传递数据等等。从一个activity跳转到另一个activity有两种方法,第一种方法叫做显示启动,直接创建一个intent对象,在这个对象里指定要跳转到的activity,还可以携带要传递的数据,然后通过调用startActivity()方法实现跳转。另一种方法叫做隐士启动,它是在要跳转到的activity中增加一个intent过滤器,过滤器里面有个action我们在跳转到这个activity的时候只需要创建的intent中的内容与action匹配上就可以实现跳转,这种隐士启动比较适合我们启动系统的activity,比如说打开图库,摄像头等等。Activity通信的时候,我们可能不仅仅要第一个activity向第二个activity传递数据,也有可能需要从第二个页面获取结果,这个时候startActivity就不能满足需求了。遇到这种情况,我们可以调用startActivityForResult()来启动activity,然后在onActivityResult()来收到后续activity的结果,在这里有两个重要的常量,一个是请求码requestCode,一个是resultCode。只有两个都匹配的时候才能收到后续结果。
    
  2. 如何保存activity的状态:

    有的时候我们需要保存activity的状态,我们可以通过调用onSaveInstanceStates()来实现,但是它只能保存activity的瞬态,不能存储持久化的数据,这些持久化的数据应该在onPause()中保存到数据库或者sp中。
    
  3. 横竖屏切换时Activity的生命周期

    此时的生命周期跟清单文件里的配置有关系。
    

    (1)不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,默认首先销毁当前的activity,然后重新加载。

    (2)设置Activity的android:configChanges="orientation|keyboardHidden|screenSize"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法。

    通常在游戏开发,屏幕的朝向都是写死的。
    

系统权限篇:

  1. Android安全机制简介:

    Android安全模型主要提供以下几种安全机制:
    

(1) 进程沙箱隔离机制,android是一个权限分离的系统,这是利用liunx已有的权限管理机制,通过为每一个application分配不同的uid和gid,从而使不同的application逐渐的私有数据和访问达到隔离的目的。但是在有些情况下,进程之间还可以存在相互信任的关系,如果是同一开发者的应用程序,可以通过android提供的共享uid机制,使得具备信任关系的应用程序可以运行在同一进程空间。

(2) 应用程序签名机制,规定apk文件必须被开发者进行数字签名,以便标识应用程序作者和在应用程序之间的信任关系。在安装应用程序APK时,系统安装程序首先检查APK是否被签名,有签名才能安装。当应用程序升级时,需要检查新版应用的数字签名与已安装的应用程序的签名是否相同,否则,会被当做一个新的应用程序。Android开发者有可能把安装包命名为相同的名字,通过不同的签名可以把他们区分开来,也保证签名不同的包不被替换,同时防止恶意软件替换安装的应用。

(3) 权限声明机制,要想获得在对象上进行操作,就需要把权限和此对象的操作进行绑定。不同级别要求应用程序行使权限的认证方式也不一样,Normal级申请就可以使用,Dangerous级需要安装时由用户确认,Signature和Signatureorsystem级则必须是系统用户才可用。

(4) 访问控制机制,Android是基于liunx内核的,因此liunx对文件权限的控制同样适用于android,在android中每个应用都拥有自己的/data/data/包名 文件夹,该文件夹只能该应用访问,而其他应用则无权访问。

(5) 进程通信机制,基于共享内存的Binder实现,提供轻量级的远程进程调用(RPC)。通过接口描述语言(AIDL)定义接口与交换数据的类型,确保进程间通信的数据不会溢出越界。

(6) 内存管理机制,基于Linux的低内存管理机制,设计实现了独特的LMK,将进程重要性分级、分组,当内存不足时,自动清理级别进程所占用的内存空间。同时,引入的Ashmem内存机制,使得Android具备清理不再使用共享内存区域的能力。

  1. Android权限机制:

(1)Android权限概述

     Android系统中权限分为普通级别(Normal),危险级别(dangerous),签名级别(signature)和系统/签名级别(signature or system)。系统中所有预定义的权限根据作用的不同,分别属于不同的级别。对于普通和危险级别的权限,我们称之为低级权限,应用申请即授予。其他两级权限,我们称之为高级权限或系统权限,应用拥有platform级别的认证才能申请。当应用试图在没有权限的情况下做受限操作,应用将被系统杀掉以警示。系统应用可以使用任何权限。权限的声明者可无条件使用该权限。目前Android系统定义了许多权限,通过SDK文档用户可以查询到哪些操作需要哪些权限,然后按需申请。为了执行你自己的权限,你必须首先在你的AndroidManifest.xml中使用一个或多个<permission> 标签声明。

(2)使用权限

     应用需要的权限应当在users-permission属性中申请,所申请的权限应当被系统或某个应用所定义,否则视为无效申请。同时,使用权限的申请需要遵循权限授予条件,非platform认证的应用无法申请高级权限。

所以,程序间访问权限大致分为两种:

    第一种低级点的(permission的protectlevel属性为normal或者dangerous),其调用者apk只需声明<uses-permission>即可拥有其permission。

    第二种高级点的(permission的protectlevel属性为signature或者signatureorsystem),其调用者apk就需要和被调用的apk一样拥有相同的signature。

应用程序安装的时候,应用程序请求的permissions是通过package installer来批准获取的。package installer是通过检查该应用程序的签名来确定是否给予该程序request的权限。在用户使用过程中不会去检查权限,也就是说要么在安装的时候就批准该权限,使其按照设计可以使用该权限;要么就不批准,这样用户也就根本无法使用该feature,也不会有任何提示告知用户尝试失败。例如高级权限用有system级别权限设定的api时,需要使其apk拥有system权限。比如在 android 的API中有供给SystemClock.setCurrentTimeMillis()函数来修改系统时间。

(3)自定义权限

   Android系统定义的权限可以在Manifest.permission中找到。任何一个程序都可以定义并强制执行自己独有的permissions,因此Manifest.permission中定义的permissions并不是一个完整的列表(即能有自定义的permissions)。一个特定的permission可能会在程序操作的很多地方都被强制实施:

    当系统有来电的时候,用以阻止程序执行其它功能。

    当启动一个activity的时候,会阻止应用程序启动其它应用的Acitivity。

在发送和接收广播的时候,去控制谁可以接收你的广播或谁可以发送广播给你。

    当进入并操作一个content provider的时候。

当绑定或开始一个service的时候。

(4)组件权限

     通过 AndroidManifest.xml 文件可以设置高级权限,以限制访问系统的所有组件或者使用应用程序。所有的这些请求都包含在你所需要的组件中的 android:permission属性,命名这个权限可以控制访问此组件。

a) Activity 权限 (使用 <activity> 标签) 限制能够启动与 Activity 权限相关联的组件或应用程序。在 Context.startActivity() 和 Activity.startActivityForResult() 期间检查;

b) Service 权限(应用 <service> 标签)限制启动、绑定或启动和绑定关联服务的组件或应用程序。此权限在 Context.startService(), Context.stopService() 和 Context.bindService() 期间要经过检查;

c) BroadcastReceiver 权限(应用 <receiver> 标签)限制能够为相关联的接收者发送广播的组件或应用程序。在 Context.sendBroadcast() 返回后此权限将被检查,同时系统设法将广播递送至相关接收者。因此,权限失败将会导致抛回给调用者一个异常;它将不能递送到目的地。在相同方式下,可以使 Context.registerReceiver() 支持一个权限,使其控制能够递送广播至已登记节目接收者的组件或应用程序。其它的,当调用 Context.sendBroadcast() 以限制能够被允许接收广播的广播接收者对象一个权限(见下文)。

d) ContentProvider 权限(使用 <provider> 标签)用于限制能够访问 ContentProvider 中的数据的组件或应用程序。

如果调用者没有请求权限,那么会为调用抛出一个安全异常( SecurityException )。在所有这些情况下,一个SecurityException异常从一个调用者那里抛出时不会存储请求权限结果。

(5)发送广播时支持权限

     当发送一个广播时你能总指定一个请求权限,此权限除了权限执行外,其它能发送Intent到一个已注册的BroadcastReceiver的权限均可以。通过调用Context.sendBroadcast()及一些权限字符串,为了接收你的广播,你请求一个接收器应用程序必须持有那个权限。注意,接收者和广播者都能够请求一个权限。当这样的事发生了,对于Intent来说,这两个权限检查都必须通过,为了交付到共同的目的地。

(6)其它权限支持

     在调用service的过程中可以设置任意的fine-grained permissions(更为细化的权限)。这是通过Context.checkCallingPermission()方法来完成的。使用一个想得到的permission string来进行呼叫,然后当该权限获批的时候可以返回给呼叫方一个Integer(没有获批也会返回一个Integer)。需要注意的是这种情况只能发生在来自另一个进程的呼叫,通常是一个service发布的IDL接口或者是其他方式提供给其他的进程。

Android提供了很多其他的方式用于检查permissions。如果你有另一个进程的pid,你就可以通过Context的方法Context.checkPermission(String, int, int)去针对那个pid去检查permission。如果你有另一个应用程序的package name,你可以直接用PackageManager的方法 PackageManager.checkPermission(String, String) 来确定该package是否已经拥有了相应的权限。

(7)URI权限

     到目前为止我们讨论的标准的permission系统对于content provider来说是不够的。一个content provider可能想保护它的读写权限,而同时与它对应的直属客户端也需要将特定的URI传递给其它应用程序,以便其它应用程序对该URI进行操作。一个典型的例子就是邮件程序处理带有附件的邮件。进入邮件需要使用permission来保护,因为这些是敏感的用户数据。然而,如果有一个指向图片附件的URI需要传递给图片浏览器,那个图片浏览器是不会有访问附件的权利的,因为他不可能拥有所有的邮件的访问权限。

针对这个问题的解决方案就是per-URI permission:当启动一个activity或者给一个activity返回结果的时候,呼叫方可以设置Intent.FLAG_GRANT_READ_URI_PERMISSION和/或 Intent.FLAG_GRANT_WRITE_URI_PERMISSION . 这会使接收该intent的activity获取到进入该Intent指定的URI的权限,而不论它是否有权限进入该intent对应的content provider。

这种机制允许一个通常的capability-style模型,这种模型是以用户交互(如打开一个附件, 从列表中选择一个联系人)为驱动,特别获取fine-grained permissions(更细粒化的权限)。这是一种减少不必要权限的重要方式,这种方式主要针对的就是那些和程序的行为直接相关的权限。

这些URI permission的获取需要content provider(包含那些URI)的配合。强烈推荐在content provider中提供这种能力,并通过 android:grantUriPermissions或者<grant-uri-permissions>标签来声明支持。

(8)Android 6.0新的权限机制

     从Android6.0开始,Android引入了新的权限管理机制,将应用可使用的权限划分成了两类,一类是normal permissions,也就是普通权限,例如访问网络,创建快捷方式,开启闪光灯等 ,这类权限一般不涉及用户隐私,另一类是dangerous permissions,例如拨打电话,读取通讯录,读取短信,获取地理位置等。对normal permissions,仍然和以前一样,开发者只需要在AndroidManifest中配置即可,应用安装时提示用户所需的权限,用户同意安装即表示授权应用使用这些权限。对dangerous permissions这类涉及用户隐私的权限,不仅需要在AndroidManifest中配置,还需要在运行时请求用户授权,用户这时可以单独允许或拒绝某项权限。当用户选择了拒绝某项权限时,应用将无法执行该权限对应的api。

通过引入这套新的权限管理机制,用户在权限管理上有了更高的自由度,用户不再需要为了限制某项信息不被获取而舍弃整个应用的使用权。对涉及用户隐私的这类操作,用户可以选择拒绝,而应用的其他功能又不受影响。

危险权限运行时的权限申请主要用到如下几个API。

a) Context.checkSelfPermission(String permission) 检查是否被授予了某个权限

b) Activity.requestPermissions(String[] permissions, int requestCode) 申请一组权限

c) Activity.shouldShowRequestPermissionRationale(String permission) 判断是否需要显示申请此权限的原因,在应用第一次申请某个权限,或者用户对该权限请求授权界面选择了不再显示时此方法返回false,否则返回true。

d) Activity.onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) 权限申请结果回调

这四个都是从Android 6.0系统 (API Level 21)才开始有的new API,因此使用前都需要判断当前系统的版本是否是Android 6.0以上。

上一篇下一篇

猜你喜欢

热点阅读