【Android】面试宝典

 

 

 

 

 

 

Android面试

 

 

 

                                                                                                                  

 

1. 内容介绍................................................................................................................................................................................................................... 8

2. JavaSE基础(★★)............................................................................................................................................................................................ 8

一、 Java面向对象思想................................................................................................................................................................................ 8

1、面向对象都有哪些特性以及你对这些特性的理解............................................................................................................... 8

二、 Java中的多态......................................................................................................................................................................................... 9

1、 Java中实现多态的机制是什么?............................................................................................................................................ 9

三、 Java的异常处理.................................................................................................................................................................................. 10

1、 Java中异常分为哪些种类........................................................................................................................................................ 10

2、 调用下面的方法,得到的返回值是什么............................................................................................................................. 10

四、 Java的数据类型.................................................................................................................................................................................. 11

1、 Java的基本数据类型都有哪些各占几个字节.................................................................................................................. 11

2、 String是基本数据类型吗?可以被继承吗?................................................................................................................... 11

五、 Java的IO.............................................................................................................................................................................................. 12

1、 Java中有几种类型的流............................................................................................................................................................ 12

2、 字节流如何转为字符流.............................................................................................................................................................. 12

3、 如何将一个java对象序列化到文件里................................................................................................................................ 12

六、 Java的集合........................................................................................................................................................................................... 12

1、HashMap排序题,上机题。(本人主要靠这道题入职的第一家公司).................................................................... 12

2、 集合的安全性问题....................................................................................................................................................................... 14

七、 Java的多线程...................................................................................................................................................................................... 15

1、 多线程的两种创建方式.............................................................................................................................................................. 15

2、 在java中wait和sleep方法的不同?.............................................................................................................................. 15

3、 synchronized和volatile关键字的作用.......................................................................................................................... 15

4、 分析代码解释原因....................................................................................................................................................................... 16

5、 什么是线程池,如何使用?.................................................................................................................................................... 18

3. JavaSE高级(★★).......................................................................................................................................................................................... 18

一、 Java中的反射...................................................................................................................................................................................... 18

1、说说你对Java中反射的理解.................................................................................................................................................... 18

二、 Java中的动态代理............................................................................................................................................................................. 18

1、 写一个ArrayList的动态代理类(笔试题)...................................................................................................................... 19

三、 Java中的设计模式............................................................................................................................................................................. 19

1、 你所知道的设计模式有哪些.................................................................................................................................................... 19

2、 单例设计模式................................................................................................................................................................................ 19

3、 工厂设计模式................................................................................................................................................................................ 20

4、 建造者模式(Builder)............................................................................................................................................................ 24

5、 适配器设计模式............................................................................................................................................................................ 25

6、 装饰模式(Decorator).......................................................................................................................................................... 27

7、 策略模式(strategy).............................................................................................................................................................. 28

8、 观察者模式(Observer)....................................................................................................................................................... 29

4. Android基础(★★★)................................................................................................................................................................................... 31

一、 Android基本常识.............................................................................................................................................................................. 31

1、 写10个简单的linux命令....................................................................................................................................................... 31

2、 书写出android工程的目录结构.......................................................................................................................................... 32

3、 什么是ANR 如何避免它?..................................................................................................................................................... 32

4、 谈谈Android的优点和不足之处......................................................................................................................................... 33

5、 一条最长的短信息约占多少byte?....................................................................................................................................... 34

6、 sim卡的EF文件有何作用?.................................................................................................................................................. 34

7、 如何判断是否有SD卡?.......................................................................................................................................................... 37

8、 dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念?..................................................................... 37

9、 Android程序与Java程序的区别?................................................................................................................................... 38

10、 启动应用后,改变系统语言,应用的语言会改变么?.............................................................................................. 38

11、 请介绍下adb、ddms、aapt的作用.............................................................................................................................. 38

12、 ddms 和traceview的区别................................................................................................................................................. 39

13、 补充知识:TraceView的使用............................................................................................................................................. 39

二、 Activity................................................................................................................................................................................................... 43

1、 什么是Activity?........................................................................................................................................................................... 43

2、 请描述一下Activity 生命周期............................................................................................................................................... 43

3、 如何保存Activity的状态?..................................................................................................................................................... 44

4、 两个Activity之间跳转时必然会执行的是哪几个方法?............................................................................................. 45

5、 横竖屏切换时Activity的生命周期....................................................................................................................................... 45

6、 如何将一个Activity设置成窗口的样式............................................................................................................................. 45

7、 如何退出Activity?如何安全退出已调用多个Activity的Application?.......................................................... 45

8、 请描述一下Activity的启动模式都有哪些以及各自的特点........................................................................................ 46

三、 Service.................................................................................................................................................................................................... 55

1、 Service是否在main thread中执行, service里面是否能执行耗时的操作?..................................................... 56

2、 Activity怎么和Service绑定,怎么在Activity中启动自己对应的Service?.................................................. 56

3、 请描述一下Service的生命周期............................................................................................................................................ 56

4、 什么是IntentService?有何优点?.................................................................................................................................... 58

5、 说说Activity、Intent、Service是什么关系................................................................................................................... 60

6、 Service和Activity在同一个线程吗.................................................................................................................................... 60

7、 Service里面可以弹吐司么...................................................................................................................................................... 61

四、 BroadCastReceiver.......................................................................................................................................................................... 61

1、 请描述一下BroadcastReceiver........................................................................................................................................... 61

2、 在manifest和代码中如何注册和使用BroadcastReceiver..................................................................................... 62

3、 BroadCastReceiver的生命周期.......................................................................................................................................... 62

五、 ContentProvider............................................................................................................................................................................... 62

1、 请介绍下ContentProvider是如何实现数据共享的.................................................................................................... 63

2、 请介绍下Android的数据存储方式..................................................................................................................................... 63

3、 为什么要用ContentProvider?它和sql的实现上有什么差别?.......................................................................... 63

4、 说说ContentProvider、ContentResolver、ContentObserver之间的关系................................................ 64

六、 Android中的布局.............................................................................................................................................................................. 64

1、Android中常用的布局都有哪些............................................................................................................................................. 64

2、 谈谈UI中, Padding和Margin有什么区别?.......................................................................................................... 64

七、 ListView................................................................................................................................................................................................. 65

1、 ListView如何提高其效率?................................................................................................................................................... 65

2、 当ListView数据集改变后,如何更新ListView............................................................................................................ 65

3、 ListView如何实现分页加载................................................................................................................................................... 65

4、 ListView可以显示多种类型的条目吗................................................................................................................................. 66

5、 ListView如何定位到指定位置............................................................................................................................................... 66

6、 当在ScrollView中如何嵌入ListView............................................................................................................................... 66

7、 ListView中如何优化图片........................................................................................................................................................ 67

8、 ListView中图片错位的问题是如何产生的....................................................................................................................... 68

9、 Java中引用类型都有哪些........................................................................................................................................................ 68

八、 JNI&NDK.............................................................................................................................................................................................. 71

1、 在Android中如何调用C语言.............................................................................................................................................. 71

2、 请介绍一下NDK.......................................................................................................................................................................... 71

3、 JNI调用常用的两个参数.......................................................................................................................................................... 71

九、 Android中的网络访问.................................................................................................................................................................... 72

1、Android中如何访问网络........................................................................................................................................................... 72

2、 如何解析服务器传来的JSON文件...................................................................................................................................... 72

3、 如何解析服务器传来的XML格式数据............................................................................................................................... 74

4、 如何从网络上加载一个图片显示到界面............................................................................................................................. 76

5、 如何播放网络视频....................................................................................................................................................................... 77

十、 Intent...................................................................................................................................................................................................... 77

1、 Intent传递数据时,可以传递哪些类型数据?............................................................................................................... 77

2、 Serializable和Parcelable的区别...................................................................................................................................... 77

3、 请描述一下Intent 和 IntentFilter..................................................................................................................................... 78

十一、 Fragment.......................................................................................................................................................................................... 80

1、 Fragment跟Activity之间是如何传值的.......................................................................................................................... 80

2、 描述一下Fragment的生命周期........................................................................................................................................... 81

5. Android高级(★★★)................................................................................................................................................................................... 81

一、 Android性能优化.............................................................................................................................................................................. 81

1、 如何对Android应用进行性能分析..................................................................................................................................... 82

2、 什么情况下会导致内存泄露.................................................................................................................................................... 83

3、 如何避免OOM异常.................................................................................................................................................................. 87

4、 Android中如何捕获未捕获的异常...................................................................................................................................... 89

二、 Android屏幕适配.............................................................................................................................................................................. 90

1、 屏幕适配方式都有哪些.............................................................................................................................................................. 90

2、 屏幕适配的处理技巧都有哪些................................................................................................................................................ 96

3、 dp和px之间的关系.................................................................................................................................................................. 99

三、 AIDL......................................................................................................................................................................................................... 99

1、 什么是AIDL以及如何使用...................................................................................................................................................... 99

四、自定义控件............................................................................................................................................................................................ 100

1、如何自定义一个控件.................................................................................................................................................................. 100

2、 请描述一下View的绘制流程.............................................................................................................................................. 101

五、Android中的事件处理.................................................................................................................................................................... 103

1、Handler机制................................................................................................................................................................................ 103

2、 事件分发机制.............................................................................................................................................................................. 104

六、Android签名....................................................................................................................................................................................... 106

1、简单描述下Android 数字签名............................................................................................................................................ 106

2、 使用Eclipse如何生成数字签名......................................................................................................................................... 107

七、 Android中的动画........................................................................................................................................................................... 107

1、 Android中的动画有哪几类,它们的特点和区别是什么......................................................................................... 108

2、 如何修改Activity进入和退出动画.................................................................................................................................... 108

八、 其他知识(非归类内容).............................................................................................................................................................. 108

1、 AsyncTask如何使用............................................................................................................................................................... 109

2、 都使用过哪些框架、平台...................................................................................................................................................... 113

3、 都使用过哪些自定义控件...................................................................................................................................................... 113

6. Android项目(★★★)................................................................................................................................................................................ 114

1、 如何介绍自己的项目................................................................................................................................................................ 114

2、 项目介绍示范.............................................................................................................................................................................. 114

附录:更新记录..................................................................................................................................................................................................... 115

=======================================

更多精品教程尽在【perfect教程】

http://shop117393101.taobao.com

如地址失效,可联系Q1871209564

=======================================

非此地址购买获得,均为二次倒卖、翻录

得到的视频不完整、无售后保障

本店长期更新黑马Android视频

一次购买终身售后

=======================================

                          Android面试宝典-V1

1. 内容介绍

该面试宝典不仅收录了本人亲身面试遇到的问题,还收录了从黑马学子那里收集过来的问题。在以后的工作中本人也会不断的更新和充实该面试宝典,当然也希望大家能够多多奉献比较优质的面试题。

该面试宝典不仅展示了常见的面试问题以及回答技巧,还详细讲解了每一道题所包含的知识点,让黑马学子不仅知其然,更知其所以然。

本人的面试实战记录发布在黑马论坛:http://bbs.itheima.com/thread-196394-1-1.html

大家可以访问上面的网址,通过阳哥的实战记录略微感知一下真实面试的情况,从中学习一些面试技巧以便让自己在未来的面试中能够得心应手,顺利拿到自己喜欢的offer。

2. JavaSE基础(★★)

有人可能会问对于我们学Android的同学来讲,面试还会问Java基础吗?答案是会的,但是不会太多,因此我给了两颗星的重要程度。一般笔试的时候出现java基础题的概率比较大,口头面试的时候比较少,比如自己在面试的时候一些对基础知识比较看重的面试官会深究着Java基础去问,比如问你异常的类型以及处理方式,集合的体系结构等等。

一、Java面向对象思想

1、面向对象都有哪些特性以及你对这些特性的理解

 继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类);得到继承信息的类被称为子类(派生类)。继承让变化中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素的重要手段。

 封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装;我们编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。

 多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。如果将对象的方法视为对象向外界提供的服务,那么运行时的多态性可以解释为:当A系统访问B系统提供的服务时,B系统有多种提供服务的方式,但一切对A系统来说都是透明的。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事:1. 方法重写(子类继承父类并重写父类中已有的或抽象的方法);2. 对象造型(用父类型引用引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。

 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。

二、Java中的多态

1、Java中实现多态的机制是什么?

靠的是父类或接口定义的引用变量可以指向子类或具体实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。

三、Java的异常处理

1、Java中异常分为哪些种类

1)按照异常需要处理的时机分为编译时异常也叫CheckedException和运行时异常也叫RuntimeException。只有java语言提供了Checked异常,Java认为Checked异常都是可以被处理的异常,所以Java程序必须显式处理Checked异常。如果程序没有处理Checked异常,该程序在编译时就会发生错误无法编译。这体现了Java的设计哲学:没有完善错误处理的代码根本没有机会被执行。对Checked异常处理方法有两种:

1 当前方法知道如何处理该异常,则用try...catch块来处理该异常。

2 当前方法不知道如何处理,则在定义该方法是声明抛出该异常。

运行时异常只有当代码在运行时才发行的异常,编译时不需要try catch。Runtime如除数是0和数组下标越界等,其产生频繁,处理麻烦,若显示申明或者捕获将会对程序的可读性和运行效率影响很大。所以由系统自动检测并将它们交给缺省的异常处理程序。当然如果你有处理要求也可以显示捕获它们。

2、调用下面的方法,得到的返回值是什么

 

代码在走到第3行的时候雨大了一个MathException,这时第四行的代码就不会执行了,代码直接跳转到catch语句中,走到第6行的时候,异常机制有这么一个原则如果在catch中遇到了return或者异常等能使该函数终止的话那么用finally就必须先执行完finally代码块里面的代码然后再返回值。因此代码又跳到第8行,可惜第8行是一个return语句,那么这个时候方法就结束了,因此第6行的返回结果就无法被真正返回。如果finally仅仅是处理了一个释放资源的操作,那么该道题最终返回的结果就是2。

因此上面返回值是3。

