android 笔记

Table of Contents

最近在学习android应用开发, 发现的一些问题,进行了总结。这个就当是第一版以后还有什么问题,再进行更新吧。

1 android中常用的五种布局

FrameLayout(框架布局),LinearLayout (线性布局),AbsoluteLayout(绝对布局),RelativeLayout(相对布局),TableLayout(表格布局)

1.1 FrameLayout

这个布局可以看成是墙脚堆东西,有一个四方的矩形的左上角墙脚,我们放了第一个东西,要再放一个,那就在放在原来放的位置的上面,这样依次的放,会盖住原来的东西。这个布局比较简单,也只能放一点比较简单的东西。

1.2 LinearLayout

线性布局,这个东西,从外框上可以理解为一个div,他首先是一个一个从上往下罗列在屏幕上。每一个LinearLayout里面又可分为垂直布局 (android:orientation=”vertical”)和水平布局(android:orientation=”horizontal” )。当垂直布局时,每一行就只有一个元素,多个元素依次垂直往下;水平布局时,只有一行,每一个元素依次向右排列。

linearLayout中有一个重要的属性 android:layout_weight=”1”,这个weight在垂直布局时,代表行距;水平的时候代表列宽;weight值越大就越大。

1.3 AbsoluteLayout

绝对布局犹如div指定了absolute属性,用X,Y坐标来指定元素的位置android:layout_x=”20px” android:layout_y=”12px” 这种布局方式也比较简单,但是在垂直随便切换时,往往会出问题,而且多个元素的时候,计算比较麻烦。

1.4 RelativeLayout

相对布局可以理解为某一个元素为参照物,来定位的布局方式。主要属性有: 相对于某一个元素android:layout_below=”@id/aaa” 该元素在 id为aaa的下面 android:layout_toLeftOf=”@id/bbb” 改元素的左边是bbb

相对于父元素的地方 android:layout_alignParentLeft=”true” 在父元素左对齐 android:layout_alignParentRight=”true” 在父元素右对齐

还可以指定边距等,具体详见API

1.5 TableLayout

表格布局类似Html里面的Table。每一个TableLayout里面有表格行TableRow,TableRow里面可以具体定义每一个元素,设定他的对齐方式 android:gravity=”” 。

2 android的数据存储方式

Android系统提供了四种存储数据方式。分别为:SharePreference、SQLite、Content Provider和File。但由于Android系统中,数据基本是私有的,都是存放于”data/data”程序包名目录下,所以要实现数据共享,正确方式是使用Content Provider

SQLite:SQLite是一个轻量级的数据库,支持基本的SQL语法,是常被采用的一种数据存储方式。 Android为此数据库提供了一个名为SQLiteDatabase的类,封装了一些操作数据库的api

SharedPreference: 除SQLite数据库外,另一种常用的数据存储方式,其本质就是一个xml文件,常用于存储较简单的参数设置。

File: 即常说的文件(I/O)存储方法,常用语存储大数量的数据,但是缺点是更新数据将是一件困难的事情。

ContentProvider: Android系统中能实现所有应用程序共享的一种数据存储方式,由于数据通常在各应用间的是互相私密的,所以此存储方式较少使用,但是其又是必不可少的一种存储方式。例如音频,视频,图片和通讯录,一般都可以采用此种方式进行存储。每个Content Provider都会对外提供一个公共的URI(包装成Uri对象),如果应用程序有数据需要共享时,就需要使用Content Provider为这些数据定义一个URI,然后其他的应用程序就通过Content Provider传入这个URI来对数据进行操作。

3 android DVM 的理解

