Android基础技术核心归纳(四)

来源:互联网 发布:宝宝鼻屎 知乎 编辑:程序博客网 时间:2024/05/16 09:51

Android基础技术核心归纳(四)

转载请声明出处:http://blog.csdn.net/andrexpert/article/details/77896868

Android                                          Java                                            数据结构
Android基础技术核心归纳(一)     Java基础技术核心归纳(一)     数据结构基础知识核心归纳(一) 
Android基础技术核心归纳(二)     Java基础技术核心归纳(二)     数据结构基础知识核心归纳(二)  
Android基础技术核心归纳(三)     Java基础技术核心归纳(三)    数据结构基础知识核心归纳(三)  
Android基础技术核心归纳(四)     Java基础技术核心归纳(四)


    不知不觉又是一年的9月,今天跟一个师弟聊天,谈到了他现在面试的一些情况,突然想起自己当年也是这么走过来的,顿时感慨良多。Android/Java经验汇总系列文章,是当初自己毕业时笔试、面试和项目开发中相关的总结,虽然不是很高深的东西,也没有归纳得很全面,但是对Android、算法、Java把握个大概还是没问题,今天特意将这些文章放出来,希望能够对看到这个系列文章的毕业生朋友一点帮助吧。当然,由于受当时知识面的限制,归纳得可能不是很准确,若有疑问就留言吧,我就不细看了。


1.典型例题
1.Android中Looper的实现原理,为什么调用Looper.prepare()就在当前线程关联了一个Looper对象,它是如何实现的?

(1)线程间通信机制
     Looper、Handler、MessageQueue三者共同实现Android系统中的消息处理机制。如在A、B两个子线程之间需要传递消息,首先给每个子线程绑定一套handler、looper、messageQueue机制,然后这三个对象都与其所属线程对应。然后A线程通过调用B线程的Handler对象,发送消息。这个消息会被Handler发送到B线程的messageQueue中,而属于B线程的Looper对象一直在for循环里无限遍历MessageQueue,一旦发现该消息队列里收到了新的消息,就会去对消息进行处理,处理过程中会回调对应的Handler的handleMessage方法,从而实现了不同线程间通信问题。
(2)Looper实现原理
    Looper类里包含一个消息队列对象和一个线程对象。当创建Looper对象(Looper.prepare())时,会自动创建一个消息队列,同时将内部线程对象指向创建Looper的线程。当开启Looper后(looper.loop())会自动进入无限for循环中,不断去遍历消息队列,如果没有消息则阻塞,有消息则回调handler的handleMessage()方法进行处理。
(3)Looper.prepare()
      首先,要使用Looper机制一般会在当前线程中创建Handler对象,里面会自动创建一个looper对象和消息队列,这里面的消息队列属于当前线程空间。但此时的looper还不会遍历消息队列,也没有绑定到当前线程。其中,looper对象内部包含一个空消息队列对象和空线程。通过Looper.prepare()方法,先让该消息队列指向当前线程的消息队列,让空线程也指向当前线程,从而实现了绑定。   
(4)假如在子线程中new Handler,且并调用语句Looper.prepare()创建Looper对象,问如何将子线程的消息发送到UI线程。
解决:由于Looper对象可以绑定任意Handler对象,可以使用UI线程的Looper对象绑定子线程的Handler对象。子线程就可以使用自己的Handler对象,将消息发送到UI线程的Looper对应的MessageQueue中。
2.关于Intent的说法,错误的是?
A)可以用来激活一些组件
B)表示程序想做某事的意图
C)只能用于一个组件内部
D)是一个简单的消息对象
解析:A:对,startActivity,startService,sendBroadcastReceiver等等
B:对,本意就是一个意图
C:错,同一个app中不同组件之间传递信息
3.下面哪种进程最重要,最后被销毁?
解析:重要性依次是:前台进程,可见进程,服务进程,后台进程和空进程;所以销毁的顺序是逆方向。
4.当 Activity 被消毁时,如何保存它原来的状态()
解析:实现onSaveInstanceState() 方法
当你的程序中某一个Activity A在运行时,主动或被动地运行另一个新的Activity B,这个时候A会执行onSaveInstanceState()。B完成以后又会来找A,这个时候就有两种情况:一是A被回收,二是A没有被回收,被回收的A就要重新调用onCreate()方法,不同于直接启动的是这回onCreate()里是带上了参数savedInstanceState;而没被收回的就直接执行onResume(),跳过onCreate()了。
5.关于AlertDialog描述错误的是( D).
A)show()方法只显示对话框
B)AlertDialog.Builder的create() 和show()方法都返回AlertDialog对象
C)AlertDialog不能直接用new关键字构建对象,而必须使用其内部类Builder
D)create()方法创建并显示对话框
解析:A:show()方法最终还是创建并显示。附源码:

 public AlertDialog show() {            AlertDialog dialog = create();            dialog.show();     return dialog;        }