四、Java的数据类型

1、Java的基本数据类型都有哪些各占几个字节

Java有8种基本数据类型

byte 1

char 2

sort 2

int 4

float 4

double 8

long 8

boolean 1(boolean类型比较特别可能只占一个bit,多个boolean可能共同占用一个字节)

2、String是基本数据类型吗?可以被继承吗?

String是引用类型,底层用char数组实现的。因为String是final类,在java中被final修饰的类不能被继承,因此String当然不可以被继承。

 

五、Java的IO

1、Java中有几种类型的流

字节流和字符流。字节流继承于InputStream和OutputStream,字符流继承于InputStreamReader 和OutputStreamWriter。

2、字节流如何转为字符流

字节输入流转字符输入流通过InputStreamReader实现,该类的构造函数可以传入InputStream对象。

字节输出流转字符输出流通过OutputStreamWriter实现,该类的构造函数可以传入OutputStream对象。

3、如何将一个java对象序列化到文件里

在java中能够被序列化的类必须先实现Serializable接口,该接口没有任何抽象方法只是起到一个标记作用。

 

六、Java的集合

1、HashMap排序题,上机题。(本人主要靠这道题入职的第一家公司)

已知一个HashMap<Integer,User>集合, User有name(String)和age(int)属性。请写一个方法实现对HashMap的排序功能,该方法接收HashMap<Integer,User>为形参,返回类型为HashMap<Integer,User>,要求对HashMap中的User的age倒序进行排序。排序时key=value键值对不得拆散。

:要做出这道题必须对集合的体系结构非常的熟悉。HashMap本身就是不可排序的,但是该道题偏偏让给HashMap排序,那我们就得想在API中有没有这样的Map结构是有序的,LinkedHashMap,对的,就是他,他是Map结构,也是链表结构,有序的,更可喜的是他是HashMap的子类,我们返回LinkedHashMap<Integer,User>即可,还符合面向接口(父类编程的思想)。

但凡是对集合的操作,我们应该保持一个原则就是能用JDK中的API就有JDK中的API,比如排序算法我们不应该去用冒泡或者选择,而是首先想到用Collections集合工具类。 users = new HashMap<>(); users.put(1, new User("张三", 25)); users.put(3, new User("李四", 22)); users.put(2, new User("王五", 28)); System.out.println(users); HashMap<integer,user> sortHashMap = sortHashMap(users); System.out.println(sortHashMap); /** * 控制台输出内容 * {1=User [name=张三, age=25], 2=User [name=王五, age=28], 3=User [name=李四, age=22]} {2=User [name=王五, age=28], 1=User [name=张三, age=25], 3=User [name=李四, age=22]} */ } public static HashMap<integer, user=""> sortHashMap(HashMap<integer, user=""> map) { // 首先拿到map的键值对集合 Set<entry<integer, user="">> entrySet = map.entrySet(); // 将set集合转为List集合,为什么,为了使用工具类的排序方法 List<entry<integer, user="">> list = new ArrayList<entry<integer, user="">>(entrySet); " v:shapes="_x0000_s1091">

 

>() { @Override public int compare(Entry<integer, user=""> o1, Entry<integer, user=""> o2) { //按照要求根据User的age的倒序进行排 return o2.getValue().getAge()-o1.getValue().getAge(); } }); //创建一个新的有序的HashMap子类的集合 LinkedHashMap<integer, user=""> linkedHashMap = new LinkedHashMap<integer, user="">(); //将List中的数据存储在LinkedHashMap中 for(Entry<integer, user=""> entry : list){ linkedHashMap.put(entry.getKey(), entry.getValue()); } //返回结果 return linkedHashMap; } } " v:shapes="_x0000_s1090">

2、集合的安全性问题

请问ArrayList、HashSet、HashMap是线程安全的吗?如果不是我想要线程安全的集合怎么办?

我们都看过上面那些集合的源码(如果没有那就看看吧),每个方法都没有加锁,显然都是线程不安全的。话又说过来如果他们安全了也就没第二问了。

在集合中Vector和HashTable倒是线程安全的。你打开源码会发现其实就是把各自核心方法添加上了synchronized关键字。

Collections工具类提供了相关的API,可以让上面那3个不安全的集合变为安全的。

 

上面几个函数都有对应的返回值类型,传入什么类型返回什么类型。打开源码其实实现原理非常简单,就是将集合的核心方法添加上了synchronized关键字。

七、Java的多线程

1、多线程的两种创建方式

java.lang.Thread 类的实例就是一个线程但是它需要调用java.lang.Runnable接口来执行,由于线程类本身就是调用的Runnable接口所以你可以继承java.lang.Thread 类或者直接实现Runnable接口来重写run()方法实现线程。

2、在java中wait和sleep方法的不同?

最大的不同是在等待时wait会释放锁,而sleep一直持有锁。wait通常被用于线程间交互,sleep通常被用于暂停执行。

3、synchronized和volatile关键字的作用

一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:

  1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。

  2)禁止进行指令重排序。

volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;

synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。

1.volatile仅能使用在变量级别;

synchronized则可以使用在变量、方法、和类级别的

2.volatile仅能实现变量的修改可见性,并不能保证原子性;

synchronized则可以保证变量的修改可见性和原子性

3.volatile不会造成线程的阻塞;

synchronized可能会造成线程的阻塞。

4.volatile标记的变量不会被编译器优化;

synchronized标记的变量可以被编译器优化

4、分析代码解释原因

 

上面的代码执行完后输出的结果确定为1000吗?

答案是不一定,或者不等于1000。这是为什么吗?

在 java 的内存模型中每一个线程运行时都有一个线程栈,线程栈保存了线程运行时候变量值信息。当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。

也就是说上面主函数中开启了1000个子线程,每个线程都有一个变量副本,每个线程修改变量只是临时修改了自己的副本,当线程结束时再将修改的值写入在主内存中,这样就出现了线程安全问题。因此结果就不可能等于1000了,一般都会小于1000。

上面的解释用一张图表示如下:

(图片来自网络,非本人所绘)

 

5、什么是线程池,如何使用?

线程池就是事先将多个线程对象放到一个容器中,当使用的时候就不用new线程而是直接去池中拿线程即可,节省了开辟子线程的时间,提高的代码执行效率。

在JDK的java.util.concurrent.Executors中提供了生成多种线程池的静态方法。

 

然后调用他们的execute方法即可。

3. JavaSE高级(★★)

一、Java中的反射

1、说说你对Java中反射的理解

Java中的反射首先是能够获取到Java中要反射类的字节码,获取字节码有三种方法,1.Class.forName(className) 2.类名.class 3.this.getClass()。然后将字节码中的方法,变量,构造函数等映射成相应的Method、Filed、Constructor等类,这些类提供了丰富的方法可以被我们所使用。

二、Java中的动态代理

1、写一个ArrayList的动态代理类(笔试题)

list = new ArrayList(); List proxyInstance = (List) Proxy.newProxyInstance(list.getClass().getClassLoader(), list.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(list, args); } }); proxyInstance.add("你好"); System.out.println(list); " v:shapes="_x0000_s1086">

三、Java中的设计模式

1、你所知道的设计模式有哪些

Java中一般认为有23种设计模式,我们不需要所有的都会,但是其中常用的几种设计模式应该去掌握。下面列出了所有的设计模式。需要掌握的设计模式我单独列出来了,当然能掌握的越多越好。

总体来说设计模式分为三大类:

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

2、单例设计模式

最好理解的一种设计模式,分为懒汉式和饿汉式。

 饿汉式:

 

 懒汉式:

 

3、工厂设计模式

工厂模式分为工厂方法模式和抽象工厂模式。

 工厂方法模式

工厂方法模式分为三种:普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。

多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。

静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。

 普通工厂模式

 

 多个工厂方法模式

该模式是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。

 

 静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。

 

 抽象工厂模式

工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。

 

 

4、建造者模式(Builder)

工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来得到的。

list = new ArrayList(); public void produceMailSender(int count) { for (int i = 0; i < count; i++) { list.add(new MailSender()); } } public void produceSmsSender(int count) { for (int i = 0; i < count; i++) { list.add(new SmsSender()); } } } " v:shapes="_x0000_s1078">

 

5、适配器设计模式

 适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。

 类的适配器模式

 

 对象的适配器模式

基本思路和类的适配器模式相同,只是将Adapter类作修改,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题。

 

 接口的适配器模式

接口的适配器是这样的:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。

6、装饰模式(Decorator)

顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。

 

7、策略模式(strategy)

策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数。策略模式的决定权在用户,系统本身提供不同算法的实现,新增或者删除算法,对各种算法做封装。因此,策略模式多用在算法决策系统中,外部用户只需要决定用哪个算法即可。

 

 

8、观察者模式(Observer)

观察者模式很好理解,类似于邮件订阅和RSS订阅,当我们浏览一些博客或wiki时,经常会看到RSS图标,就这的意思是,当你订阅了该文章,如果后续有更新,会及时通知你。其实,简单来讲就一句话:当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系。

 