DVM有如下特征: +使用专有的.dex格式。 +原因是java类文件在编译过后,会产生至少一个.class文件包含大量陈余信息,dex文件格式会把所有的.class文件内容整合到一个.dex文件中。即减少了整体文件的尺寸和IO操作,也提高了类的查找速度。 +增加了对新的操作码的支持 +文件结构尽量简洁,使用等长的指令,借以提高解析速度。 +尽量扩大只读结构的大小,借以提高跨进程的数据共享。 +dex的优化,dex文件的结构是紧凑的,但是如果想提高运行时的性能,就需要对dex文件进行进一步的优化,这些优化针对以下几个方面: +验证dex文件中的所有类 +对一些特定的类和方法里面的操作码进行优化 +调整所有的字节序(Little_endian)和对齐结构中的每一个域 +基于寄存器,基于寄存器的虚拟机虽然比基于堆栈的虚拟机在硬件,通用性上要差一些,但是它的代码执行效率去更好 +每一个Android应用都运行在它自己的DVM实例中,每一个DVM实例都是一个独立的进程空间。所有的Android应用的线程都对应一个Linux线程,DVM因此可以更多地依赖操作系统的线程调度和管理机制。不同的应用在不同的进程空间里运行,不同的应用都是用不同的Linux用户来运行以最大程度地保户应用程序的安全性和独立性

4 android种线程间通讯

android 有一种叫消息队列的说法,这里我们可以这样理解:假如一个隧道就是一个消息队列,那么里面的每一部汽车就是一个一个消息,这里我们先忽略掉超车等种种因素,只那么先进隧道的车将会先出,这个机制跟我们android 的消息机制是一样的。

  1. Looper:(相当于隧道) 一个线程可以产生一个Looper 对象,由它来管理此线程里的Message Queue( 车队,消息隧道) 。
  2. Handler: 你可以构造Handler 对象来与Looper 沟通,以便push 新消息到Message Queue 里;或者接收Looper( 从Message Queue 取出) 所送来的消息。
  3. Message Queue( 消息队列): 用来存放线程放入的消息。
  4. 线程:UI thread 通常就是main thread ,而Android 启动程序时会替它建立一个Message Queue。

5 mvc模式的原理,android中的应用

mvc是model,view,controller的缩写,mvc包含三个部分:

  • 模型(model)对象:是应用程序的主体部分,所有的业务逻辑都应该写在该层。
  • 视图(view)对象:是应用程序中负责生成用户界面的部分。也是在整个mvc架构中用户唯一可以看到的一层,接收用户的输入,显示处理结果。
  •  控制器(control)对象:是根据用户的输入,控制用户界面数据显示及更新model对象状态的部分,控制器更重要的一种导航功能,响应用户出发的相关事件,交给m层处理。

android鼓励弱耦合和组件的重用,在android中mvc的具体体现如下:

  1. 视图层(view):一般采用xml文件进行界面的描述,使用的时候可以非常方便的引入,当然,如果你对android了解的比较的多了话,就一定可以想到在android中也可以使用javascript+html等的方式作为view层,当然这里需要进行java和javascript之间的通信,幸运的是,android提供了它们之间非常方便的通信实现。
  2. 控制层(controller):android的控制层的重任通常落在了众多的acitvity的肩上,这句话也就暗含了不要在acitivity中写代码,要通过activity交割model业务逻辑层处理,这样做的另外一个原因是android中的acitivity的响应时间是5s,如果耗时的操作放在这里,程序就很容易被回收掉。
  3. 模型层(model):对数据库的操作、对网络等的操作都应该在model里面处理,当然对业务计算等操作也是必须放在的该层的。

6 android应用的入口点

android应用程序提供的是入口Activity,而非入口函数 从哪里定义它是Activity呢?AndroidManifest.xml文件中定义了整个android应用所包含的Activity.

7 android Service 和 Binder机制

Service作为Android四大组件之一,在后台处理一些耗时的逻辑,或者去执行某些需要长期运行的任务。必要的时候我们甚至可以在程序退出的情况下,让Service在后台继续保持运行状态。

Binder关联机制

8 andorid程序运行时的权限与文件系统权限的区别