B:查看源码,正确;
C:因为其构造器都是保护的,所以不允许非子类调用;所以不能直接使用new关键字来创建AlertDialog类的对象实例。要想创建AlertDialog对话框,需要使用Builder类,该类是AlertDialog类中定义的一个内嵌类。因此必须创建AlertDialog.Builder类的对象实例,然后再调用show()来显示对话框。D:create()方法只创建,不显示。
6.android中使用SQLiteOpenHelper这个辅助类时,可以生成一个数据库,并可以对数据库版本进行管理的方法可以是?
解析:getWriteableDatabase() 、getReadableDatabase()
如果只是数据库的查询,则只需调用getReadableDatabase(),获取数据库的信息。
如果是修改的话,则使用 getWriteableDatabase()方法,对数据库进行修改。
7.Android中MVC模式M、V、 C层分别指的是?
解析:M是逻辑模型 ,用于处理逻辑业务,比如耗时任务
V是视图模型,对应于android里面的View
C是控制器,android中的activity实现了事件控制,尽量不要在Acitivity中写代码
8. Intent传递数据时,下列的数据类型可以被传递的是()
A)Serializable
B)File
C)Parcelable
D)Thread
解析:

bundle.putSerializable(key,object);bundle.putParcelable(key,object);使用两种方式接收的语法分别为:object=(Object) getIntent().getSerializableExtra(key);object=(Object) getIntent().getParcelableExtra(key);

Serializable:将 Java 对象序列化为二进制文件的 Java 序列化技术是 Java系列技术中一个较为重要的技术点,在大部分情况下,开发人员只需要了解被序列化的类需要实现 Serializable 接口,使用ObjectInputStream 和 ObjectOutputStream 进行对象的读写。
Parcelable:android提供了一种新的类型:Parcel。本类被用作封装数据的容器,封装后的数据可以通过Intent或IPC传递。 除了基本类型以外,只有实现了Parcelable接口的类才能被放入Parcel中。
9.GLSurfaceView是一个视图,继承至SurfaceView,它内嵌的surface专门负责OpenGL渲染。
        GLSurfaceView提供了下列特性:
       1> 管理一个surface,这个surface就是一块特殊的内存,能直接排版到android的视图view上。
       2> 管理一个EGL display,它能让opengl把内容渲染到上述的surface上。
       3> 用户自定义渲染器(render)。
       4> 让渲染器在独立的线程里运作,和UI线程分离。
       5> 支持按需渲染(on-demand)和连续渲染(continuous)。
       6> 一些可选工具,如调试
10.对一些资源以及状态的操作保存,最好是保存在生命周期的哪个函数中进行?
A)onPause()
B)onCreate()
C)onResume()
D)onStart()
解析:onCreat():初始化操作,如:加载布局,绑定事件...
onStart():活动由不可见变为可见是调用
---------------------------------》都是进行初始化的
onResume():准备好和用户进行交互时调用
---------------------------------》交互也需要数据保存,数据交互
onPause():系统准备启动或恢复另一个活动时调用,所以会保存一些关键数据 
11.下面哪一项属于android的动画类型?
A)Tween
B)Alpha
C)Frame
D)Animation
解析:Tween(补间动画)包含:alpha和scale
Frame(逐帧动画)包含:translate和rotate,不会改变位图属性
12.在 Android 中, 在屏幕密度为160时, 1pt 大概等于__sp
A)1.22
B)2.22
C)2.12
D)1.12
解析:与分辨率无关的度量单位可以解决这一问题。Android支持下列所有单位。
       px(像素):屏幕上的点。
       in(英寸):长度单位。
       mm(毫米):长度单位。
       pt(磅):1/72英寸。
       dp(与密度无关的像素):一种基于屏幕密度的抽象单位。在每英寸160点的显示器上,1dp = 1px。
       dip:与dp相同,多用于android/ophone示例中。
       sp(与刻度无关的像素):与dp类似,但是可以根据用户的字体大小首选项进行缩放。
 分辨率:整个屏是多少点,比如800x480,它是对于软件来说的显示单位,以px为单位的点。 density(密度)值表示每英寸有多少个显示点,与分辨率是两个概念。apk的资源包中,  
       当屏幕density=240时使用hdpi标签的资源  
       当屏幕density=160时,使用mdpi标签的资源  
       当屏幕density=120时,使用ldpi标签的资源。  
       一般android设置长度和宽度多用dip,设置字体大小多用sp. 在屏幕密度为160,1dp=1px=1dip, 1pt = 160/72 sp 1pt = 1/72 英寸.当屏幕密度为240时,1dp=1dip=1.5px. 