vector = new Vector(); @Override public void add(Observer observer) { vector.add(observer); } @Override public void del(Observer observer) { vector.remove(observer); } @Override public void notifyObservers() { Enumeration enumo = vector.elements(); while (enumo.hasMoreElements()) { enumo.nextElement().update(); } } } public class MySubject extends AbstractSubject { @Override public void operation() { System.out.println("update self!"); notifyObservers(); } } public class ObserverTest { public static void main(String[] args) { Subject sub = new MySubject(); sub.add(new Observer1()); " v:shapes="_x0000_s1070">

 

4. Android基础(★★★)

一、Android基本常识

1、写10个简单的linux命令

mkdir 创建文件夹

rmdir 删除文件夹

rm 删除文件

mv 移动文件

cp 拷贝文件

cat 查看文件

tail 查看文件尾部

more 分页查看文件

cd 切换当前目录

ls 列出文件清单

reboot 重启

date 显示日期

cal  显示日历

ps 查看系统进程相当于windows的任务管理器

ifconfig 配置网络

2、书写出android工程的目录结构

src 源文件

gen 生成的文件 R文件就在此

android. jar 依赖的android sdk

assets 资源文件

    bin 生成的字节码apk在此

libs 依赖jar和so

res 资源文件

drawable

drawable-hdpi

layout

menu

values

AndroidManifest.xml

project.properties

3、什么是ANR 如何避免它?

在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(ANR:Application Not Responding)对话框。用户可以选择让程序继续运行,但是,他们在使用你的应用程序时,并不希望每次都要处理这个对话框。因此,在程序里对响应性能的设计很重要,这样,系统不会显示ANR给用户。

不同的组件发生ANR的时间不一样,主线程(Activity、Service)是5秒,BroadCastReceiver 是10秒。

解决方案:

将所有耗时操作,比如访问网络,Socket通信,查询大量SQL语句,复杂逻辑计算等都放在子线程中去,然后通过handler.sendMessage、runonUITread、AsyncTask等方式更新UI。无论如何都要确保用户界面操作的流畅度。如果耗时操作需要让用户等待,那么可以在界面上显示进度条。

4、谈谈Android的优点和不足之处

优点:

1、开放性,开源,免费,可定制

2、挣脱运营商束缚

3、丰富的硬件选择

4、不受任何限制的开发商

5、无缝结合的Google应用

缺点:

1、安全问题、隐私问题

2、同质化严重

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

4、山寨化严重

5、过分依赖开发商,缺乏标准配置

5、一条最长的短信息约占多少byte?

在国内的三大运营商通常情况下中文70(包括标点),英文160个。对于国外的其他运行商具体多长需要看运营商类型了。

android内部是通过如下代码进行判断具体一个短信多少byte的。

ArrayList<String> android.telephony.SmsManager.divideMessage(String text)

6、sim卡的EF文件有何作用?

基本文件EF(Elementary File)是SIM卡文件系统的一部分。

 

文件

文件标识符

文件缩写

中文名称

文件作用

MF

3F00

根目录

备注:所有非ETSI GSM协议中规定的应用文件由各厂家自行定义在根目录下(如:PIN1,PIN2…)

EFICCID

2FE2

ICCID

SIM卡唯一的识别号

包含运营商、卡商、发卡时间、省市代码等信息

DFGSM

7F20

GSM目录

备注:根据ETSIGSM09.91的规定Phase2(或以上)的SIM卡中应该有7F21并指向7F20,用以兼容Phase1的手机

EFLP语言选择

6F05

LP

语言选择文件

包含一种或多种语言编码

EFIMSI

6F07

IMSI

国际移动用户识别符

包含SIM卡所对应的号段,比如46000代表135-139号段、46002代表1340-1348

EFKC语音加密密钥

6F20

Kc

计算密钥

用于SIM卡的加密、解密

EFPLMNsel网络选择表

6F30

PLMNsel

公共陆地网选择

决定SIM卡选择哪种网络,在这里应该选择中国移动的网络

EFHPLMN归属地网络选择表

6F31

HPLMN

两次搜索PLMN的时间间隔

两次搜索中国移动的网络的时间间隔

EFACMmax最大计费额

6F37

ACMmax

包含累积呼叫表的最大值

全部的ACM数据存在SIM卡中,此处取最大值

EFSST SIM卡服务表

6F38

SST

SIM卡服务列表

指出SIM卡可以提供服务的种类,哪些业务被激活哪些业务没有开通

EFACM累加计费计数器

6F39

ACM

累计呼叫列表

当前的呼叫和以前的呼叫的单位总和

EFGID1分组识别1

6F3E

GID1

1级分组识别文件

包含特定的SIM-ME组合的标识符,可以识别一组特定的SIM卡

EFGID2分组识别2

6F3F

GID2

2级分组识别文件

包含特定的SIM-ME组合的标识符,可以识别一组特定的SIM卡

EFPUCT单位价格/货币表

6F41

PUCT

呼叫单位的价格和货币表

PUCT是与计费通知有关的信息,ME用这个信息结合EFACM,以用户选择的货币来计算呼叫费用

EFCBMI小区广播识别号

6F45

CBMI

小区广播信息标识符

规定了用户希望MS采纳的小区广播消息内容的类型

EFSPN服务提供商

6F46

SPN

服务提供商名称

包含服务提供商的名称和ME显示的相应要求

EFCBMID

6F48

CBMID

数据下载的小区广播消息识别符

移动台将收到的CBMID传送给SIM卡

EFSUME

6F54

SUME

建立菜单单元

建立SIM卡中的菜单

EFBCCH广播信道

6F74

BCCH

广播控制信道

由于BCCH的存储,在选择小区时,MS可以缩小对BCCH载波的搜索范围

EFACC访问控制级别

6F78

ACC

访问控制级别

SIM卡有15个级别,10个普通级别,5个高级级别

EFFPLMN禁止网络号

6F7B

FPLMN

禁用的PLMN

禁止选择除中国移动以外的其他运营商,比如中国联通、中国卫通等

EFLOCI位置信息

6F7E

LOCI

 位置信息

存储临时移动用户识别符、位置区信息等内容

EFAD管理数据

6FAD

AD

管理数据

包括关于不同类型SIM卡操作模式的信息。例如:常规模式(PLMN用户用于GSM网络操作),型号认证模式(允许ME在无线设备的认证期间的特殊应用);小区测试模式(在小区商用之前,进行小区测试),制造商特定模式(允许ME制造商在维护阶段进行特定的性能自动测试)

EFPHASE阶段

6FAE

PHASE

阶段标识

标识SIM卡所处的阶段信息,比如是普通SIM卡还是STK卡等

DFTELECOM

7F10

电信目录

 

 

EFADN缩位拨号

6F3A

AND

电话簿

用于将电话记录存放在SIM卡中

EFFDN固定拨号

6F3B

FDN

固定拨号

包括固定拨号(FDN)和/或补充业务控制字串(SSC),还包括相关网络/承载能力的识别符和扩展记录的识别符,以及有关的α识别符

EFSMS短消息

6F3C

SMS

短消息

用于将短消息记录存放在SIM卡中

EFCCP能力配置参数

6F3D

CCP

能力配置参数

包括所需要的网络和承载能力的参数,以及当采用一个缩位拨号号码,固定拨号号码,MSISDN、最后拨号号码、服务拨号号码或禁止拨号方式等,建立呼叫时相关的ME配置

EFMSISDN电话号码

6F40

MSISDN

移动基站国际综合业务网号

存放用户的手机号

EFSMSP短信息参数

6F42

SMSP

短消息业务参数

包括短信中心号码等信息

EFSMSS短信息状态

6F43

SMSS

短消息状态

这个标识是用来控制流量的

EFLND最后拨号

6F44

LND

最后拨叫号码

存储最后拨叫号码

EFExt1扩展文件1

6F4A

EXT1

扩展文件1

包括AND,MSISDN或LND的扩展数据

EFExt2扩展文件2

6F4B

EXT2

扩展文件2

包含FDN的扩展数据

 

7、如何判断是否有SD卡?

 通过如下方法:

Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)

如果返回true就是有sdcard,如果返回false则没有。

8、dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念?

dvm指dalvik的虚拟机。每一个Android应用程序都拥有一个独立的Dalvik虚拟机实例,应用程序都在它自己的进程中运行。而每一个dvm都是在Linux 中的一个进程,所以说可以近似认为是同一个概念。

什么是android DVM:Dalvik是Google公司自己设计用于Android平台的Java虚拟机,每一个Dalvik 应用作为一个独立的Linux 进程执行。独立的进程可以防止在虚拟机崩溃的时候所有程序都被关闭。

Dalvik和Java虚拟机的区别

1:Dalvik主要是完成对象生命周期管理,堆栈管理,线程管理,安全和异常管理,以及垃圾回收等等重要功能。   

2:Dalvik负责进程隔离和线程管理,每一个Android应用在底层都会对应一个独立的Dalvik虚拟机实例,其代码在虚拟机的解释下得以执行。

3:不同于Java虚拟机运行java字节码,Dalvik虚拟机运行的是其专有的文件格式Dex

4: dex文件格式可以减少整体文件尺寸,提高I/O操作的类查找速度。 

5: odex是为了在运行过程中进一步提高性能,对dex文件的进一步优化。   

6:所有的Android应用的线程都对应一个Linux线程,虚拟机因而可以更多的依赖操作系统的线程调度和管理机制

7:有一个特殊的虚拟机进程Zygote,他是虚拟机实例的孵化器。它在系统启动的时候就会产生,它会完成虚拟机的初始化,库的加载,预制类库和初始化的操作。如果系统需要一个新的虚拟机实例,它会迅速复制自身,以最快的数据提供给系统。对于一些只读的系统库,所有虚拟机实例都和Zygote共享一块内存区域。

9、Android程序与Java程序的区别?

 Android程序用android sdk开发,java程序用javasdk开发.

Android SDK引用了大部分的Java SDK,少数部分被Android SDK抛弃,比如说界面部分,java.awt  swing  package除了java.awt.font被引用外,其他都被抛弃,在Android平台开发中不能使用。android sdk 添加工具jar httpclient , pull  opengl

10、启动应用后,改变系统语言,应用的语言会改变么?

这个一般是不会的,一般需要重启应用才能改变应用语言。但是对应应用来说如果做了国际化处理则支持如果没有处理那系统语言再更改也是无用的。

11、请介绍下adb、ddms、aapt的作用

adb是Android Debug Bridge ,Android调试桥的意思,ddms是Dalvik Debug Monitor Service,dalvik调试监视服务。aapt即Android Asset Packaging Tool,在SDK的build-tools目录下。该工具可以查看,创建, 更新ZIP格式的文档附件(zip, jar, apk)。也可将资源文件编译成二进制文件,尽管我们没有直接使用过该工具,但是开发工具会使用这个工具打包apk文件构成一个Android 应用程序。

Android 的主要调试工具是adb(Android debuging bridge),ddms是一个在adb基础上的一个图形化工具。

adb,它是一个命令行工具。而ddms功能与adb相同,只是它有一个图形化界面。对不喜欢命今操作方式的人来说是一个不错的选择。

12、ddms 和traceview的区别

简单的说ddms是一个程序执行查看器,在里面可以看见线程和堆栈等信息,traceView是程序性能分析器。

13、补充知识:TraceView的使用

一、TraceView简介

     Traceview是Android平台特有的数据采集和分析工具,它主要用于分析Android中应用程序的hotspot(瓶颈)。Traceview本身只是一个数据分析工具,而数据的采集则需要使用Android SDK中的Debug类或者利用DDMS工具。二者的用法如下:

开发者在一些关键代码段开始前调用Android SDK中Debug类的startMethodTracing函数,并在关键代码段结束前调用stopMethodTracing函数。这两个函数运行过程中将采集运行时间内该应用所有线程(注意,只能是Java线程)的函数执行情况,并将采集数据保存到/mnt/sdcard/下的一个文件中。开发者然后需要利用SDK中的Traceview工具来分析这些数据。

借助Android SDK中的DDMS工具。DDMS可采集系统中某个正在运行的进程的函数调用信息。对开发者而言,此方法适用于没有目标应用源代码的情况。DDMS工具中Traceview的使用如下图所示。

 

点击上图中所示按钮即可以采集目标进程的数据。当停止采集时,DDMS会自动触发Traceview工具来浏览采集数据。

下面,我们通过一个示例程序介绍Traceview的使用。

实例程序如下图所示:界面有4个按钮,对应四个方法。

 

点击不同的方法会进行不同的耗时操作。

 

 

我们分别点击按钮一次,要求找出最耗时的方法。点击前通过DDMS 启动 Start Method Profiling按钮。

 

然后依次点击4个按钮,都执行后再次点击上图中红框中按钮,停止收集数据。

接下来我们开始对数据进行分析。

当我们停止收集数据的时候会出现如下分析图表。该图表分为2大部分,上面分不同的行,每一行代表一个线程的执行耗时情况。main线程对应行的的内容非常丰富,而其他线程在这段时间内干得工作则要少得多。图表的下半部分是具体的每个方法执行的时间情况。显示方法执行情况的前提是先选中某个线程。

 

 

我们主要是分析main线程。

上面方法指标参数所代表的意思如下:

列名

描述

Name

该线程运行过程中所调用的函数名

Incl Cpu Time

某函数占用的CPU时间,包含内部调用其它函数的CPU时间

Excl Cpu Time

某函数占用的CPU时间,但不含内部调用其它函数所占用的CPU时间

Incl Real Time

某函数运行的真实时间(以毫秒为单位),内含调用其它函数所占用的真实时间

Excl Real Time

某函数运行的真实时间(以毫秒为单位),不含调用其它函数所占用的真实时间

Call+Recur Calls/Total

某函数被调用次数以及递归调用占总调用次数的百分比

Cpu Time/Call

某函数调用CPU时间与调用次数的比。相当于该函数平均执行时间

Real Time/Call

同CPU Time/Call类似,只不过统计单位换成了真实时间

我们为了找到最耗时的操作,那么可以通过点击Incl Cpu Time,让其按照时间的倒序排列。我点击后效果如下图:

 

通过分析发现:method1最耗时,耗时2338毫秒。

 

那么有了上面的信息我们可以进入我们的method1方法查看分析我们的代码了。

二、Activity

1、什么是Activity?

四大组件之一,通常一个用户交互界面对应一个activity。activity 是Context的子类,同时实现了window.callback和keyevent.callback, 可以处理与窗体用户交互的事件。

常见的Activity类型有FragmentActivitiy,ListActivity,TabAcitivty等。

如果界面有共同的特点或者功能的时候,还会自己定义一个BaseActivity。

2、请描述一下Activity 生命周期

Activity从创建到销毁有多种状态,从一种状态到另一种状态时会激发相应的回调方法,这些回调方法包括:onCreate onStart onResume onPause onStop onDestroy

其实这些方法都是两两对应的,onCreate创建与onDestroy销毁;

onStart可见与onStop不可见;onResume可编辑(即焦点)与onPause;

这6个方法是相对应的,那么就只剩下一个onRestart方法了,这个方法在什么时候调用呢?

答案就是:在Activity被onStop后,但是没有被onDestroy,在再次启动此Activity时就调用onRestart(而不再调用onCreate)方法;

如果被onDestroy了,则是调用onCreate方法。

3、如何保存Activity的状态?

Activity的状态通常情况下系统会自动保存的,只有当我们需要保存额外的数据时才需要使用到这样的功能。

一般来说, 调用onPause()和onStop()方法后的activity实例仍然存在于内存中, activity的所有信息和状态数据不会消失, 当activity重新回到前台之后, 所有的改变都会得到保留。

但是当系统内存不足时, 调用onPause()和onStop()方法后的activity可能会被系统摧毁, 此时内存中就不会存有该activity的实例对象了。如果之后这个activity重新回到前台, 之前所作的改变就会消失。为了避免此种情况的发生, 我们可以覆写onSaveInstanceState()方法。onSaveInstanceState()方法接受一个Bundle类型的参数, 开发者可以将状态数据存储到这个Bundle对象中, 这样即使activity被系统摧毁, 当用户重新启动这个activity而调用它的onCreate()方法时, 上述的Bundle对象会作为实参传递给onCreate()方法, 开发者可以从Bundle对象中取出保存的数据, 然后利用这些数据将activity恢复到被摧毁之前的状态。

需要注意的是, onSaveInstanceState()方法并不是一定会被调用的, 因为有些场景是不需要保存状态数据的. 比如用户按下BACK键退出activity时, 用户显然想要关闭这个activity, 此时是没有必要保存数据以供下次恢复的, 也就是onSaveInstanceState()方法不会被调用. 如果调用onSaveInstanceState()方法, 调用将发生在onPause()或onStop()方法之前。

 

4、两个Activity之间跳转时必然会执行的是哪几个方法?

一般情况下比如说有两个activity,分别叫A,B,当在A里面激活B组件的时候, A会调用 onPause()方法,然后B调用onCreate() ,onStart(), onResume()。

 这个时候B覆盖了窗体, A会调用onStop()方法.  如果B是个透明的,或者是对话框的样式, 就不会调用A的onStop()方法。

5、横竖屏切换时Activity的生命周期

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

1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期

默认首先销毁当前activity,然后重新加载。

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

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

6、如何将一个Activity设置成窗口的样式

只需要给我们的Activity配置如下属性即可。

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

7、如何退出Activity?如何安全退出已调用多个Activity的Application?

1、通常情况用户退出一个Activity只需按返回键,我们写代码想退出activity直接调用finish()方法就行。

2、记录打开的Activity:

每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。

lists ;// 在application 全局的变量里面 lists = new ArrayList(); lists.add(this); for(Activity activity: lists) { activity.finish(); } lists.remove(this); " v:shapes="_x0000_s1067">

3、发送特定广播:

在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。

//给某个activity 注册接受接受广播的意图  

       registerReceiver(receiver, filter)

//如果过接受到的是 关闭activity的广播  就调用finish()方法 把当前的activity finish()掉

4、递归退出

在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。

5、其实 也可以通过 intent的flag 来实现intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)激活一个新的activity。此时如果该任务栈中已经有该Activity,那么系统会把这个Activity上面的所有Activity干掉。其实相当于给Activity配置的启动模式为SingleTop。

 

8、请描述一下Activity的启动模式都有哪些以及各自的特点

启动模式(launchMode)在多个Activity跳转的过程中扮演着重要的角色,它可以决定是否生成新的Activity实例,是否重用已存在的Activity实例,是否和其他Activity实例公用一个task里。这里简单介绍一下task的概念,task是一个具有栈结构的对象,一个task可以管理多个Activity,启动一个应用,也就创建一个与之对应的task。

Activity一共有以下四种launchMode:

 1.standard

 2.singleTop

 3.singleTask

 4.singleInstance

我们可以在AndroidManifest.xml配置<activity>的android:launchMode属性为以上四种之一即可。

下面我们结合实例一一介绍这四种lanchMode:

8.1 standard

