Table of Contents
- 1 android中常用的五种布局
- 2 android的数据存储方式
- 3 android DVM 的理解
- 4 android种线程间通讯
- 5 mvc模式的原理,android中的应用
- 6 android应用的入口点
- 7 android Service 和 Binder机制
- 8 andorid程序运行时的权限与文件系统权限的区别
- 9 Activity的生命周期
- 10 Activity设置窗口样式
- 11 Activity被回收了怎么办
- 12 如何退出Activity,如何安全退出已调用多个Activity 的Application?
- 13 系统上安装了多个浏览器,能否指定某浏览器访问指定页面?
- 14 什么情况下会导致Force close ? 如何避免?能否捕获导致其的异常?
- 15 哪些情况下会发生ANR? 怎么应对?
- 16 View 如何刷新?
最近在学习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 的消息机制是一样的。
- Looper:(相当于隧道) 一个线程可以产生一个Looper 对象,由它来管理此线程里的Message Queue( 车队,消息隧道) 。
- Handler: 你可以构造Handler 对象来与Looper 沟通,以便push 新消息到Message Queue 里;或者接收Looper( 从Message Queue 取出) 所送来的消息。
- Message Queue( 消息队列): 用来存放线程放入的消息。
- 线程:UI thread 通常就是main thread ,而Android 启动程序时会替它建立一个Message Queue。
5 mvc模式的原理,android中的应用
mvc是model,view,controller的缩写,mvc包含三个部分:
- 模型(model)对象:是应用程序的主体部分,所有的业务逻辑都应该写在该层。
- 视图(view)对象:是应用程序中负责生成用户界面的部分。也是在整个mvc架构中用户唯一可以看到的一层,接收用户的输入,显示处理结果。
- 控制器(control)对象:是根据用户的输入,控制用户界面数据显示及更新model对象状态的部分,控制器更重要的一种导航功能,响应用户出发的相关事件,交给m层处理。
android鼓励弱耦合和组件的重用,在android中mvc的具体体现如下:
- 视图层(view):一般采用xml文件进行界面的描述,使用的时候可以非常方便的引入,当然,如果你对android了解的比较的多了话,就一定可以想到在android中也可以使用javascript+html等的方式作为view层,当然这里需要进行java和javascript之间的通信,幸运的是,android提供了它们之间非常方便的通信实现。
- 控制层(controller):android的控制层的重任通常落在了众多的acitvity的肩上,这句话也就暗含了不要在acitivity中写代码,要通过activity交割model业务逻辑层处理,这样做的另外一个原因是android中的acitivity的响应时间是5s,如果耗时的操作放在这里,程序就很容易被回收掉。
- 模型层(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的权限规则
- Android中的apk必须签名
- 基于UserID的进程级别的安全机制
- 默认apk生成的数据对外是不可见的
- AndroidManifest.xml中的显式权限声明
9 Activity的生命周期
下面一张图描述这个过程:
10 Activity设置窗口样式
- 在你的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的应用来说,现提供几个方法:
- 抛异常强制退出.
- 记录打开的Activity
- 发送特定广播
- 递归退出
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吧。
- 下载UC apk:http://i-uc.net/read.php?2
- 下载反编译dex文件工具:http://nchc.dl.sourceforge.net/project/dedexer/dedexer/1.5/ddx1.5.jar(Dedexer 项目主页: http://dedexer.sourceforge.net/)
- 执行命令:java -jar ddx1.5.jar -o -D -d c:\ c:\classes.dex
- 得到package name是:com.uc.browser,启动的activity是:com.uc.browser.ActivityUpdate(补充:当我在这里选择采用ActivityBrowser的时候发觉权限不够,报permiss denied 异常,而且也不是我们要的那个activity,幸运的是在第二次尝试用ActivityUpdate,刚好能满足要求)
- 修改上面的代码为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