13. 关于ServiceConnection接口的onServiceConnected()方法的触发条件描述正确的是?
A)bindService()方法执行成功后
B)bindService()方法执行成功同时onBind()方法返回非空IBinder对象
C)Service的onCreate()方法和onBind()方法执行成功后
D)Service的onCreate()和onStartCommand()方法启动成功后
解析:

servicedispatcher里面有个函数doconnection{if(service!=null){//其中service为Ibind类型mconnection.onserviceConnected(name,service)}
14. 下列哪些情况下系统会弹出Froce Close对话框
A)应用运行时,Main线程进行了耗时操作 ---ANR
B)应用运行时抛出了OutOfMemoryError ---FC
C)应用运行时抛出了RuntimeException ---FC
D)应用运行时,用户操作过于频繁---ANR    
15. Android系统对下列哪些对象提供了资源池
A)Message
B)Thread
C)AsyncTask
D)Looper
解析:A.Message提供了消息池,有静态方法Obtain从消息池中取对象;
B.Thread默认不提供资源池,除非使用线程池ThreadPool管理;
C.AsynTask是线程池改造的,默认提供最多5个线程进行并发操作;
D.Looper,每个Looper创建时创建一个消息队列和线程对象,也不是资源池
16.下列关于IntentService与Service的关系描述错误的是
A)IntentService是Service的子类
B)IntentService在运行时会启动新的线程来执行任务
C)启动方式不同
D)没有区别
解析:IntentService是继承Service的,那么它包含了Service的全部特性,当然也包含service的生命周期,那么与service不同的是,IntentService在执行onCreate操作的时候,内部开了一个线程,去你执行你的耗时操作。 Service在OnStart中处理intent,并且是在主线程中运行。
17.有关Activity生命周期描述正确的是
A)设置Activity的android:screenOrientation="portrait"属性时,切换屏幕横纵方向时不会重新调用各个生命周期,只会执行onConfigurationChanged方法
B)未设置Activity的android:configChanges属性,切换屏幕横纵方向时会重新调用onCreate()方法
C)当再次启动某个launchMode设置为singletask的Activity,它的onNewIntent()方法会被触发
D)用户正在操作某个Activity,这时如果其他应用程序需要内存,系统会将用户当前操作的Activity强制关闭
解析:A 设置Activity的android:screenOrientation="portrait"属性时,无法切换横竖屏,因此不但不会重新调用各个生命周期方法,而且onConfigurationChanged()方法也不会执行。
B 未设置Activity的android:configChanges属性,API上这样说"the activity will be restarted if any of these configuration changes happen in the system.";如何配置有改变,就会重启activity
C launchMode为singleTask的时候,通过Intent启到一个Activity, 如果系统已经存在一个实例,系统就会将请求发送到这个实例上, 但这个时候,       系统就不会再调用通常情况下我们处理请求数据的onCreate方法,而是调用onNewIntent方法
 
D 用户正在操作某个Activity,这时如果其他应用程序需要内存。 此时的Activity是Foreground process,应该按照Empty process,Background process,Service process,Visible process顺序kill,最后才是前台进程
18.Android dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念
解析:是。DVM指dalivk的虚拟机。每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的Dalvik虚拟机实例。而每一个DVM都是在Linux 中的一个进程,所以说可以认为是同一个概念。android DVM:
Dalvik是Google公司自己设计用于Android平台的Java虚拟机,每一个Dalvik应用作为一个独立的Linux 进程执行。独立的进程可以防止在虚拟机崩溃的时候所有程序都被关闭
19.Fragment与Activity的生命周期
      