standard模式是默认的启动模式,不用为<activity>配置android:launchMode属性即可,当然也可以指定值为standard。

我们将创建一个Activity,命名为FirstActivity,来演示一下标准的启动模式。FirstActivity代码如下:

 

FirstActivity界面中的TextView用于显示当前Activity实例的序列号,Button用于跳转到下一个FirstActivity界面。

然后我们连续点击几次按钮,将会出现下面的现象:

 

 

 

我们注意到都是FirstActivity的实例,但序列号不同,并且我们需要连续按后退键两次,才能回到第一个FirstActivity。standard模式的原理如下图所示:

 

如图所示,每次跳转系统都会在task中生成一个新的FirstActivity实例,并且放于栈结构的顶部,当我们按下后退键时,才能看到原来的FirstActivity实例。

这就是standard启动模式,不管有没有已存在的实例,都生成新的实例。

8.2 singleTop

我们在上面的基础上为<activity>指定属性android:launchMode="singleTop",系统就会按照singleTop启动模式处理跳转行为。我们重复上面几个动作,将会出现下面的现象:

 

 

 

我们看到这个结果跟standard有所不同,三个序列号是相同的,也就是说使用的都是同一个FirstActivity实例;如果按一下后退键,程序立即退出,说明当前栈结构中只有一个Activity实例。singleTop模式的原理如下图所示:

 

正如上图所示,跳转时系统会先在栈结构中寻找是否有一个FirstActivity实例正位于栈顶,如果有则不再生成新的,而是直接使用。也许朋友们会有疑问,我只看到栈内只有一个Activity,如果是多个Activity怎么办,如果不是在栈顶会如何?我们接下来再通过一个示例来证实一下大家的疑问。

我们再新建一个Activity命名为SecondActivity,如下:

 

然后将之前的FirstActivity跳转代码改为:

 

这时候,FirstActivity会跳转到SecondActivity,SecondActivity又会跳转到FirstActivity。演示结果如下:

 

 

 

我们看到,两个FirstActivity的序列号是不同的,证明从SecondActivity跳转到FirstActivity时生成了新的FirstActivity实例。原理图如下:

 

我们看到,当从SecondActivity跳转到FirstActivity时,系统发现存在有FirstActivity实例,但不是位于栈顶,于是重新生成一个实例。

这就是singleTop启动模式,如果发现有对应的Activity实例正位于栈顶,则重复利用,不再生成新的实例。

8.3 singleTask

在上面的基础上我们修改FirstActivity的属性android:launchMode="singleTask"。演示的结果如下:

 

 

我们注意到,在上面的过程中,FirstActivity的序列号是不变的,SecondActivity的序列号却不是唯一的,说明从SecondActivity跳转到FirstActivity时,没有生成新的实例,但是从FirstActivity跳转到SecondActivity时生成了新的实例。singleTask模式的原理图如下图所示:

 

在图中的下半部分是SecondActivity跳转到FirstActivity后的栈结构变化的结果,我们注意到,SecondActivity消失了,没错,在这个跳转过程中系统发现有存在的FirstActivity实例,于是不再生成新的实例,而是将FirstActivity之上的Activity实例统统出栈,将FirstActivity变为栈顶对象,显示到幕前。也许朋友们有疑问,如果将SecondActivity也设置为singleTask模式,那么SecondActivity实例是不是可以唯一呢?在我们这个示例中是不可能的,因为每次从SecondActivity跳转到FirstActivity时,SecondActivity实例都被迫出栈,下次等FirstActivity跳转到SecondActivity时,找不到存在的SecondActivity实例,于是必须生成新的实例。但是如果我们有ThirdActivity,让SecondActivity和ThirdActivity互相跳转,那么SecondActivity实例就可以保证唯一。

这就是singleTask模式,如果发现有对应的Activity实例,则使此Activity实例之上的其他Activity实例统统出栈,使此Activity实例成为栈顶对象,显示到幕前。

8.4 singleInstance

这种启动模式比较特殊,因为它会启用一个新的栈结构,将Activity放置于这个新的栈结构中,并保证不再有其他Activity实例进入。

我们修改FirstActivity的launchMode="standard",SecondActivity的launchMode="singleInstance",由于涉及到了多个栈结构,我们需要在每个Activity中显示当前栈结构的id,所以我们为每个Activity添加如下代码:

 

然后我们再演示一下这个流程:

 

我们发现这两个Activity实例分别被放置在不同的栈结构中,关于singleInstance的原理图如下

我们看到从FirstActivity跳转到SecondActivity时,重新启用了一个新的栈结构,来放置SecondActivity实例,然后按下后退键,再次回到原始栈结构;图中下半部分显示的在SecondActivity中再次跳转到FirstActivity,这个时候系统会在原始栈结构中生成一个FirstActivity实例,然后回退两次,注意,并没有退出,而是回到了SecondActivity,为什么呢?是因为从SecondActivity跳转到FirstActivity的时候,我们的起点变成了SecondActivity实例所在的栈结构,这样一来,我们需要“回归”到这个栈结构。

如果我们修改FirstActivity的launchMode值为singleTop、singleTask、singleInstance中的任意一个,流程将会如图所示:

 

singleInstance启动模式可能是最复杂的一种模式,为了帮助大家理解,我举一个例子,假如我们有一个share应用,其中的ShareActivity是入口Activity,也是可供其他应用调用的Activity,我们把这个Activity的启动模式设置为singleInstance,然后在其他应用中调用。我们编辑ShareActivity的配置:

" v:shapes="_x0000_s1062">

然后我们在其他应用中这样启动该Activity:

 

当我们打开ShareActivity后再按后退键回到原来界面时,ShareActivity做为一个独立的个体存在,如果这时我们打开share应用,无需创建新的ShareActivity实例即可看到结果,因为系统会自动查找,存在则直接利用。大家可以在ShareActivity中打印一下taskId,看看效果。关于这个过程,原理图如下:

 

三、Service

1、Service是否在main thread中执行, service里面是否能执行耗时的操作?

默认情况,如果没有显示的指servic所运行的进程, Service和activity是运行在当前app所在进程的main thread(UI主线程)里面。

service里面不能执行耗时的操作(网络请求,拷贝数据库,大文件 )

特殊情况 ,可以在清单文件配置 service 执行所在的进程 ,让service在另外的进程中执行

" v:shapes="_x0000_s1060">

2、Activity怎么和Service绑定,怎么在Activity中启动自己对应的Service?

Activity通过bindService(Intent service, ServiceConnection conn, int flags)跟Service进行绑定,当绑定成功的时候Service会将代理对象通过回调的形式传给conn,这样我们就拿到了Service提供的服务代理对象。

在Activity中可以通过startService和bindService方法启动Service。一般情况下如果想获取Service的服务对象那么肯定需要通过bindService()方法,比如音乐播放器,第三方支付等。如果仅仅只是为了开启一个后台任务那么可以使用startService()方法。

3、请描述一下Service的生命周期

Service有绑定模式和非绑定模式,以及这两种模式的混合使用方式。不同的使用方法生命周期方法也不同。

非绑定模式:当第一次调用startService的时候执行的方法依次为onCreate()、onStartCommand(),当Service关闭的时候调用onDestory方法。

绑定模式:第一次bindService()的时候,执行的方法为onCreate()、onBind()解除绑定的时候会执行onUnbind()、onDestory()。

上面的两种生命周期是在相对单纯的模式下的情形。我们在开发的过程中还必须注意Service实例只会有一个,也就是说如果当前要启动的Service已经存在了那么就不会再次创建该Service当然也不会调用onCreate()方法。

一个Service可以被多个客户进行绑定,只有所有的绑定对象都执行了onBind()方法后该Service才会销毁,不过如果有一个客户执行了onStart()方法,那么这个时候如果所有的bind客户都执行了unBind()该Service也不会销毁。

Service的生命周期图如下所示,帮助大家记忆。

 

4、什么是IntentService?有何优点?

我们通常只会使用Service,可能IntentService对大部分同学来说都是第一次听说。那么看了下面的介绍相信你就不再陌生了。如果你还是不了解那么在面试的时候你就坦诚说没用过或者不了解等。并不是所有的问题都需要回答上来的。

一、IntentService简介

IntentService是Service的子类,比普通的Service增加了额外的功能。先看Service本身存在两个问题:

Service不会专门启动一条单独的进程,Service与它所在应用位于同一个进程中;

Service也不是专门一条新线程,因此不应该在Service中直接处理耗时的任务;

二、IntentService特征

会创建独立的worker线程来处理所有的Intent请求;

会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题;

所有请求处理完成后,IntentService会自动停止,无需调用stopSelf()方法停止Service;

为Service的onBind()提供默认实现,返回null;

为Service的onStartCommand提供默认实现,将请求Intent添加到队列中;

三、使用IntentService

本人写了一个IntentService的使用例子供参考。该例子中一个MainActivity一个MyIntentService,这两个类都是四大组件当然需要在清单文件中注册。这里只给出核心代码:

MainActivity.java:

 

 

MyIntentService.java

 

运行后效果如下:

 

5、说说Activity、Intent、Service是什么关系

他们都是Android开发中使用频率最高的类。其中Activity和Service都是Android四大组件之一。他俩都是Context类的子类ContextWrapper的子类,因此他俩可以算是兄弟关系吧。不过兄弟俩各有各自的本领,Activity负责用户界面的显示和交互,Service负责后台任务的处理。Activity和Service之间可以通过Intent传递数据,因此可以把Intent看作是通信使者。

6、Service和Activity在同一个线程吗

对于同一app来说默认情况下是在同一个线程中的,main Thread (UI Thread)。

7、Service里面可以弹吐司么

可以的。弹吐司有个条件就是得有一个Context上下文,而Service本身就是Context的子类,因此在Service里面弹吐司是完全可以的。比如我们在Service中完成下载任务后可以弹一个吐司通知用户。

四、BroadCastReceiver

1、请描述一下BroadcastReceiver

BroadCastReceiver是Android四大组件之一,主要用于接收系统或者app发送的广播事件。

广播分两种:有序广播和无序广播。

内部通信实现机制:通过Android系统的Binder机制实现通信。

无序广播:完全异步,逻辑上可以被任何广播接收者接收到。优点是效率较高。缺点是一个接收者不能将处理结果传递给下一个接收者,并无法终止广播intent的传播。

有序广播:按照被接收者的优先级顺序,在被接收者中依次传播。比如有三个广播接收者A,B,C,优先级是A > B > C。那这个消息先传给A,再传给B,最后传给C。每个接收者有权终止广播,比如B终止广播,C就无法接收到。此外A接收到广播后可以对结果对象进行操作,当广播传给B时,B可以从结果对象中取得A存入的数据。

在通过Context.sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler, initialCode, initialData, initialExtras)时我们可以指定resultReceiver广播接收者,这个接收者我们可以认为是最终接收者,通常情况下如果比他优先级更高的接收者如果没有终止广播,那么他的onReceive会被执行两次,第一次是正常的按照优先级顺序执行,第二次是作为最终接收者接收。如果比他优先级高的接收者终止了广播,那么他依然能接收到广播。

在我们的项目中经常使用广播接收者接收系统通知,比如开机启动、sd挂载、低电量、外播电话、锁屏等。

如果我们做的是播放器,那么监听到用户锁屏后我们应该将我们的播放之暂停等。

2、在manifest和代码中如何注册和使用BroadcastReceiver

在清单文件中注册广播接收者称为静态注册,在代码中注册称为动态注册。静态注册的广播接收者只要app在系统中运行则一直可以接收到广播消息,动态注册的广播接收者当注册的Activity或者Service销毁了那么就接收不到广播了。

静态注册:在清单文件中进行如下配置

" v:shapes="_x0000_s1057">

动态注册:在代码中进行如下注册

 

3、BroadCastReceiver的生命周期

a. 广播接收者的生命周期非常短暂的,在接收到广播的时候创建,onReceive()方法结束之后销毁;

b. 广播接收者中不要做一些耗时的工作,否则会弹出Application No Response错误对话框;

c. 最好也不要在广播接收者中创建子线程做耗时的工作,因为广播接收者被销毁后进程就成为了空进程,很容易被系统杀掉;

d. 耗时的较长的工作最好放在服务中完成;

4、如何让自己的广播只让指定的app接收(2015.09.02)

 

五、ContentProvider

1、请介绍下ContentProvider是如何实现数据共享的

在Android中如果想将自己应用的数据(一般多为数据库中的数据)提供给第三发应用,那么我们只能通过ContentProvider来实现了。

ContentProvider是应用程序之间共享数据的接口。使用的时候首先自定义一个类继承ContentProvider,然后覆写query、insert、update、delete等方法。因为其是四大组件之一因此必须在AndroidManifest文件中进行注册。

" v:shapes="_x0000_s1055">

第三方可以通过ContentResolver来访问该Provider。

2、请介绍下Android的数据存储方式

File存储

SharedPreference存储

ContentProvider存储

SQLiteDataBase存储

网络存储

3、为什么要用ContentProvider?它和sql的实现上有什么差别?

ContentProvider屏蔽了数据存储的细节,内部实现对用户完全透明,用户只需要关心操作数据的uri就可以了,ContentProvider可以实现不同app之间共享。

       Sql也有增删改查的方法,但是sql只能查询本应用下的数据库。而ContentProvider 还可以去增删改查本地文件. xml文件的读取等。

4、说说ContentProvider、ContentResolver、ContentObserver之间的关系

ContentProvider 内容提供者,用于对外提供数据

ContentResolver.notifyChange(uri)发出消息

ContentResolver 内容解析者,用于获取内容提供者提供的数据

ContentObserver 内容监听器,可以监听数据的改变状态

ContentResolver.registerContentObserver()监听消息。

六、Android中的布局

1、Android中常用的布局都有哪些

FrameLayout

RelativeLayout

LinearLayout

AbsoluteLayout

TableLayout

2、谈谈UI中, Padding和Margin有什么区别?