8.1 linux文件系统上的权限

-rwxr-x–x system system 4156 2010-04-30 16:13 test.apk 代表的是相应的用户/用户组及其他人对此文件的访问权限,与此文件运行起来具有的权限完全不相关。比如上面的例子只能说明system用户拥有对此文件的读写执行权限;system组的用户对此文件拥有读、执行权限;其他人对此文件只具有执行权限。而test.apk运行起来后可以干哪些事情,跟这个就不相关了。千万不要看apk文件系统上属于system/system用户及用户组,或者root/root用户及用户组,就认为apk具有system或root权限

8.2 Android的权限规则

  1. Android中的apk必须签名
  2. 基于UserID的进程级别的安全机制
  3. 默认apk生成的数据对外是不可见的
  4. AndroidManifest.xml中的显式权限声明

9 Activity的生命周期

下面一张图描述这个过程: Activity

10 Activity设置窗口样式

  1. 在你的styles.xml文件中可以新建一如下的style:

<style name="Theme.FloatActivity" parent="android:style/Theme.Dialog">

2.在AndroidManifest.xml中在你需要显示为窗口的activity中添加如果属性:

android:theme="@style/Theme.FloatActivity"

11 Activity被回收了怎么办

当你的程序中某一个Activity A在运行中,主动或被动地运行另一个Activity B这个时候A会执行onSaveInstanceState()方法缓存一些计算的数据;

public   void onSaveInstanceState(Bundle outState) {

super.onSaveInstanceState(outState);

outState.putInt( “id” , 1);
}

B完成之后又会来找A,这个时候就有两种情况,一种是A被回收,一种是没有被回收,被回收的A就要重新调用onCreate()方法,不同于直接启动的是这回onCreate()里是带上参数savedInstanceState,没被回收的就还是onResume()就好了。

savedInstanceState是一个Bundle对象,可以理解为系统帮你维护的一个Map对象,在onCreate()里你可能会用到它,如果正常启动onCreate()就不会有它,所以用的时候要判断一下是否为空。

`if(savedInstanceState !=null) {

int id =savedInstanceState.getInt( “id” );

}`

12 如何退出Activity,如何安全退出已调用多个Activity 的Application?

对于单一Activity的应用来说,退出很简单,直接finish()即可。 当然,也可以用killProcess()和System.exit()这样的方法。

对于多Activity的应用来说,现提供几个方法:

  1. 抛异常强制退出.
  2. 记录打开的Activity
  3. 发送特定广播
  4. 递归退出

13 系统上安装了多个浏览器,能否指定某浏览器访问指定页面?

具体方法如下:

`Intent intent = new Intent();

intent.setAction("android.intent.action.VIEW");
Uri content_uri_browsers = Uri.parse("http://isomobile.com");
intent.setData(content_uri_browsers);
intent.setClassName("com.android.browser",  "com.android.browser.BrowserActivity");
startActivity(intent);`

问题的关键在于我们设置了class name,也就是我们想要跳转的pakcage的activity。如果你想要跳转到其它的浏览器,只需要修改一下这个函数就OK了。 好,我们现在来让刚刚的思路来指导我们的实践。假如我们现在要直接启动UC浏览器,那么我们该怎么做呢?让我们step by step吧。   

  1. 下载UC apk:http://i-uc.net/read.php?2   
  2. 下载反编译dex文件工具:http://nchc.dl.sourceforge.net/project/dedexer/dedexer/1.5/ddx1.5.jar(Dedexer 项目主页: http://dedexer.sourceforge.net/)   
  3. 执行命令:java -jar ddx1.5.jar -o -D -d c:\ c:\classes.dex   
  4. 得到package name是:com.uc.browser,启动的activity是:com.uc.browser.ActivityUpdate(补充:当我在这里选择采用ActivityBrowser的时候发觉权限不够,报permiss denied 异常,而且也不是我们要的那个activity,幸运的是在第二次尝试用ActivityUpdate,刚好能满足要求)   
  5. 修改上面的代码为intent.setClassName(“com.uc.browser”,”com.uc.browser.ActivityUpdate”);