onCreate过程  
01-22 15:30:28.091: E/HJJ(10315): Activity &&&& onCreate...  
01-22 15:30:28.091: E/HJJ(10315): ArrayListFragment **** onAttach...  
01-22 15:30:28.091: E/HJJ(10315): ArrayListFragment **** onCreate...  
01-22 15:30:28.115: E/HJJ(10315): ArrayListFragment **** onCreateView...  
01-22 15:30:28.123: E/HJJ(10315): ArrayListFragment **** onActivityCreated...  
onStart过程  
01-22 15:30:28.123: E/HJJ(10315): Activity &&&& onStart...  
01-22 15:30:28.123: E/HJJ(10315): ArrayListFragment **** onStart...  
onResume过程  
01-22 15:30:28.123: E/HJJ(10315): Activity &&&& onResume...  
01-22 15:30:28.123: E/HJJ(10315): ArrayListFragment **** onResume...  
onPause过程  
01-22 15:31:26.748: E/HJJ(10315): ArrayListFragment **** onPause...  
01-22 15:31:26.748: E/HJJ(10315): Activity &&&& onPause...    
onStop过程  
01-22 15:31:27.638: E/HJJ(10315): ArrayListFragment **** onStop...  
01-22 15:31:27.638: E/HJJ(10315): Activity &&&& onStop...    
onStart过程  
01-22 15:31:57.537: E/HJJ(10315): Activity &&&& onStart...  
01-22 15:31:57.537: E/HJJ(10315): ArrayListFragment **** onStart...   
onResume过程  
01-22 15:31:57.537: E/HJJ(10315): Activity &&&& onResume...  
01-22 15:31:57.537: E/HJJ(10315): ArrayListFragment **** onResume...    
onPause过程  
01-22 15:32:47.412: E/HJJ(10315): ArrayListFragment **** onPause...  
01-22 15:32:47.412: E/HJJ(10315): Activity &&&& onPause...   
onStop过程  
01-22 15:32:47.865: E/HJJ(10315): ArrayListFragment **** onStop...  
01-22 15:32:47.865: E/HJJ(10315): Activity &&&& onStop...  
onDestroy过程  
01-22 15:32:47.865: E/HJJ(10315): ArrayListFragment **** onDestroyView...  
01-22 15:32:47.865: E/HJJ(10315): ArrayListFragment **** onDestroy...  
01-22 15:32:47.865: E/HJJ(10315): ArrayListFragment **** onDetach...  
01-22 15:32:47.865: E/HJJ(10315): Activity &&&& onDestroy...  
20.使用代码获得在string.xml定义的一个字符串方法
    getResources 是获取项目中的资源文件可以用来获取你说的string,xml还可以获取图片,音乐,视频等资源文件。getText就是获取文本,getResources().getText(R.string.***);这样的方法可以获取到时因为资源文件中而你在activity中getText默认就是去读取String.xml中的内容了。
21.Android应用程序入口分析
     android应用程序,由一到多个Activity组成.每个Activity没有很紧密的联系。android应用程序中,并没有像c++和java这样有main函数来作为应用程序的入口.android应用程序提供的是入口Activity,而非入口函数。在eclipse中创建一个android应用程序的时候,默认会创建一个Activity.这个Activity实际上就是入口Activity了。从哪里定义它是Activity呢?AndroidManifest.xml文件中定义了整个android应用所包含的Activity.默认生成的Activity的定义为:  
        <activity android:name=".activity01" android:label="@string/app_name">              <intent-filter>                  <action android:name="android.intent.action.MAIN" />                  <category android:name="android.intent.category.LAUNCHER" />              </intent-filter>          </activity>  
     action节点中的android.intent.action.MAIN表明它所在的Activity是整个应用程序的入口点.而category中的android.intent.category.LAUNCHER意思是把这个Activityg归属到加载器类,即把这个Activity标注为自动会加载和启动的Activity,这样程序启动时候就先加载这个Activity了。
2.Fragment开发
     Fragment是Android3.0引入的新API,可以把Fragment想成Activity中的模块,这个模块有自己的布局,有自己的生命周期,单独处理自己的输入,在Activity运行的时候可以加载或者移除Fragment模块。 可以把Fragment设计成可以在多个Activity中复用的模块,当开发的应用程序同时适用于平板电脑和手机时,可以利用Fragment实现灵活的布局,改善用户体验。