android:padding和android:layout_margin的区别,其实概念很简单,padding是站在父view的角度描述问题,它规定它里面的内容必须与这个父view边界的距离。margin则是站在自己的角度描述问题,规定自己和其他(上下左右)的view之间的距离,如果同一级只有一个view,那么它的效果基本上就和padding一样了。

 

七、ListView

1、ListView如何提高其效率?

① 复用ConvertView

② 自定义静态类ViewHolder

③ 使用分页加载

④ 使用WeakRefrence引用ImageView对象

2、当ListView数据集改变后,如何更新ListView

使用该ListView的adapter的notifyDataSetChanged()方法。该方法会使ListView重新绘制。

3、ListView如何实现分页加载

      ① 设置ListView的滚动监听器:setOnScrollListener(new OnScrollListener{….})

在监听器中有两个方法: 滚动状态发生变化的方法(onScrollStateChanged)和listView被滚动时调用的方法(onScroll)

      ② 在滚动状态发生改变的方法中,有三种状态:

手指按下移动的状态:                     SCROLL_STATE_TOUCH_SCROLL: // 触摸滑动

惯性滚动(滑翔(flgin)状态):     SCROLL_STATE_FLING: // 滑翔

静止状态:                                SCROLL_STATE_IDLE: // 静止

 对不同的状态进行处理:

分批加载数据,只关心静止状态:关心最后一个可见的条目,如果最后一个可见条目就是数据适配器(集合)里的最后一个,此时可加载更多的数据。在每次加载的时候,计算出滚动的数量,当滚动的数量大于等于总数量的时候,可以提示用户无更多数据了。

4、ListView可以显示多种类型的条目吗

这个当然可以的,ListView显示的每个条目都是通过baseAdapter的getView(int position, View convertView, ViewGroup parent)来展示的,理论上我们完全可以让每个条目都是不同类型的view,除此之外adapter还提供了getViewTypeCount()和getItemViewType(int position)两个方法。在getView方法中我们可以根据不同的viewtype加载不同的布局文件。

5、ListView如何定位到指定位置

可以通过ListView提供的lv.setSelection(48);方法。

6、如何在ScrollView中如何嵌入ListView

通常情况下我们不会在ScrollView中嵌套ListView,但是如果面试官非让我嵌套的话也是可以的。

在ScrollView添加一个ListView会导致listview控件显示不全,通常只会显示一条,这是因为两个控件的滚动事件冲突导致。所以需要通过listview中的item数量去计算listview的显示高度,从而使其完整展示,如下提供一个方法供大家参考。

 

 

7、ListView中如何优化图片

图片的优化策略比较多。

1、处理图片的方式:

如果ListView中自定义的Item中有涉及到大量图片的,一定要对图片进行细心的处理,因为图片占的内存是ListView项中最头疼的,处理图片的方法大致有以下几种:

①、不要直接拿路径就去循环BitmapFactory.decodeFile;使用Options保存图片大小、不要加载图片到内存去。

②、对图片一定要经过边界压缩尤其是比较大的图片,如果你的图片是后台服务器处理好的那就不需要了

③、在ListView中取图片时也不要直接拿个路径去取图片,而是以WeakReference(使用WeakReference代替强引用。比如可以使用WeakReference mContextRef)、SoftReference、WeakHashMap等的来存储图片信息。

④、在getView中做图片转换时,产生的中间变量一定及时释放

2、异步加载图片基本思想:

1)、 先从内存缓存中获取图片显示(内存缓冲)

2)、获取不到的话从SD卡里获取(SD卡缓冲)

3)、都获取不到的话从网络下载图片并保存到SD卡同时加入内存并显示(视情况看是否要显示)

原理:

优化一:先从内存中加载,没有则开启线程从SD卡或网络中获取,这里注意从SD卡获取图片是放在子线程里执行的,否则快速滑屏的话会不够流畅。

优化二:于此同时,在adapter里有个busy变量,表示listview是否处于滑动状态,如果是滑动状态则仅从内存中获取图片,没有的话无需再开启线程去外存或网络获取图片。

优化三:ImageLoader里的线程使用了线程池,从而避免了过多线程频繁创建和销毁,如果每次总是new一个线程去执行这是非常不可取的,好一点的用的AsyncTask类,其实内部也是用到了线程池。在从网络获取图片时,先是将其保存到sd卡,然后再加载到内存,这么做的好处是在加载到内存时可以做个压缩处理,以减少图片所占内存。

8、ListView中图片错位的问题是如何产生的

图片错位问题的本质源于我们的listview使用了缓存convertView,假设一种场景,一个listview一屏显示九个item,那么在拉出第十个item的时候,事实上该item是重复使用了第一个item,也就是说在第一个item从网络中下载图片并最终要显示的时候,其实该item已经不在当前显示区域内了,此时显示的后果将可能在第十个item上输出图像,这就导致了图片错位的问题。所以解决之道在于可见则显示,不可见则不显示。

9、Java中引用类型都有哪些

Java中对象的引用分为四种级别,这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用。

 强引用(StrongReference)

这个就不多说,我们写代码天天在用的就是强引用。如果一个对象被被人拥有强引用,那么垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。

Java的对象是位于heap中的,heap中对象有强可及对象、软可及对象、弱可及对象、虚可及对象和不可到达对象。应用的强弱顺序是强、软、弱、和虚。对于对象是属于哪种可及的对象,由他的最强的引用决定。如下代码:

softRef=new SoftReference(abc); //2 WeakReference weakRef = new WeakReference(abc); //3 abc=null; //4 softRef.clear();//5 " v:shapes="_x0000_s1048">

第一行在heap堆中创建内容为“abc”的对象,并建立abc到该对象的强引用,该对象是强可及的。

第二行和第三行分别建立对heap中对象的软引用和弱引用,此时heap中的abc对象已经有3个引用,显然此时abc对象仍是强可及的。

第四行之后heap中对象不再是强可及的,变成软可及的。

第五行执行之后变成弱可及的。

 软引用(SoftReference)

如果一个对象只具有软引用,那么如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。

软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

软引用是主要用于内存敏感的高速缓存。在jvm报告内存不足之前会清除所有的软引用,这样以来gc就有可能收集软可及的对象,可能解决内存吃紧问题,避免内存溢出。什么时候会被收集取决于gc的算法和gc运行时可用内存的大小。当gc决定要收集软引用时执行以下过程,以上面的softRef为例:

    1 首先将softRef的referent(abc)设置为null,不再引用heap中的new String("abc")对象。

    2 将heap中的new String("abc")对象设置为可结束的(finalizable)。

    3 当heap中的new String("abc")对象的finalize()方法被运行而且该对象占用的内存被释放, softRef被添加到它的ReferenceQueue(如果有的话)中。

   注意:对ReferenceQueue软引用和弱引用可以有可无,但是虚引用必须有。

  被 Soft Reference 指到的对象,即使没有任何 Direct Reference,也不会被清除。一直要到 JVM 内存不足且没有Direct Reference 时才会清除,SoftReference 是用来设计 object-cache 之用的。如此一来 SoftReference 不但可以把对象 cache 起来,也不会造成内存不足的错误 (OutOfMemoryError)。

 弱引用(WeakReference)

如果一个对象只具有弱引用,那该类就是可有可无的对象,因为只要该对象被gc扫描到了随时都会把它干掉。弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。

弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

 虚引用(PhantomReference)

"虚引用"顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。虚引用主要用来跟踪对象被垃圾回收的活动。

虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

建立虚引用之后通过get方法返回结果始终为null,通过源代码你会发现,虚引用通向会把引用的对象写进referent,只是get方法返回结果为null。先看一下和gc交互的过程再说一下他的作用。

  1 不把referent设置为null, 直接把heap中的new String("abc")对象设置为可结束的(finalizable)。

  2 与软引用和弱引用不同, 先把PhantomRefrence对象添加到它的ReferenceQueue中.然后在释放虚可及的对象。

八、JNI&NDK

1、在Android中如何调用C语言

当我们的Java需要调用C语言的时候可以通过JNI的方式,Java Native Interface。Android提供了对JNI的支持,因此我们在Android中可以使用JNI调用C语言。在Android开发目录的libs目录下添加xxx.so文件,不过xxx.so文件需要放在对应的CPU架构名目录下,比如armeabi,x86等。

在Java代码需要通过System.loadLibrary(libName);加载so文件。同时C语言中的方法在java中必须以native关键字来声明。普通Java方法调用这个native方法接口,虚拟机内部自动调用so文件中对应的方法。

2、请介绍一下NDK

1.NDK 是一系列工具的集合

NDK 提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so 和java 应用一起打包成apk。NDK 集成了交叉编译器,并提供了相应的mk 文件隔离CPU、平台、ABI 等差异,开发人员只需要简单修改mk 文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。

2.NDK 提供了一份稳定、功能有限的API 头文件声明

Google 明确声明该API 是稳定的,在后续所有版本中都稳定支持当前发布的API。从该版本的NDK 中看出,这些API 支持的功能非常有限,包含有:C 标准库(libc)、标准数学库(libm)、压缩库(libz)、Log 库(liblog)。

3、JNI调用常用的两个参数

 JNIEnv *env, jobject obj

第一个是指向虚拟机对象的指针,是一个二级指针。里面封装了很多方法和中间变量供我们使用。

第二个代表着调用该方法的Java对象的C语言表示。

九、Android中的网络访问

1、Android中如何访问网络

Android提供了org.apache.http.HttpClientConnection和java.net.HttpURLConnection两个连接网络对象。使用哪个都行,具体要看企业领导的要求了。

除此之外一般我比较喜欢使用xUtils中的HttpUtils功能,该模块底层使用的就是org.apache.http.client.HttpClient,使用起来非常方便。

2、如何解析服务器传来的JSON文件

在Android中内置了JSON的解析API,在org.json包中包含了如下几个类:JSONArray、JSONObject、JSONStringer、JSONTokener和一个异常类JSONException。

 

1、JSON解析步骤

1)、读取网络文件数据并转为一个json字符串

       InputStream in = conn.getInputStream();

       String jsonStr = DataUtil.Stream2String(in);//将流转换成字符串的工具类

2)、将字符串传入相应的JSON构造函数中

①、通过构造函数将json字符串转换成json对象

       JSONObject  jsonObject = new JSONObject(jsonStr);

②、通过构造函数将json字符串转换成json数组:

JSONArray array = new JSONArray(jsonStr);

3)、解析出JSON中的数据信息:

①、从json对象中获取你所需要的键所对应的值

       JSONObject  json=jsonObject.getJSONObject("weatherinfo");

       String city = json.getString("city");

       String temp = json.getString("temp")

②、遍历JSON数组,获取数组中每一个json对象,同时可以获取json对象中键对应的值

       for (int i = 0; i < array.length(); i++) {

              JSONObject obj = array.getJSONObject(i);

              String title=obj.getString("title");

              String description=obj.getString("description");

       }

2、生成JSON对象和数组

1)生成JSON:

方法1、创建一个map,通过构造方法将map转换成json对象

       Map<String, Object> map = new HashMap<String, Object>();

       map.put("name", "zhangsan");

       map.put("age", 24);

       JSONObject json = new JSONObject(map);

方法2、创建一个json对象,通过put方法添加数据

       JSONObject json=new JSONObject();

       json.put("name", "zhangsan");

       json.put("age", 24);

2)生成JSON数组:

创建一个list,通过构造方法将list转换成json对象

       Map<String, Object> map1 = new HashMap<String, Object>();

       map1.put("name", "zhangsan");

       map1.put("age", 24);

       Map<String, Object> map2 = new HashMap<String, Object>();

       map2.put("name", "lisi");

       map2.put("age", 25);

       List<Map<String, Object>> list=new ArrayList<Map<String,Object>>();

       list.add(map1);

       list.add(map2);

       JSONArray array=new JSONArray(list);

       System.out.println(array.toString());

3、如何解析服务器传来的XML格式数据

Android为我们提供了原生的XML解析和生成支持。

1、XML解析

              获取解析器: Xml.newPullParser()

              设置输入流: setInput()

              获取当前事件类型: getEventType()

              解析下一个事件, 获取类型: next()

              获取标签名: getName()

              获取属性值: getAttributeValue()

              获取下一个文本: nextText()

              获取当前文本: getText()

              5种事件类型: START_DOCUMENT, END_DOCUMENT, START_TAG, END_TAG, TEXT

示例代码:

public List<Person> getPersons(InuptStream in){ 

       XmlPullParser parser=Xml.newPullParser();//获取解析器

       parser.setInput(in,"utf-8");

       for(int type=){   //循环解析

       }     

}

2、XML生成

              获取生成工具: Xml.newSerializer()

              设置输出流: setOutput()

              开始文档: startDocument()

              结束文档: endDocument()

              开始标签: startTag()

              结束标签: endTag()

              属性: attribute()

              文本: text()   

示例代码:

XmlSerializer serial=Xml.newSerializer();//获取xml序列化工具

serial.setOuput(put,"utf-8");

serial.startDocument("utf-8",true);

serial.startTag(null,"persons");

for(Person p:persons){

       serial.startTag(null,"persons");     

       serial.attribute(null,"id",p.getId().toString());

       serial.startTag(null,"name");  

       serial.attribute(null,"name",p.getName().toString());

       serial.endTag(null,"name");

       serial.startTag(null,"age");      

       serial.attribute(null,"age",p.getAge().toString());

       serial.endTag(null,"age");

       serial.endTag(null,"persons");      

}

4、如何从网络上加载一个图片显示到界面

可以通过BitmapFactory.decodeStream(inputStream);方法将图片转换为bitmap,然后通过

imageView.setImageBitmap(bitmap);将该图片设置到ImageView中。这是原生的方法,还可以使用第三方开源的工具来实现,比如使用SmartImageView作为ImageView控件,然后直接设置一个url地址即可。也可以使用xUtils中的BitmapUtils工具。

5、如何播放网络视频

除了使用Android提供的MediaPlayer和VideoView外通常还可以使用第三方开源万能播放器,VitamioPlayer。该播放器兼容性好,支持几乎所有主流视频格式。