14 什么情况下会导致Force close ? 如何避免?能否捕获导致其的异常?

程序出现异常,比如nullpointer会导致Force Close。

避免:编写程序时逻辑连贯,思维缜密。

能捕获异常,在logcat中能看到异常信息

15 哪些情况下会发生ANR? 怎么应对?

在Android中,应用的响应性被活动管理器(Activity Manager)和窗口管理器(Window Manager)这两个系统服务所监视,当用户触发输入事件(如按键、触摸屏事件)的响应超过5秒,或者广播接收者(BroadcastReceiver)的onReceiver()方法在10秒没有执行完毕,那么Android会认为该应用无响应,便弹出ANR对话框。

避免方法:Activity应该在它的关键生命周期方法(如onCreate()和onResume())里尽可能少的去做创建操作、潜在的耗时操作,例如网络或数据库操作,或者高耗时的计算如改变位图尺寸,应该在子线程里(或者异步方式)来完成,主线程应该为子线程提供一个Handler,以便完成时能够提交给主线程;如果BroadcastReceiver要完成比较耗时的操作,应该通过发送Intent给Service,有Service来完成(注意广播接收者不能用子线程来解决,因为BroadcastReceiver的生命周期很短,子线程可能还没有结束BroadcastReceiver就先结束了;一旦BroadcastReceiver结束,它所在的进程(此时已变成空进程)很容易在系统需要内存时被优先杀死,那么正在工作的子线程也会被杀死)。

16 View 如何刷新?

Android中对View的更新有很多种方式,使用时要区分不同的应用场合。我感觉最要紧的是分清:多线程和双缓冲的使用情况。

现在可以尝试理解下面的模拟场景: 两个人:一对夫妻,老公上班,老婆在家,现在他们都要吃饭。 “不使用多线程和双缓冲”的情况是:老公在公司吃,老婆在家吃,互不干扰,吃就是了。 “使用多线程和不使用双缓冲”的情况是:老婆做好饭,另外让人送一份到公司,老公收到饭就可以吃了。 “使用多线程和使用双缓冲”的情况是:老婆做好饭,等老公回家一起吃。

16.1 不使用多线程和双缓冲

这种情况最简单了,一般只是希望在View发生改变时对UI进行重绘。你只需在Activity中显式地调用View对象中的invalidate()方法即可。系统会自动调用 View的onDraw()方法。

16.2 使用多线程和不使用双缓冲

这种情况需要开启新的线程,新开的线程就不好访问View对象了。强行访问的话会报:android.view.ViewRoot$CalledFromWrongThreadException:Only the original thread that created a view hierarchy can touch its views.

这时候你需要创建一个继承了android.os.Handler的子类,并重写handleMessage(Message msg)方法。android.os.Handler是能发送和处理消息的,你需要在Activity中发出更新UI的消息,然后再你的Handler(可以使用匿名内部类)中处理消息(因为匿名内部类可以访问父类变量, 你可以直接调用View对象中的invalidate()方法 )。也就是说:在新线程创建并发送一个Message,然后再主线程中捕获、处理该消息。

16.3 使用多线程和双缓冲

Android中SurfaceView是View的子类,她同时也实现了双缓冲。你可以定义一个她的子类并实现SurfaceHolder.Callback接口。由于实现SurfaceHolder.Callback接口,新线程就不需要android.os.Handler帮忙了。SurfaceHolder中lockCanvas()方法可以锁定画布,绘制玩新的图像后调用unlockCanvasAndPost(canvas)解锁(显示),还是比较方便得。

Date: 2015-07-12 Sun

Author: hujd

Org version 7.9.3f with Emacs version 24

Validate XHTML 1.0

JasonThink wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!