1.Fragment的特征
(1)Fragment总是作为Activity界面的组成部分。Fragment可调用getActvity()方法获取它所在的
    Activity,Activity可调用FragmentManager的findFragmentById()或findFragmentByTag()方法来获取
    Fragment。其中,fragment的id或tag在其布局文件<fragment../>元素中定义。 
(2)在Activity运行过程中,可调用FragmentManager的add()、remove()、replace()、方法动态地添加、
    删除或替换Fragment。 
(3)一个Activity可以同时组合多个Fragment;反过来,一个Fragment也可能被多个Activity复用;
(4)Fragment可以响应自己的输入事件、并拥有自己的生命周期,但它们的生命周期直接被其他所
    属的Activity的生命周期控制。
2.Fragment的生命周期

3.Fragment的开发步骤
(1)创建一个Fragment
    实现一个Fragment类,并重写onCreate用于初始化、onCreateView用于返回Fragment的View、onPause方法用于提交保存一些变化数据;
(2)添加Fragment到Activity的ViewGroup
    Fragment不能单独存在,必须依附在Activity上。添加Fragment到Activity有两种方式
    a.在layout中使用标签<fragment>声明
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     ..........>          <!-- android:name属性为该需要加载的Fragment完整类名(包.类名)           android:id属性为该Fragment的唯一标识符ID,可以通过ID实现对该Fragment进行操作 -->        <fragment            android:name="com.example.android_fragment.BookListFragment"            android:id="@+id/bookList"            ......./>      </LinearLayout>
    b.在代码中把Fragment加入到一个Activity的指定ViewGroup中
    FragmentManager fragmentManager=getFragmentManager();  //获得FragmentManager对象    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();//打开事务    BookListFragment booklistfragment = new BookListFragment();      //创建一个图书列表Fragment    fragmentTransaction.add(R.id.activity_container, booklistfragment );  //添加fragment到Activity的某个容器    fragmentTransaction.commit();                                                           //提交事务改变生效-使View容器   onCreate.onAttach.onCreate. onCreateView..onActivityCreated onDestroyView.onDestroy.onDetach.
说明:
    >FragmentManager主要完成获取指定Fragment,将Fragment从后台弹出栈、为后台Fragment注册
        一个监听器。
    >FragmentTransaction则完成Fragment的添加、删除、替换等事务,每个FragmentTransaction可以包    
        含多个对Fragment修改。
5.多设备兼容处理方法
    由于Android设备的屏幕尺寸、分辨率差别非常大,如果希望我们的应用能够在不同屏幕尺寸或分辨率的Android设备上运行,即更换Android设备后界面和字体不会因此变得混乱,则需要考虑屏幕的自适应性问题。
1.使用layout_weight属性方法
    该属性的作用是决定控件在其父布局中的显示权重,一般用于线性布局中。(1)传统使用方法:将组件的layout_width和layout_height设置为fill_parent,通过layout_weight属性控制控件的显示比例,当layout_weight越小,控件显示比例就越大。    (2)(2)0px设值法:即使layout_width="0dp"或layout_height="0dp",再结合layout_weight属性正比例控制控件的显示。该方法有效解决了当前Android开发中碎片化问题之一。
2.自定义尺寸法
       所谓自定义尺寸法,即为每一种屏幕界面定义一套界面尺寸大小。

3.多布局
    所谓多布局,即为不同尺寸屏幕设计单独的布局文件。为了提供自适应不同屏幕的资源,我们可以为不同屏幕尺寸、不同屏幕分辨率提供相应的布局资源、Drawable资源。需要注意的是,使用多布局方法,须在清单文件中添加如下代码,否则,会出现异常。

    在程序中显示声明你的应用程序支持屏幕尺寸的清单(AndroidMnifest.xml)
<supports-screens   
     android:resizeable=[“true”|”false”]  
     android:smallScreens=[“true”|”false”]  
     android:normalScreens=[“true”|”false”]  
     android:largeScreens=[“true”|”false”]  
     android:xlargeScreens=[“true”|”false”]  
     android:anyDensity=[“true”|”false”]/>
 4. 滚动视图(ScrollView)使用方法
    滚动视图ScrollView由FrameLayout派生出来,主要用于为普通组件添加滚动条的组件。ScollView里最多只能包含一个组件且为该组件添加的是垂直滚动条。如果应用需要添加水平滚动条,则需要通过HorizontalScrollView组件实现。   