十、Intent

1、Intent传递数据时,可以传递哪些类型数据?

       Intent可以传递的数据类型非常的丰富,java的基本数据类型和String以及他们的数组形式都可以,除此之外还可以传递实现了Serializable和Parcelable接口的对象。

2、Serializable和Parcelable的区别

1.在使用内存的时候,Parcelable 类比Serializable性能高,所以推荐使用Parcelable类。

2.Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。

3.Parcelable不能使用在要将数据存储在磁盘上的情况。尽管Serializable效率低点,但在这种情况下,还是建议你用Serializable 。

实现:

1 Serializable 的实现,只需要继承Serializable 即可。这只是给对象打了一个标记,系统会自动将其序列化。

2 Parcelabel 的实现,需要在类中添加一个静态成员变量 CREATOR,这个变量需要继承 Parcelable.Creator 接口。

CREATOR = new Parcelable.Creator() { public MyParcelable createFromParcel(Parcel in) { return new MyParcelable(in); } public MyParcelable[] newArray(int size) { return new MyParcelable[size]; } }; private MyParcelable(Parcel in) { mData = in.readInt(); } } " v:shapes="_x0000_s1054">

3、请描述一下Intent 和 IntentFilter

Android 中通过 Intent 对象来表示一条消息,一个 Intent 对象不仅包含有这个消息的目的地,还可以包含消息的内容,这好比一封 Email,其中不仅应该包含收件地址,还可以包含具体的内容。对于一个 Intent 对象,消息“目的地”是必须的,而内容则是可选项。

通过Intent 可以实现各种系统组件的调用与激活. 

IntentFilter: 可以理解为邮局或者是一个信笺的分拣系统…

这个分拣系统通过3个参数来识别

Action: 动作    view

Data: 数据uri   uri

Category : 而外的附加信息

Action 匹配

Action 是一个用户定义的字符串,用于描述一个 Android 应用程序组件,一个 IntentFilter 可以包含多个 Action。在 AndroidManifest.xml 的 Activity 定义时可以在其 <intent-filter >节点指定一个 Action 列表用于标示 Activity 所能接受的“动作”,例如:

 <intent-filter >

 <action android:name="android.intent.action.MAIN" />

 <action android:name="cn.itheima.action" />

……

 </intent-filter>

如果我们在启动一个 Activity 时使用这样的 Intent 对象:

 Intent intent =new Intent();

 intent.setAction("cn.itheima.action");

那么所有的 Action 列表中包含了“cn.itheima”的 Activity 都将会匹配成功。

Android 预定义了一系列的 Action 分别表示特定的系统动作。这些 Action 通过常量的方式定义在 android.content. Intent中,以“ACTION_”开头。我们可以在 Android 提供的文档中找到它们的详细说明。

URI 数据匹配

一个 Intent 可以通过 URI 携带外部数据给目标组件。在 <intent-filter >节点中,通过 <data/>节点匹配外部数据。

mimeType 属性指定携带外部数据的数据类型,scheme 指定协议,host、port、path 指定数据的位置、端口、和路径。如下:

 <data android:mimeType="mimeType" android:scheme="scheme"

 android:host="host" android:port="port" android:path="path"/>

电话的uri   tel: 12345

                 http://www.baidu.com

自己定义的uri  itcast://cn.itcast/person/10

如果在 Intent Filter 中指定了这些属性,那么只有所有的属性都匹配成功时 URI 数据匹配才会成功。

Category 类别匹配

<intent-filter >节点中可以为组件定义一个 Category 类别列表,当 Intent 中包含这个列表的所有项目时 Category 类别匹配才会成功。

4、under what condition could the code sample below crash your application?How would you modify the code to avoid this potential problem?Explain your answer?

Intent sendIntent = new Intent();

sendIntent.setAction(Intent.ACTION_SEND);

sendIntent.putExtra(Intent.EXTRA_TEXT,textMessage);

sendIntent.setType(HTTP.PLAIN_TEXT_TYEP);//"text/plain" MIME type

content.startActivity(sendIntent);

 

5、what are Activity and Fragment?where and why should you use one over the other?

 

6、can you use an intent to provide data to a ContentProvider ? if not ,what would be the proper mechanism for doing this?

 

十一、Fragment

1、Fragment跟Activity之间是如何传值的

当Fragment跟Activity绑定之后,在Fragment中可以直接通过getActivity()方法获取到其绑定的Activity对象,这样就可以调用Activity的方法了。在Activity中可以通过如下方法获取到Fragment实例


获取到Fragment之后就可以调用Fragment的方法。也就实现了通信功能。

2、描述一下Fragment的生命周期

 

3、Fragment的replace和add方法的区别(2015.8.30)

Fragment本身并没有replace和add方法,这里的理解应该为使用FragmentManager的replace和add两种方法切换Fragment时有什么不同。

我们经常使用的一个架构就是通过RadioGroup切换Fragment,每个Fragment就是一个功能模块。

 

实现这个功能可以通过replace和add两种方法。

Fragment的容器一个FrameLayout,add的时候是把所有的Fragment一层一层的叠加到了FrameLayout上了,而replace的话首先将该容器中的其他Fragment去除掉然后将当前Fragment添加到容器中。

一个Fragment容器中只能添加一个Fragment种类,如果多次添加则会报异常,导致程序终止,而replace则无所谓,随便切换。

因为通过add的方法添加的Fragment,每个Fragment只能添加一次,因此如果要想达到切换效果需要通过Fragment的的hide和show方法结合者使用。将要显示的show出来,将其他hide起来。这个过程Fragment的生命周期没有变化。

通过replace切换Fragment,每次都会执行上一个Fragment的onDestroyView,新Fragment的onCreateView、onStart、onResume方法。

基于以上不同的特点我们在使用的使用一定要结合着生命周期操作我们的视图和数据。

4、Fragment如何实现类似Activity栈的压栈和出栈效果的?(2015.8.30)

Fragment的事物管理器内部维持了一个双向链表结构,该结构可以记录我们每次add的Fragment和replace的Fragment,然后当我们点击back按钮的时候会自动帮我们实现退栈操作。

 

除此之外因为我们要使用FragmentManger用的是FragmentActivity,因此FragmentActivity的onBackPress方法必定重新覆写了。打开看一下,发现确实如此。

 

= 0) { //从后退栈中取出当前记录对象 BackStackRecord bss = mBackStack.get(index); if (name != null && name.equals(bss.getName())) { break; } if (id >= 0 && id == bss.mIndex) { break; } index--; } " v:shapes="文本框_x0020_119">

5. Android高级(★★★)

一、Android性能优化

1、如何对Android应用进行性能分析

一款App流畅与否安装在自己的真机里,玩几天就能有个大概的感性认识。不过通过专业的分析工具可以使我们更好的分析我们的应用。

如果不考虑使用其他第三方性能分析工具的话,我们可以直接使用ddms中的工具,其实ddms工具已经非常的强大了。ddms中有traceview、heap、allocation tracker等工具都可以帮助我们分析应用的方法执行时间效率和内存使用情况。

 traceview工具在本文章中已经有详细的介绍,因此这里就不再赘述。

 heap

heap工具可以帮助我们检查代码中是否存在会造成内存泄漏的地方。

用heap监测应用进程使用内存情况的步骤如下:

1. 启动eclipse后,切换到DDMS透视图,并确认Devices视图、Heap视图都是打开的;

2. 点击选中想要监测的进程,比如system_process进程;

3. 点击选中Devices视图界面中最上方一排图标中的“Update Heap”图标;

6. 点击Heap视图中的“Cause GC”按钮;

7. 此时在Heap视图中就会看到当前选中的进程的内存使用量的详细情况。

 说明:

a) 点击“Cause GC”按钮相当于向虚拟机请求了一次gc操作;

b) 当内存使用信息第一次显示以后,无须再不断的点击“Cause GC”,Heap视图界面会定时刷新,在对应用的不断的操作过程中就可以看到内存使用的变化;

c) 内存使用信息的各项参数根据名称即可知道其意思,在此不再赘述。

  如何才能知道我们的程序是否有内存泄漏的可能性呢。这里需要注意一个值:Heap视图中部有一个Type叫做data object,即数据对象,也就是我们的程序中大量存在的类类型的对象。在data object一行中有一列是“Total Size”,其值就是当前进程中所有Java数据对象的内存总量,一般情况下,这个值的大小决定了是否会有内存泄漏。可以这样判断:

a) 不断的操作当前应用,同时注意观察data object的Total Size值;

b) 正常情况下Total Size值都会稳定在一个有限的范围内,也就是说由于程序中的的代码良好,没有造成对象不被垃圾回收的情况,所以说虽然我们不断的操作会不断的生成很多对象,而在虚拟机不断的进行GC的过程中,这些对象都被回收了,内存占用量会会落到一个稳定的水平;

c) 反之如果代码中存在没有释放对象引用的情况,则data object的Total Size值在每次GC后不会有明显的回落,随着操作次数的增多Total Size的值会越来越大,

  直到到达一个上限后导致进程被kill掉。

d) 此处以system_process进程为例,在我的测试环境中system_process进程所占用的内存的data object的Total Size正常情况下会稳定在2.2~2.8之间,而当其值超过3.55后进程就会被kill。

  总之,使用DDMS的Heap视图工具可以很方便的确认我们的程序是否存在内存泄漏的可能性。

 allocation tracker

运行DDMS,只需简单的选择应用进程并单击Allocation tracker标签,就会打开一个新的窗口,单击“Start Tracing”按钮;

然后,让应用运行你想分析的代码。运行完毕后,单击“Get Allocations”按钮,一个已分配对象的列表就会出现第一个表格中。

单击第一个表格中的任何一项,在表格二中就会出现导致该内存分配的栈跟踪信息。通过allocation tracker,不仅知道分配了哪类对象,还可以知道在哪个线程、哪个类、哪个文件的哪一行。

2、什么情况下会导致内存泄露

Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M,有的机器为24M。因此我们所能利用的内存空间是有限的。如果我们的内存占用超过了一定的水平就会出现OutOfMemory的错误。

内存溢出的几点原因:

1、资源释放问题

程序代码的问题,长期保持某些资源,如Context、Cursor、IO流的引用,资源得不到释放造成内存泄露。

2、对象内存过大问题

保存了多个耗用内存过大的对象(如Bitmap、XML文件),造成内存超出限制。

3、static关键字的使用问题

static是Java中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。所以用static修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例(Context的情况最多),这时就要谨慎对待了。

public class ClassName { 

     private static Context mContext; 

     //省略

}

以上的代码是很危险的,如果将Activity赋值到mContext的话。那么即使该Activity已经onDestroy,但是由于仍有对象保存它的引用,因此该Activity依然不会被释放。

我们举Android文档中的一个例子。

 

 

 

 

 

sBackground是一个静态的变量,但是我们发现,我们并没有显式的保存Contex的引用,但是,当Drawable与View连接之后,Drawable就将View设置为一个回调,由于View中是包含Context的引用的,所以,实际上我们依然保存了Context的引用。这个引用链如下:

    Drawable->TextView->Context

    所以,最终该Context也没有得到释放,发生了内存泄露。

 针对static的解决方案

① 应该尽量避免static成员变量引用资源耗费过多的实例,比如Context。

    ② Context尽量使用ApplicationContext,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题。

    ③ 使用WeakReference代替强引用。比如可以使用WeakReference<Context> mContextRef;

4、线程导致内存溢出

线程产生内存泄露的主要原因在于线程生命周期的不可控。我们来考虑下面一段代码。

 

 

 

这段代码很平常也很简单,是我们经常使用的形式。我们思考一个问题:假设MyThread的run函数是一个很费时的操作,当我们开启该线程后,将设备的横屏变为了竖屏,一 般情况下当屏幕转换时会重新创建Activity,按照我们的想法,老的Activity应该会被销毁才对,然而事实上并非如此。

由于我们的线程是Activity的内部类,所以MyThread中保存了Activity的一个引用,当MyThread的run函数没有结束时,MyThread是不会被销毁的,因此它所引用的老的Activity也不会被销毁,因此就出现了内存泄露的问题。

有些人喜欢用Android提供的AsyncTask,但事实上AsyncTask的问题更加严重,Thread只有在run函数不结束时才出现这种内存泄露问题,然而AsyncTask内部的实现机制是运用了ThreadPoolExcutor,该类产生的Thread对象的生命周期是不确定的,是应用程序无法控制的,因此如果AsyncTask作为Activity的内部类,就更容易出现内存泄露的问题。

针对这种线程导致的内存泄露问题的解决方案:

    第一、将线程的内部类,改为静态内部类(因为非静态内部类拥有外部类对象的强引用,而静态类则不拥有)。

    第二、在线程内部采用弱引用保存Context引用。

3、如何避免OOM异常

想要避免OOM异常首先我们要知道什么情况下会导致OOM异常。

1、图片过大导致OOM

Android 中用bitmap时很容易内存溢出,比如报如下错误:Java.lang.OutOfMemoryError : bitmap size exceeds VM budget。

解决方法:

方法1: 等比例缩小图片

 

以上代码可以优化内存溢出,但它只是改变图片大小,并不能彻底解决内存溢出。

方法2:对图片采用软引用,及时地进行recyle()操作

bitmap = new SoftReference(pBitmap); if(bitmap != null){ if(bitmap.get() != null && !bitmap.get().isRecycled()){ bitmap.get().recycle(); bitmap = null; } } " v:shapes="_x0000_s1044">

2、界面切换导致OOM

有时候我们会发现这样的问题,横竖屏切换N次后 OOM了。

这种问题没有固定的解决方法,但是我们可以从以下几个方面下手分析。

1、看看页面布局当中有没有大的图片,比如背景图之类的。

去除xml中相关设置,改在程序中设置背景图(放在onCreate()方法中):

 

    在Activity destory时注意,drawable.setCallback(null); 防止Activity得不到及时的释放。

 2、跟上面方法相似,直接把xml配置文件加载成view 再放到一个容器里,然后直接调用 this.setContentView(View view);方法,避免xml的重复加载。