5.FilterInputStream和FilterOutputStream详解
按照前篇文章所说,java.io包中的字节流中的类关系有用到GoF《设计模式》中的装饰者模式,而这正体现在FilterInputStream和FilterOutputStream和它的子类上,我们这篇就来看一看。
0. FilterInputStream和FilterOutputStream
首先,这两个都分别是InputStream和OutputStream的子类。而且,FilterInputStream和FilterOutputStream是具体的子类,实现了InputStream和OutputStream这两个抽象类中为给出实现的方法。
但是,FilterInputStream和FilterOutputStream仅仅是“装饰者模式”封装的开始,它们在各个方法中的实现都是最基本的实现,都是基于构造方法中传入参数封装的InputStream和OutputStream的原始对象。
比如,在FilterInputStream类中,封装了这样一个属性:

protectedvolatileInputStream in;
而对应的构造方法是:
protectedFilterInputStream(InputStream in) {
    this.in = in;
}
read()方法的实现则为:
publicintread() throwsIOException {
    returnin.read();
}
其它方法的实现,以及FilterOutputStream也都是同理类似的。
我们注意到FilterInputStream和FilterOutputStream并没给出其它额外的功能实现,只是做了一层简单地封装。那么实现额外功能的实际是FilterInputStream和FilterOutputStream的各个子类。
1. BufferedInputStream/BufferedOutputStream
先说说这个最简单的一对,BufferedInputStream和BufferedOutputStream。顾名思义,Buffered就是缓冲了的。在BufferedInputStream和BufferedOutputStream中,都额外实现了byte数组做buffer。
我们知道在父类FilterInputStream和FilterOutputStream类中,已经在构造方法时封装了原始的InputStream或者OutputStream对象。
在我们使用BufferedInputStream和BufferedOutputStream来进行read()和write()调用的时候,并不一定直接对封装的InputStream或者OutputStream对象进行操作,而是要经过缓冲处理。
在BufferedInputStream的read()中,实际上是一次读取了多个字节到缓冲数组,而非一次只读取一个。后续的read()操作可以直接从数组中获取字节,而不必再次调用封装的InputStream对象的read()操作。这样做其实在一定情况下可以减少底层的read调用次数,降低成本开销,提高了效率。
在BufferedOutputStream中也是一样,它的write()会先把数据写到缓冲数组中,直到数据达到了某个特定的限额,再调用write()的时候回真正调用到封装的OutputStream对象的write()方法。
2. DataInputStream/DataOutputStream
这也是比较重要的一对Filter实现。那么说起功能,实际上就不得不提到他们除了extends FilterInputStream/FilterOutputStream外,还额外实现了DataInput和DataOutput接口。

我们可以先来看下DataInput和DataOutput这两个interface。


DataInput
DataInput接口的outline

再看DataOutput:


DataOutput
DataOutput接口的outline
而DataInputStream/DataOutputStream这一对实际上所做的也就是这两个接口所定义的方法。再DataInputStream/DataOutputStream中,这些方法做了拼接和拆分字节的工作。通过这些方法,我们可以方便的读取、写出各种我们实际所面对的类型的数据,而不必具体去在字节层面上做细节操作。
3. PrintStream
这个类不成对,只有这样一个OutputStream。看起名字中的Print,我们会想到什么?println()方法和print()方法。实际上,包括java.lang包中的System.out和System.error,使用的都是PrintStream类对象。

从使用层面来看,这个类主要是提供了丰富的print()和println()的各类参数重载方法。对各个类型的输出,包括换行处理等都集成在内。还有format()方法,帮我们做到了类似C语言中printf()函数的效果。

而从实现上来看,这些print()和println()最终都调用了各类write()方法。在这些write()方法中,实际上使用到了类中封装的这两个属性。
privateBufferedWriter textOut;
privateOutputStreamWriter charOut;
他们都是Writer的子类,是字符流处理类,有编码解码机制,我们会在后续文章中详细说明。
6.Android子线程更新UI线程的几种方法
(1)Handler消息处理机制
(2)AsyncTask异步任务类:阻塞主线程的任务

class AsyncTaskThread extends AsyncTask<String, Integer, Bitmap> {        @Override        protected Bitmap doInBackground(String... params) {            publishProgress(0);            HttpClient client = new DefaultHttpClient();            publishProgress(30);            HttpGet get = new HttpGet(params[0]);            final Bitmap bitmap;            try {                HttpResponse response = client.execute(get);                bitmap = BitmapFactory.decodeStream(response.getEntity()                        .getContent());            } catch (Exception e) {                returnnull;            }            publishProgress(100);            return bitmap;        }
    params是一个可变参数列表,publishProgress()中的参数就是Progress,同样是一个可变参数列表,它用于向UI线程提交    后台的进度,这里我们一开始设置为0,然后在30%的时候开始获取图片,一旦获取成功,就设置为100%。中间的代码用于下载     和获取网上的图片资源。
protectedvoid onProgressUpdate(Integer... progress) {            mProgressBar.setProgress(progress[0]);        }        protectedvoid onPostExecute(Bitmap result) {            if (result != null) {                Toast.makeText(MainActivity.this, "成功获取图片", Toast.LENGTH_LONG)                        .show();                mImageView.setImageBitmap(result);            } else {                Toast.makeText(MainActivity.this, "获取图片失败", Toast.LENGTH_LONG)                        .show();            }        }        protectedvoid onPreExecute() {            mImageView.setImageBitmap(null);            mProgressBar.setProgress(0);        }        protectedvoid onCancelled() {            mProgressBar.setProgress(0);        }    }    @Override    publicboolean onCreateOptionsMenu(Menu menu) {        // Inflate the menu; this adds items to the action bar if it is present.        getMenuInflater().inflate(R.menu.main, menu);        returntrue;    }
UI线程执行以下代码启动异步任务线程:
    AsyncTaskThread thread = new AsyncTaskThread();
    thread.execute("http://g.search2.alicdn.com/img/bao/uploaded/i4/"
                        + "i4/12701024275153897/T1dahpFapbXXXXXXXX_!!0-item_pic.jpg_210x210.jpg");
AsyncTask本质上是一个静态的线程池,由它派生出来的子类可以实现不同的异步任务,但这些任务都是提交到该静态线程池中执行,执行的时候通过调用doInBackground()方法执行异步任务,期间会通过Handler将相关的信息发送到UI线程中,但神奇的是,并不是调用UI线程中的回调方法,而是AsyncTask本身就有一个Handler的子类InternalHandler会响应这些消息并调用AsyncTask中相应的回调方法。从上面的代码中我们也可以看到,UI的ProgressBar的更新是在AsyncTask的onProgressUpdate(),而ImageView是在onPostExecute()方法里。这是因为InternalHandler其实是在UI线程里面创建的,所以它能够调用相应的回调方法来更新UI。
      AsyncTask就是专门用来处理后台任务的,而且它针对后台任务的五种状态提供了五个相应的回调接口,使得我们处理后台任务变得非常方便。
      如果只是普通的UI更新操作,像是不断更新TextView这种动态的操作,可以使用Handler,但如果是涉及到后台操作,像是下载任务,然后根据后台任务的进展来更新UI,就得使用AsyncTask,但如果前者我们就使用AsyncTask,那真的是太大材小用了!!
参考:http://www.cnblogs.com/wenjiang/p/3180324.html
(3)View.post()方法
imageView.post(new Runnable(){                        @Override                      public void run() {                          imageView.setImageBitmap(bitmap);                      }                                        }); 
(4)Activity.runOnUiThread()方法:需要新启动一个线程
class ProgressThread extends Thread {        @Override        publicvoid run() {            super.run();            while (mProgress <= 100) {                runOnUiThread(new Runnable() {                    @Override                    publicvoid run() {                        mProgressBar.setProgress(mProgress);                        mProgress++;                    }                });                try {                    Thread.sleep(100);                } catch (InterruptedException e) {                }            }        }    }
(5)Service+broadcastReceiver
Service为一个后台运行的子线程,发送一个广播给BroadcastReciver,广播接收器获得Intent绑定的数据,然后更新UI。
总结:
1.如果只是单纯的想要更新UI而不涉及到多线程的话,使用View.post()就可以了;
2.需要另开线程处理数据以免阻塞UI线程,像是IO操作或者是循环,可以使用Activity.runOnUiThread(); 
3.如果需要传递状态值等信息,像是蓝牙编程中的socket连接,就需要利用状态值来提示连接状态以及做相应的处理,就需要使用Handler + Thread的方式;
4.如果是后台任务,像是下载任务等,就需要使用AsyncTask。
ThreadLocal变量:http://www.iteye.com/topic/103804
7.Android开发之XML文件的解析的三种方法
(1)DOM方式:OM方式解析xml是先把xml文档都读到内存中,然后再用DOM API来访问树形结构,并获取数据。如果XML文件很大的时候,处理效率就会变得比较低。
(2)SAX方式:相比于DOM而言SAX是一种速度更快,更有效,占用内存更少的解析XML文件的方法。它是逐行扫描,可以做到边扫描边解析,因此SAX可以在解析文档的任意时刻停止解析。非常适用于Android等移动设备。SAX是基于事件驱动的。所谓事件驱动就是说,它不用解析完整个文档,在按内容顺序解析文档过程中,SAX会判断当前读到的字符是否符合XML文件语法中的某部分。如果符合某部分,则会触发事件。所谓触发事件,就是调用一些回调方法。当然android的事件机制是基于回调方法的,在用SAX解析xml文档时候,在读取到文档开始和结束标签时候就会回调一个事件,在读取到其他节点与内容时候也会回调一个事件。在SAX接口中,事件源是org.xml.sax包中的XMLReader,它通过parser()方法来解析XML文档,并产生事件。事件处理器是org.xml.sax包中ContentHander、DTDHander、ErrorHandler,以及EntityResolver这4个接口。
(3)PULL方式:Android内置的Pull解析器解析XML文件。Pull解析器的运行方式与 SAX 解析器相似。它也是事件触发的。Pull解析方式让应用程序完全控制文档该怎么样被解析。Android推荐使用PULL方式。
总结:DOM  一次性全部加载到内存 生成一个树状结构,缺点就是消耗的内存比较大 ;SAX  基于事件解析   速度快,效率高 缺点是不能倒退 ;PULL 解析 使用方便 效率高 。
参考文献:http://blog.csdn.net/redoffice/article/details/7782770
8.android 定位的4种方式
    android 定位一般有四种方法,这四种方式分别是:GPS定位,WIFI定准,基站定位,AGPS定位
    (1)Android GPS:需要GPS硬件支持,直接和卫星交互来获取当前经纬度,这种方式需要手机支持GPS模块(现在大部分的智能机应该都有了)。通过GPS方式准确度是最高的,但是它的缺点也非常明显:1,比较耗电;2,绝大部分用户默认不开启GPS模块;3,从GPS模块启动到获取第一次定位数据,可能需要比较长的时间;4,室内几乎无法使用。这其中,缺点2,3都是比较致命的。需要指出的是,GPS走的是卫星通信的通道,在没有网络连接的情况下也能用。
    (2)Android Wifi定位:根据一个固定的Wifi MAC地址,通过收集到的该Wifi热点的位置,然后访问网络上的定位服务以获得经纬度坐标。因为它和基站定位其实都需要使用网络,所以在Android也统称为Network方式。
    (3)AGPS(AssistedGPS:辅助全球卫星定位系统)是结合GSM或GPRS与传统卫星定位,利用基地台代送辅助卫星信息,以缩减GPS芯片获取卫星信号的延迟时间,受遮盖的室内也能借基地台讯号弥补,减轻GPS芯片对卫星的依赖度。和纯GPS、基地台三角定位比较,AGPS能提供范围更广、更省电、速度更快的定位服务,理想误差范围在10公尺以内.
参考文献:http://www.jb51.net/article/52676.htm
9.SQLite
 一、创建/删除表
  String sql="Create table "+TABLE_NAME+"("+FIELD_ID+" integer primary key autoincrement," +FIELD_TITLE+" text );";
    db.execSQL(sql);
  String sql=" DROP TABLE IF EXISTS "+TABLE_NAME;
    db.execSQL(sql);
  二、查询
  从表中查询数据(in)  SELECT * FROM meta where media_id in (1,2,9);
  三、插入
  SQLiteDatabase db=this.getWritableDatabase();
    ContentValues cv=new ContentValues(); 
    cv.put(FIELD_TITLE, Title);
    long row=db.insert(TABLE_NAME, null, cv);
  四、更新
  SQLiteDatabase db=this.getWritableDatabase();
    String where=FIELD_ID+"= ";
    String[] whereValue={Integer.toString(id)};
    ContentValues cv=new ContentValues(); 
    cv.put(FIELD_TITLE, Title);
    db.update(TABLE_NAME, cv, where, whereValue);
  五、删除
  SQLiteDatabase db=this.getWritableDatabase();
    String where=FIELD_ID+"= ";
    String[] whereValue={Integer.toString(id)};
    db.delete(TABLE_NAME, where, whereValue);
参考文献:http://liangruijun.blog.51cto.com/3061169/663686/