3、 在页面切换时尽可能少地重复使用一些代码

比如:重复调用数据库,反复使用某些对象等等......

常见的内存使用不当的情况

3、查询数据库没有关闭游标

程序中经常会进行查询数据库的操作,但是经常会有使用完毕Cursor后没有关闭的情况。如果我们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会出现内存问题,这样就会给以后的测试和问题排查带来困难和风险。

4、构造Adapter时,没有使用缓存的 convertView

在使用ListView的时候通常会使用Adapter,那么我们应该尽可能的使用ConvertView。

5、Bitmap对象不再使用时调用recycle()释放内存

有时我们会手工的操作Bitmap对象,如果一个Bitmap对象比较占内存,当它不再被使用的时候,可以调用Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是必须的,视情况而定。

6、其他

  Android应用程序中最典型的需要注意释放资源的情况是在Activity的生命周期中,在onPause()、onStop()、 onDestroy()方法中需要适当的释放资源的情况。

4、Android中如何捕获未捕获的异常

1、自定义一个Application,比如叫MyApplication继承Application实现UncaughtExceptionHandler。

2、覆写UncaughtExceptionHandler的onCreate和uncaughtException方法。

 

注意:上面的代码只是简单的将异常打印出来。

在onCreate方法中我们给Thread类设置默认异常处理handler,如果这句代码不执行则一切都是白搭。

在uncaughtException方法中我们必须新开辟个线程进行我们异常的收集工作,然后将系统给杀死。

3、在AndroidManifest中配置该Application

 

4、blog分享

关于异常数据的收集在网上有一篇不错的blog可以推荐给大家。

http://blog.csdn.net/jdsjlzx/article/details/7606423

二、Android屏幕适配

1、屏幕适配方式都有哪些

1.1 适配方式之dp

名词解释:

 分辨率:eg:480*800,1280*720。表示物理屏幕区域内像素点的总和。(切记:跟屏幕适配没有任何关系)

   因为我们既可以把1280*720的分辨率做到4.0的手机上面。我也可以把1280*720的分辨率做到5.0英寸的手机上面,如果分辨率相同,手机屏幕越小清晰。

 px(pix):像素,就是屏幕中最小的一个显示单元

 dpi(像素密度):即每英寸屏幕所拥有的像素数,像素密度越大,显示画面细节就越丰富。

计算公式:像素密度=√{(长度像素数^2+宽度像素数^2)}/ 屏幕尺寸

注:屏幕尺寸单位为英寸 例:分辨率为1280*720 屏幕宽度为6英寸 计算所得像素密度约等于245,屏幕尺寸指屏幕对角线的长度。

在Android手机中dpi分类:

ldpi

Resources for low-density (ldpi) screens (~120dpi).

mdpi

Resources for medium-density (mdpi) screens (~160dpi). (This is the baseline density.)

hdpi

Resources for high-density (hdpi) screens (~240dpi).

xhdpi

Resources for extra high-density (xhdpi) screens (~320dpi).

在我们的Android工程目录中有如下drawable-*dpi目录,这些目录是用来适配不同分辨率手机的。

 

Android应用在查找图片资源时会根据其分辨率自动从不同的文件目录下查找(这本身就是Android系统的适配策略),如果在低分辨的文件目录中比如drawable-mdpi中没有图片资源,其他目录中都有,当我们将该应用部署到mdpi分辨率的手机上时,那么该应用会查找分辨率较高目录下的资源文件,如果较高分辨率目录下也没有资源则只好找较低目录中的资源了。

常见手机屏幕像素及对应分别率级别:

 ldpi  320*240    

 mdpi  480*320    

 hdpi  800*480

 xhdpi  1280*720

 xxhdpi  1920*1080

dp和px之间的简单换算关系:

 

 ldpi的手机 1dp=0.75px

 mdpi的手机 1dp=1.0px

 hdpi的手机 1dp=1.5px

 xhdpi的手机 1dp=2.0px

 xxhdpi的手机 1dp=3.0px

 

:根据上面的描述我们得出如下结论,对于mdpi的手机,我们的布局通过dp单位可以达到适配效果。

1.2 适配方式之dimens

跟drawable目录类似的,在Android工程的res目录下有values目录,这个是默认的目录,同时为了适配不同尺寸手机我们可以创建一个values-1280x720的文件夹,同时将dimens.xml文件拷贝到该目录下。

 

在dimens.xml中定义一个尺寸,如下图所示。

 

在values-1280x720目录中的dimens.xml中定义同样的尺寸名称,但是使用不同的尺寸,如下图所示。

 

当我们在布局文件中使用长或者宽度单位时,比如下图所示,应该使用@dimen/width来灵活的定义宽度。

 

:在values-1280x720中,中间的是大写字母X的小写形式x,而不是加减乘除的乘号。如果我们在values-1280x720中放置了dimens常量,一定记得也将该常量的对应值在values目录下的dimens.xml中放一份,因为该文件是默认配置,当用户的手机不是1280*720的情况下系统应用使用的是默认values目录中的dimens.xml。

1.3 适配方式之layout

跟values一样,在Android工程目录中layout目录也支持类似values目录一样的适配,在layout中我们可以针对不同手机的分辨率制定不同的布局,如下图所示。

 

1.4 适配方式之java代码适配

为了演示用java代码控制适配的效果,因此假设有这样的需求,让一个TextView控件的宽和高分别为屏幕的宽和高的一半。

我们新创建一个Android工程,修改main_activity.xml,布局文件清单如下:

" v:shapes="_x0000_s1040">

" v:shapes="_x0000_s1039">

在MainActivity.java类中完成用java代码控制TextView的布局效果,其代码清单如下:

 

其中Constant类是一个常量类,很简单,只有两个常量用来记录屏幕的宽和高,其代码清单如下:

 

1.5适配方式之weight权重适配

在控件中使用属性android:layout_weight="1"以起到适配效果,但是该属性的使用有如下规则:

1、只能用在线性控件中,比如LinearLayout。

2、竖直方向上使用权重的控件高度必须为0dp(Google官方的推荐用法)

3、水平方向上使用权重的控件宽度必须为0dp(Google官方的推荐用法)

2、屏幕适配的处理技巧都有哪些

手机自适应主要分为两种情况:横屏和竖屏的切换,以及分辨率大小的不同。

2.1横屏和竖屏的切换

1、Android应用程序支持横竖屏幕的切换,Android中每次屏幕的切换动会重启Activity,所以应该在Activity销毁(执行onPause()方法和onDestroy()方法)前保存当前活动的状态;在Activity再次创建的时候载入配置,那样,进行中的游戏就不会自动重启了!有的程序适合从竖屏切换到横屏,或者反过来,这个时候怎么办呢?可以在配置Activity的地方进行如下的配置android:screenOrientation="portrait"(landscape是横向,portrait是纵向)。这样就可以保证是竖屏总是竖屏了。

2、而有的程序是适合横竖屏切换的。如何处理呢?首先要在配置Activity的时候进行如下的配置:

android:configChanges="keyboardHidden|orientation",另外需要重写Activity的onConfigurationChanged方法。实现方式如下:

 

2.2分辨率大小不同

对于分辨率问题,官方给的解决办法是创建不同的layout文件夹,这就需要对每种分辨率的手机都要写一个布局文件,虽然看似解决了分辨率的问题,但是如果其中一处或多处有修改了,就要每个布局文件都要做出修改,这样就造成很大的麻烦。那么可以通过以下几种方式解决:

一)使用layout_weight

目前最为推荐的Android多屏幕自适应解决方案。

    该属性的作用是决定控件在其父布局中的显示权重,一般用于线性布局中。其值越小,则对应的layout_width或layout_height的优先级就越高(一般到100作用就不太明显了);一般横向布局中,决定的是layout_width的优先级;纵向布局中,决定的是layout_height的优先级。

    传统的layout_weight使用方法是将当前控件的layout_width和layout_height都设置成fill_parent,这样就可以把控件的显示比例完全交给layout_weight;这样使用的话,就出现了layout_weight越小,显示比例越大的情况(即权重越大,显示所占的效果越小)。不过对于2个控件还好,如果控件过多,且显示比例也不相同的时候,控制起来就比较麻烦了,毕竟反比不是那么好确定的。于是就有了现在最为流行的0px设值法。看似让人难以理解的layout_height=0px的写法,结合layout_weight,却可以使控件成正比例显示,轻松解决了当前Android开发最为头疼的碎片化问题之一。

二)清单文件配置:【不建议使用这种方式,需要对不同的界面写不同的布局】

需要在AndroidManifest.xml文件的<manifest>元素如下添加子元素

<supports-screensandroid:largeScreens="true"

android:normalScreens="true"

android:anyDensity="true"

android:smallScreens="true"

android:xlargeScreens="true">

</supports-screens>

以上是为我们的屏幕设置多分辨率支持(更准确的说是适配大、中、小三种密度)。

Android:anyDensity="true",这一句对整个的屏幕都起着十分重要的作用,值为true,我们的应用程序当安装在不同密度的手机上时,程序会分别加载hdpi,mdpi,ldpi文件夹中的资源。相反,如果值设置为false,即使我们在hdpi,mdpi,ldpi,xdpi文件夹下拥有同一种资源,那么应用也不会自动地去相应文件夹下寻找资源。而是会在大密度和小密度手机上加载中密度mdpi文件中的资源。

有时候会根据需要在代码中动态地设置某个值,可以在代码中为这几种密度分别设置偏移量,但是这种方法最好不要使用,最好的方式是在xml文件中不同密度的手机进行分别设置。这里地图的偏移量可以在values-xpdi,values-hpdi,values-mdpi,values-ldpi四种文件夹中的dimens.xml文件进行设置。

三)、其他:

说明:

       在不同分辨率的手机模拟器下,控件显示的位置会稍有不同

       通过在layout中定义的布局设置的参数,使用dp(dip),会根据不同的屏幕分辨率进行适配

       但是在代码中的各个参数值,都是使用的像素(px)为单位的

技巧:

1、尽量使用线性布局,相对布局,如果屏幕放不下了,可以使用ScrollView(可以上下拖动)

ScrowView使用的注意:

在不同的屏幕上显示内容不同的情况,其实这个问题我们往往是用滚动视图来解决的,也就是ScrowView;需要注意的是ScrowView中使用layout_weight是无效的,既然使用ScrowView了,就把它里面的控件的大小都设成固定的吧。

2、指定宽高的时候,采用dip的单位,dp单位动态匹配

3、由于android代码中写的单位都是像素,所有需要通过工具类进行转化

4、尽量使用9-patch图,可以自动的依据图片上面显示的内容被拉伸和收缩。其中在编辑的时候,灰色区域是被拉伸的,上下两个点控制水平方向的拉伸,左右两点控制垂直方向的拉伸

3、dp和px之间的关系

dp:是dip的简写,指密度无关的像素。

       指一个抽象意义上的像素,程序用它来定义界面元素。一个与密度无关的,在逻辑尺寸上,与一个位于像素密度为160dpi的屏幕上的像素是一致的。要把密度无关像素转换为屏幕像素,可以用这样一个简单的公式:pixels=dips*(density/160)。举个例子,在DPI为240的屏幕上,1个DIP等于1.5个物理像素。

布局时最好使用dp来定义我们程序的界面,因为这样可以保证我们的UI在各种分辨率的屏幕上都可以正常显示。

 

三、AIDL

1、什么是AIDL以及如何使用

①aidl是Android interface definition Language 的英文缩写,意思Android 接口定义语言。

②使用aidl可以帮助我们发布以及调用远程服务,实现跨进程通信。

③将服务的aidl放到对应的src目录,工程的gen目录会生成相应的接口类

我们通过bindService(Intent,ServiceConnect,int)方法绑定远程服务,在bindService中有一个ServiceConnec接口,我们需要覆写该类的onServiceConnected(ComponentName,IBinder)方法,这个方法的第二个参数IBinder对象其实就是已经在aidl中定义的接口,因此我们可以将IBinder对象强制转换为aidl中的接口类。

我们通过IBinder获取到的对象(也就是aidl文件生成的接口)其实是系统产生的代理对象,该代理对象既可以跟我们的进程通信,又可以跟远程进程通信,作为一个中间的角色实现了进程间通信。

四、自定义控件

1、如何自定义一个控件

自定义控件可以分为两种自定义组合控件和自定义view。

 自定义组合控件

自定义组合控件就是把多个控件做为一个整体看待、处理。这样的好处不仅可以减轻xml的代码量,也提高了代码的复用性。

在手机卫士项目中我们第一次接触了自定义组合控件。

1. 声明一个View 对象,继承相对布局,或者线性布局或者其他的ViewGroup。

2. 在自定义的View 对象里面重写它的构造方法,在构造方法里面就把布局都初始化完毕。

3. 根据业务需求添加一些api 方法,扩展自定义的组合控件;

4. 希望在布局文件里面可以自定义一些属性。

5. 声明自定义属性的命名空间。

xmlns:itheima="http://schemas.android.com/apk/res/com.itheima.mobilesafe"

6. 在res 目录下的values 目录下创建attrs.xml 的文件声明我们写的属性。

7. 在布局文件中写自定义的属性。

8. 使用这些定义的属性。自定义View 对象的构造方法里面有一个带两个参数的构造方法布局文件里面定义的属性都放在AttributeSet attrs,获取那些定义的属性。

 自定义view

自定义View首先要实现一个继承自View的类。添加类的构造方法,通常是三个构造方法,不过从Android5.0开始构造方法已经添加到4个了。override父类的方法,如onDraw,(onMeasure)等。如果自定义的View有自己的属性,需要在values下建立attrs.xml文件,在其中定义属性,同时代码也要做修改。

blog分享:http://blog.csdn.net/lmj623565791/article/details/24252901

2、请描述一下View的绘制流程

整个View树的绘图流程是在ViewRoot.java类(该类位于Android源码下面:D:\AndroidSource_GB\AndroidSource_GB\frameworks\base\core\java\android\view)的performTraversals()函数展开的,该函数做的执行过程可简单概况为根据之前设置的状态,判断是否需要重新计算视图大小(measure)、是否重新需要安置视图的位置(layout)、以及是否需要重绘 (draw),其框架过程如下:

 

1、mesarue()过程

  主要作用:为整个View树计算实际的大小,即设置实际的高(对应属性:mMeasuredHeight)和宽(对应属性:

  mMeasureWidth),每个View的控件的实际宽高都是由父视图和本身视图决定的。

  具体的调用链如下: ViewRoot根对象的属性mView(其类型一般为ViewGroup类型)调用measure()方法去计算View树的大小,回调View/ViewGroup对象的onMeasure()方法,该方法实现的功能如下:   

         1、设置本View视图的最终大小,该功能的实现通过调用setMeasuredDimension()方法去设置实际的高(对应属性:mMeasuredHeight)和宽(对应属性:mMeasureWidth)。

         2 、如果该View对象是个ViewGroup类型,需要重写该onMeasure()方法,对其子视图进行遍历的measure()过程。对每个子视图的measure()过程,是通过调用父类ViewGroup.java类里的measureChildWithMargins()方法去实现,该方法内部只是简单地调用了View对象的measure()方法。

2、layout布局过程

主要作用:为将整个根据子视图的大小以及布局参数将View树放到合适的位置上。

具体的调用链如下:

          1、layout方法会设置该View视图位于父视图的坐标轴,即mLeft,mTop,mLeft,mBottom(调用setFrame()函数去实现)接下来回调onLayout()方法(如果该View是ViewGroup对象,需要实现该方法,对每个子视图进行布局)。

      2、如果该View是个ViewGroup类型,需要遍历每个子视图chiildView,调用该子视图的layout()方法去设置它的坐标值。

3、draw()绘图过程

  由ViewRoot对象的performTraversals()方法调用draw()方法发起绘制该View树,值得注意的是每次发起绘图时,并不会重新绘制每个View树的视图,而只会重新绘制那些“需要重绘”的视图,View类内部变量包含了一个标志位DRAWN,当该视图需要重绘时,就会为该View添加该标志位。

调用流程 :

          1 、绘制该View的背景

          2 、为显示渐变框做一些准备操作(大多数情况下,不需要改渐变框)          

          3、调用onDraw()方法绘制视图本身(每个View都需要重载该方法,ViewGroup不需要实现该方法)

          4、调用dispatchDraw ()方法绘制子视图(如果该View类型不为ViewGroup,即不包含子视图,不需要重载该方法)

值得说明的是,ViewGroup类已经为我们重写了dispatchDraw ()的功能实现,应用程序一般不需要重写该方法,但可以重载父类函数实现具体的功能。

参考blog分享:http://blog.csdn.net/qinjuning/article/details/7110211

五、Android中的事件处理

1、Handler机制

Android中主线程也叫UI线程,那么从名字上我们也知道主线程主要是用来创建、更新UI的,而其他耗时操作,比如网络访问,或者文件处理,多媒体处理等都需要在子线程中操作,之所以在子线程中操作是为了保证UI的流畅程度,手机显示的刷新频率是60Hz,也就是一秒钟刷新60次,每16.67毫秒刷新一次,为了不丢帧,那么主线程处理代码最好不要超过16毫秒。当子线程处理完数据后,为了防止UI处理逻辑的混乱,Android只允许主线程修改UI,那么这时候就需要Handler来充当子线程和主线程之间的桥梁了。

我们通常将Handler声明在Activity中,然后覆写Handler中的handleMessage方法,当子线程调用handler.sendMessage()方法后handleMessage方法就会在主线程中执行。

这里面除了Handler、Message外还有隐藏的Looper和MessageQueue对象。

在主线程中Android默认已经调用了Looper.preper()方法,调用该方法的目的是在Looper中创建MessageQueue成员变量并把Looper对象绑定到当前线程中。当调用Handler的sendMessage(对象)方法的时候就将Message对象添加到了Looper创建的MessageQueue队列中,同时给Message指定了target对象,其实这个target对象就是Handler对象。主线程默认执行了Looper.looper()方法,该方法从Looper的成员变量MessageQueue中取出Message,然后调用Message的target对象的handleMessage()方法。这样就完成了整个消息机制。

2、事件分发机制

2.1 事件分发中的onTouch和onTouchEvent有什么区别,又该如何使用?

这两个方法都是在View的dispatchTouchEvent中调用的,onTouch优先于onTouchEvent执行。如果在onTouch方法中通过返回true将事件消费掉,onTouchEvent将不会再执行。

另外需要注意的是,onTouch能够得到执行需要两个前提条件,第一mOnTouchListener的值不能为空,第二当前点击的控件必须是enable的。因此如果你有一个控件是非enable的,那么给它注册onTouch事件将永远得不到执行。对于这一类控件,如果我们想要监听它的touch事件,就必须通过在该控件中重写onTouchEvent方法来实现。

2.2 请描述一下Android的事件分发机制

Android的事件分发机制主要是Touch事件分发,有两个主角:ViewGroup和View。Activity的Touch事件事实上是调用它内部的ViewGroup的Touch事件,可以直接当成ViewGroup处理。

View在ViewGroup内,ViewGroup也可以在其他ViewGroup内,这时候把内部的ViewGroup当成View来分析。

先分析ViewGroup的处理流程:首先得有个结构模型概念:ViewGroup和View组成了一棵树形结构,最顶层为Activity的ViewGroup,下面有若干的ViewGroup节点,每个节点之下又有若干的ViewGroup节点或者View节点,依次类推。如图:

 

当一个Touch事件(触摸事件为例)到达根节点,即Acitivty的ViewGroup时,它会依次下发,下发的过程是调用子View(ViewGroup)的dispatchTouchEvent方法实现的。简单来说,就是ViewGroup遍历它包含着的子View,调用每个View的dispatchTouchEvent方法,而当子View为ViewGroup时,又会通过调用ViwGroup的dispatchTouchEvent方法继续调用其内部的View的dispatchTouchEvent方法。上述例子中的消息下发顺序是这样的:①-②-⑤-⑥-⑦-③-④。dispatchTouchEvent方法只负责事件的分发,它拥有boolean类型的返回值,当返回为true时,顺序下发会中断。在上述例子中如果⑤的dispatchTouchEvent返回结果为true,那么⑥-⑦-③-④将都接收不到本次Touch事件。

1.Touch事件分发中只有两个主角:ViewGroup和View。ViewGroup包含onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent三个相关事件。View包含dispatchTouchEvent、onTouchEvent两个相关事件。其中ViewGroup又继承于View。

2.ViewGroup和View组成了一个树状结构,根节点为Activity内部包含的一个ViwGroup。

3.触摸事件由Action_Down、Action_Move、Aciton_UP组成,其中一次完整的触摸事件中,Down和Up都只有一个,Move有若干个,可以为0个。

4.当Acitivty接收到Touch事件时,将遍历子View进行Down事件的分发。ViewGroup的遍历可以看成是递归的。分发的目的是为了找到真正要处理本次完整触摸事件的View,这个View会在onTouchuEvent结果返回true。

5.当某个子View返回true时,会中止Down事件的分发,同时在ViewGroup中记录该子View。接下去的Move和Up事件将由该子View直接进行处理。由于子View是保存在ViewGroup中的,多层ViewGroup的节点结构时,上级ViewGroup保存的会是真实处理事件的View所在的ViewGroup对象:如ViewGroup0-ViewGroup1-TextView的结构中,TextView返回了true,它将被保存在ViewGroup1中,而ViewGroup1也会返回true,被保存在ViewGroup0中。当Move和UP事件来时,会先从ViewGroup0传递至ViewGroup1,再由ViewGroup1传递至TextView。

6.当ViewGroup中所有子View都不捕获Down事件时,将触发ViewGroup自身的onTouch事件。触发的方式是调用super.dispatchTouchEvent函数,即父类View的dispatchTouchEvent方法。在所有子View都不处理的情况下,触发Acitivity的onTouchEvent方法。

7.onInterceptTouchEvent有两个作用:1.拦截Down事件的分发。2.中止Up和Move事件向目标View传递,使得目标View所在的ViewGroup捕获Up和Move事件。

 

六、Android签名

1、简单描述下Android 数字签名

在Android系统中,所有安装到系统的应用程序都必有一个数字证书,此数字证书用于标识应用程序的作者和在应用程序之间建立信任关系。

Android系统要求每一个安装进系统的应用程序都是经过数字证书签名的,数字证书的私钥则保存在程序开发者的手中。Android将数字证书用来标识应用程序的作者和在应用程序之间建立信任关系,不是用来决定最终用户可以安装哪些应用程序。

这个数字证书并不需要权威的数字证书签名机构认证(CA),它只是用来让应用程序包自我认证的。

同一个开发者的多个程序尽可能使用同一个数字证书,这可以带来以下好处。

(1)有利于程序升级,当新版程序和旧版程序的数字证书相同时,Android系统才会认为这两个程序是同一个程序的不同版本。如果新版程序和旧版程序的数字证书不相同,则Android系统认为他们是不同的程序,并产生冲突,会要求新程序更改包名。

(2)有利于程序的模块化设计和开发。Android系统允许拥有同一个数字签名的程序运行在一个进程中,Android程序会将他们视为同一个程序。所以开发者可以将自己的程序分模块开发,而用户只需要在需要的时候下载适当的模块。

在签名时,需要考虑数字证书的有效期:

(1)数字证书的有效期要包含程序的预计生命周期,一旦数字证书失效,持有改数字证书的程序将不能正常升级。

(2)如果多个程序使用同一个数字证书,则该数字证书的有效期要包含所有程序的预计生命周期。

(3)Android Market强制要求所有应用程序数字证书的有效期要持续到2033年10月22日以后。

Android数字证书包含以下几个要点:

 (1)所有的应用程序都必须有数字证书,Android系统不会安装一个没有数字证书的应用程序

 (2)Android程序包使用的数字证书可以是自签名的,不需要一个权威的数字证书机构签名认证

 (3)如果要正式发布一个Android ,必须使用一个合适的私钥生成的数字证书来给程序签名,而不能使用adt插件或者ant工具生成的调试证书来发布。

 (4)数字证书都是有有效期的,Android只是在应用程序安装的时候才会检查证书的有效期。如果程序已经安装在系统中,即使证书过期也不会影响程序的正常功能。

2、使用Eclipse如何生成数字签名

可以通过Eclipse导出工程时为当前工程设置签名证书。File -> Export ->Export Android Application ->Create New keystore ....

七、Android中的动画

1、Android中的动画有哪几类,它们的特点和区别是什么

Android中动画分为两种,一种是Tween动画、还有一种是Frame动画。

Tween动画,这种实现方式可以使视图组件移动、放大、缩小以及产生透明度的变化;

Frame动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影。

2、如何修改Activity进入和退出动画

可以通过两种方式,一是通过定义Activity的主题,二是通过覆写Activity的overridePendingTransition方法。

 通过设置主题样式

在styles.xml中编辑如下代码:

@anim/slide_in_left @anim/slide_out_left @anim/slide_in_right @anim/slide_out_right " v:shapes="_x0000_s1034">

添加themes.xml文件:

@style/AnimationActivity true " v:shapes="_x0000_s1033">

在AndroidManifest.xml中给指定的Activity指定theme。

 覆写overridePendingTransition方法

 overridePendingTransition(R.anim.fade, R.anim.hold);

八、其他知识(非归类内容)

1、AsyncTask如何使用

AsyncTask用于处理异步任务,该类是一个抽象的泛型类。类的签名如下:public abstract class AsyncTask<Params, Progress, Result>。

三种泛型类型分别代表“启动任务执行的输入参数”、“后台任务执行的进度”、“后台计算结果的类型”。在特定场合下,并不是所有类型都被使用,如果没有被使用,可以用java.lang.Void类型代替。

一个异步任务的执行一般包括以下几个步骤:

1.execute(Params... params),执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。

2.onPreExecute(),在execute(Params... params)被调用后立即执行,一般用来在执行后台任务前对UI做一些标记。

3.doInBackground(Params... params),在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。在执行过程中可以调用publishProgress(Progress... values)来更新进度信息。

4.onProgressUpdate(Progress... values),在调用publishProgress(Progress... values)时,此方法被执行,直接将进度信息更新到UI组件上。

5.onPostExecute(Result result),当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。

在使用的时候,有几点需要格外注意:

1.异步任务的实例必须在UI线程中创建。

2.execute(Params... params)方法必须在UI线程中调用。

3.不要手动调用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values),onPostExecute(Result result)这几个方法。

4.不能在doInBackground(Params... params)中更改UI组件的信息。

5.一个任务实例只能执行一次,如果执行第二次将会抛出异常。

我写一个简单的例子来演示AsyncTask的用法。

  • MainActivity.java

asyncTask = new MyAsyncTask(); asyncTask.execute(100); } class MyAsyncTask extends AsyncTask<integer, integer,="" string="">{ /** * 该方法在子线程中运行,因此不能有任何修改UI操作 */ @Override protected String doInBackground(Integer... params) { for(int i=0;i<params[0];i++){ try="" {="" 模拟耗时操作="" thread.sleep(100);="" }="" catch="" (interruptedexception="" e)="" e.printstacktrace();="" 发送进度="" publishprogress(i);="" return="" "任务已经完成";="" **="" *="" 任务执行前在ui线程中调用="" "="">

 

* @param result 正是doInBackground的返回值 */ @Override protected void onPostExecute(String result) { Toast.makeText(MainActivity.this, result, 0).show(); super.onPostExecute(result); } /** * 在UI线程中执行 * 当doInBackground执行publishProgress时调用该方法 */ @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); tv.setText("当前进度:"+values[0]); } } } " v:shapes="_x0000_s1031">

activity_main.xml

posted @ 2016-08-08 10:25  52赫兹  阅读(895)  评论(0编辑  收藏  举报