Android总结随笔
Posted Airsolstice
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android总结随笔相关的知识,希望对你有一定的参考价值。
********************************
线程并发
线程锁
原子操作
********************************
触摸事件分发机制
********************************
ListView的缓存机制
********************************
自定义动画
********************************
IPC的过程
********************************
Activity的生命周期
********************************
四大组件所属的线程
********************************
java中 private和default的区别
********************************
IOC机制的实现
********************************
瀑布流的实现
********************************
UDP和TCP的原理
********************************
android开发中图和调用debug
17、自定义View的原理
a、编写attrs文件,自定义属性相关
b、编写相关实现类
在构造方法中获取相关自定义属性,在onLayout中确定控件的位置,在onMeasure中确定控件的大小,在onDraw中绘制控件的样子
16、Android启动过程
原文链接:http://m.kanzhun.com/k-mianshitimu/529367.html
1. 系统引导bootloader
1) 源码:bootable/bootloader/*
2) 说明:加电后,CPU将先执行bootloader程序,此处有三种选择
a) 开机按Camera+Power启动到fastboot,即命令或SD卡烧写模式,不加载内核及文件系统,此处可以进行工厂模式的烧写
b) 开机按Home+Power启动到recovery模式,加载recovery.img,recovery.img包含内核,基本的文件系统,用于工程模式的烧写
c) 开机按Power,正常启动系统,加载boot.img,boot.img包含内核,基本文件系统,用于正常启动手机(以下只分析正常启动的情况)
2. 内核kernel
1) 源码:kernel/*
2) 说明:kernel由bootloader加载
3. 文件系统及应用init
1) 源码:system/core/init/*
2) 配置文件:system/core/rootdir/init.rc,
3) 说明:init是一个由内核启动的用户级进程,它按照init.rc中的设置执行:启动服务(这里的服务指linux底层服务,如adbd提供adb支持,vold提供SD卡挂载等),执行命令和按其中的配置语句执行相应功能
4. 重要的后台程序zygote
1) 源码:frameworks/base/cmds/app_main.cpp等
2) 说明:zygote是一个在init.rc中被指定启动的服务,该服务对应的命令是/system/bin/app_process
source (service zygote /system/bin/app_process -Xzygote /system/bin –zygote –start- system-server
socket zygote stream 666)
a) 建立Java Runtime,建立虚拟机
b) 建立Socket接收ActivityManangerService的请求,用于Fork应用程序
c) 启动System Server
5. 系统服务system server
1) 源码:frameworks/base/services/java/com/android/server/SystemServer.java
2) 说明:被zygote启动,通过System Manager管理android的服务(这里的服务指frameworks/base/services下的服务,如卫星定位服务,剪切板服务等)
6. 桌面launcher
1) 源码:ActivityManagerService.java为入口,packages/apps/launcher*实现
2) 说明:系统启动成功后SystemServer使用xxx.systemReady()通知各个服务,系统已经就绪,桌面程序Home就是在ActivityManagerService.systemReady()通知的过程中建立的,最终调用startHomeActivityLocked()启launcher
7. 解锁
1) 源码:
frameworks/policies/base/phone/com/android/internal/policy/impl/*lock*
2) 说明:系统启动成功后SystemServer调用wm.systemReady()通知WindowManagerService,进而调用PhoneWindowManager,最终通过LockPatternKeyguardView显示解锁界面,跟踪代码可以看到解锁界面并不是一个Activity,这是只是向特定层上绘图,其代码了存放在特殊的位置
8. 开机自启动的第三方应用程序
1) 源码:
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
2) 说明:系统启动成功后SystemServer调用ActivityManagerNative.getDefault().systemReady()通知ActivityManager启动成功,ActivityManager会通过置变量mBooting,通知它的另一线程,该线程会发送广播android.intent.action.BOOT_COMPLETED以告知已注册的第三方程序在开机时自动启动。
9. 总结
综上所述,系统层次关于启动最核心的部分是zygote(即app_process)和system server,zygote它负责最基本的虚拟机的建立,以支持各个应用程序的启动,而system server用于管理android后台服务,启动步骤及顺序。
15、Service使用时的注意事项以及它的工作流程,对service的理解,service中如何调用toast
原文链接:http://m.blog.csdn.net/article/details?id=4986450
a、可以通过调用Context.startService()启动一个Service,这可能会触发Service的onCreate()和onStart()操作,具体来说即执行startService()一定会触发onStart(),但如果该Service已经在系统中存在,则onCreate()不会被再次调用,它只在Service第一次启动时触发。
通过Context.startService()启动的Service会一直运行,直到通过Context.stopService()或者stopSelf()停止它。多次通过startService()启动某个服务并不会生成多个实例,但会导致服务的onStart()被多次调用,当然由于只有一个实例,因此无论启动多少次,停止它只需调用一次Context.stopService()或stopSelf()就可以了。
2) 也可以通过Context.bindService()来获得一个服务的链接,这个链接是一直会保持到通过Context.unbindService()断掉它。如果在连接时系统中还没有该服务,则可能会新创建一个服务,这时Service的onCreate函数也同样会被调用。连接建立时会Service的onBinder会被触发,通过onBinder可以返回连接建立后的IBinder接口对象,使用服务的客户端(比如某个Activity)可以通过IBinder对象和Service交互。
一个Service如果是通过bindService()启动的,那么它会一直存在到没有任何客户端与它保持连接为止,原因是可能有很多客户端与这个服务保持连接,这时如果某个链接被客户端主动断掉只会是Service的链接数减1,当减至0的时候这个Service就会被销毁。
3) 一个Service既可以被启动(start)也可以被连接(bind),这时Service的生命周期取决于它被创建的方式,如果是通过Context.startService()创建的则和第一种情况一样,如果是通过Context.bindService()使用参数Context.BIND_AUTO_CREATE创建的,则情况和第二种一样。
当然,在Service停止,被销毁时,会触发其onDestroy()函数,我们需要在这里完成这个Service相关资源的清理,比如停止其子线程,注销监听器等等。
b.、相关的官方描述(Android SDK1.5)如下:
android-sdk文档 /docs/reference/android/app/Service.html
1) There are two reasons that a service can be run by the system. If someone calls Context.startService() then the system will retrieve the service (creating it and calling its onCreate() method if needed) and then call its onStart(Intent, int) method with the arguments supplied by the client. The service will at this point continue running until Context.stopService() or stopSelf() is called. Note that multiple calls to Context.startService() do not nest (though they do result in multiple corresponding calls to onStart()), so no matter how many times it is started a service will be stopped once Context.stopService() or stopSelf() is called.
2) Clients can also use Context.bindService() to obtain a persistent connection to a service. This likewise creates the service if it is not already running (calling onCreate() while doing so), but does not call onStart(). The client will receive the IBinder object that the service returns from its onBind(Intent) method, allowing the client to then make calls back to the service. The service will remain running as long as the connection is established (whether or not the client retains a reference on the service's IBinder). Usually the IBinder returned is for a complex interface that has been written in aidl.
3) A service can be both started and have connections bound to it. In such a case, the system will keep the service running as long as either it is started or there are one or more connections to it with the Context.BIND_AUTO_CREATE flag. Once neither of these situations hold, the service's onDestroy() method is called and the service is effectively terminated. All cleanup (stopping threads, unregistering receivers) should be complete upon returning from onDestroy().
如下是Service的生命周期时序图:
c、 几个需要注意的地方
1) Service无论以何种方式创建,都是在应用的主线程里创建的,也就是说创建一个Service并不意味着生成了一个新的线程,Service的创建过程是阻塞式的,因此也需要考虑性能,不能影响界面和逻辑上的后续操作。
2) 如果Service自己没有生成新的线程,那它也是运行在应用的主线程里的,因此Service本身并不能提高应用的响应速度和其他的性能,而是说通过这个后台服务生成新的线程来处理比较耗时的操作如大数据的读取等来提高响应,Service自己并不能保证这一点。Service相当于提供了一个这些费时操作的平台,由它在后台创建新线程完成这些任务,以及视各种情况管理这些线程,包括销毁。
3) stopService和unbindService都可以把Service停掉,但是如果希望明确立刻停掉Service,则使用stopService更安全,因为unbindService实质上是将与Service的连接数减一,当减为0的时候才会销毁该服务实例,stopService的效果相当于将连接数立即减为0,从而关闭该服务,所以在选择关闭方式上要视不同情况而定。
14、abstract关键字的理解
a、abstract修饰类时,这个类不能产生实例
b、abstract修饰方法时,这个方法没有具体实现。并且在非抽象子类中,需要覆盖重写。
c、如果有抽象方法,就一定是抽象类,是抽象类的,可以没有任何抽象方法
13、final关键字属性:
a、修饰变量,则这个基本类型变量不可改变值,对象类型变量则是不可改变引用地址
b、修饰方法,则这个方法不可被重写
c、修饰类,则这个类不可被继承
对于多线程访问同一资源时,我们经常采用锁的机制,这样通常会造成一定的延迟性,存在效率上的问题。相对于锁,ThreadLocal则是一种复制资源,牺牲空间来换取时间的做法。也就是我们会为需要共享的资源提供备份,然后分配给所需的线程唯一的副本变量。在ThreadLocal中,我们有一个线程安全的并发的Map数据结构,key存的是每个线程的hash code,而value则是这个线程所需的资源的副本,每次在线程中访问这个副本资源时,通过ThreadLocal这个所有线程的全局变量获取,如果map中存在,则直接引用,如果不存在,就为其提供一个副本存到数据结构中。
11、Android中Activity的四大启动模式:
a、standard:每次都创建一个实例Activity,并且同一对象可重叠
b、singleTop:可多实例存在与一个栈中,但是如果在启动时,有此对象的实例引用存在与栈顶,将不会创建新的对象,而是引用栈顶的对象进入onNewIntent方法。这表明,在这个模式下,可多实例化对象,但不能对象叠加
c、singleTask:只有一个对象存在与栈中,每次启动时,都要检查此对象是否存在于战中,如果存在于栈顶,则进入栈顶对象的onNewIntent方法中,如果存在,但是不再栈顶,则将这个对象之上的所有其他对象销毁,并且进入此对象的onNewIntenr方法中。若不存在,则实例化此对象。这表明,此方法只有一个实例对象,且不可重叠
d、singleInstance;在Task栈中,此Activity的唯一对象存在。如果在这个Task栈中新建其他对象时,就会为singleInstance模式的对象新建一个Task栈
10、Android的生命周期:
a、onCreate():简单的初始化操作
b、onStart():初始化复可能造成内存泄漏的资源
c、onRestoreInstanceState:阶段只有在系统认定需要数据恢复的时候对用,对于我们主观判定的数据恢复需要在onCreate中手动判断非空,而后恢复
d、onResume():初始化耗时长的操作,比如动画,视频,照相机。这个阶段开始,就是可视化阶段
e、onPause():在这阶段中,场景是用户未离开这个Activity,但是被别的事件遮住的时候,所有做的保护现场的操作。如:暂停视频播放,暂停照相机拍摄,暂停动画播放。并且保存一些节点信息。防止用户在这个阶段直接退出
f、onSaveInstanceState():这个阶段并不是就在onPause之前或之后,他们二者没有先后关系。只能确定是在onStop之前进行。这个阶段的目的是存储一些保护现场状态的数据。防止进程被杀掉而失去现场状态
g、onStop():在这个阶段释放那些可导致内存泄漏的资源。因为从这个阶段开始,Activity又变为不可视而进入后台,这也就意味着有被扼杀的风险。并且如果在强制扼杀的时,如finish,是会跳过这个阶段,直接onDestroy掉的
h、onDestroy():这个阶段,销毁整个Activity
9、Fragment的那些事:
a、在Fragment的切换之间,我们不推荐一直使用add方法添加事务,而是用hide,add,show三者配合来加载不同的页面,但是这个处理方式是不释放所有界面的资源,因此适用于资源不大的情况
b、Fragment的生命周期是以来与Activity的,也就意味这如果Activity销毁,Fragment也会销毁。而setRetainInstance(true)这个方法用来防止Fragment随Activity销毁而导致的现场状态被破坏。在设为非中断保存的情况下,在每次销毁时,将数据保存下来,为后面恢复使用。所以如果想要真正销毁他, 就需要在销毁时,连同数据一起销毁
8、Java中Reference:
Reference其实就是一个内存地址。指向存放对象相关信息的空间。
a、StrongReference:不会被GC回收。但没有对应的类型。
b、SoftReference:在内存不足的情况下,引用对象才会被回收。所以大量用于cache和pooling中
c、WeakReference:一旦被GC检测到,就会被回收
d、PhantomReference:一旦被GC发现,就会将其入队到ReferenceQueue中。在被你真正使用过后,就会将其回收
7、设计模式:
a、饿汉模式是线程安全的,懒汉模式是线程不安全的。因为饿汉是在这个单例类第一次引用的时候就初始化了对象。后面不管都少个线程来使用它,都是使同一对象。不会造成如银行扣钱,账户却多钱的情况。至于懒汉模式的避免线程不安全的三大做法是:1,在实例方法前加入sycchronized关键字。2、在实例方法中,对整个单例对象进行加锁控制,并且通过先判断变量,在锁定对象,再判断变量的方式,达到高度安全。3、是依据饿汉模式的效果,在实例方法中,嵌套一个饿汉类,达到只要一触发懒汉的实例方法,就会触发饿汉的机制。既有延迟,又有安全。这种方法是最好的
b、原型模中需要重写clone方法。在实现该方法的过程中,又分为深拷贝和浅拷贝。深拷贝指的是在clone的过程中,不仅将一个对象的引用拷贝过去,还将该引用的所指向的对象也拷贝一份。也就是值栈和对象堆都需要复制。而后所有的操作将变为独立不影响。而浅拷贝则知识拷贝了引用,clone体和被clone者将共用一个对象
6、原子操作:
在JSR 166以前,我们java并未从硬件上提供原子操作的支持。所以,只能使用syhchrozied这个关键字进行软件上的资源独占,或者使用voliate这个关键字保证当前获取的值是最新的。但是我们要知道4个概念:
a、java中线程运行的过程是这样的:当一个线程开始时,会有一个线程值栈,保存所有线程的变量引用。并且把这个变量所指向的值拷贝一份到对象堆中,而后,线程所有的操作都是对对象堆中值的操作,与值栈中的变量引用所指向的值没有任何关系。在经过若干时间后,完成了对变量的操作后,又将值提交到变量所指向的地址空间中。
b、原子操作的概念:就是在执行某个动作的是,无法在分解动作,只能一次性执行完的操作,叫做原子操作。在x86的CPU中,通常是通过对CPU LOCK引脚的控制,达到某一个命令在执行过程中是无法取消的。这就是从硬件上的原子控制
c、voliate关键字的作用是,是直接从地址空间中取出最新的。他能保证这个值的最新性
d、synchrozied关键字的作用是,在被修饰之后,将独占所有相关资源,直到放开锁为止
通过上述概念,我们知道,voliate关键字是根本无法达到原子性的需求。因为线程执行的时间是根本不收控制的。在一个线程执行的过程中,会有其它线程去获取变量空间中的值。从而导致线程不安全性、
在JSR 166以后,java提供了上述硬件方式的JNI底层支持。从而实现了CAS为保证的原子操作。每次在计算的过程中,比较当前的值与期望值是否一致,如果一致,将执行计算操作(compare and set)
5、Handler那些事:
Handler的使用,其实就是两个机制的创建。一个是MessageQueue的创建,一个是Looper的创建。如果这两个都创建成功,就能正常进行工作
a、Looper的实现调用过程:由于每个app就是一个dvm虚拟机,即一个Linux线程。所以当打开一个app时,就进入main方法,在main中,为ActivityThread初始化一个Looper,同时在Looper中创建一个MessageQueue对象。再把这个Looper放到ThreadLocal中,以便Handler的管理。然后在通过looper()方法,轮询处理队列中的每一个消息。处理的过程中,首先进行分发,dispatchMessage(),处理msg中的runnable对象,再处理自带的runnable对象,如果处理失败,最后处理handler中的重写的方法。
b、ThreadLocal提供Looper的副本
c、Handler的源码执行过程;
/**构造方法**/
public Handler()
//判断handler的合法性
if (FIND_POTENTIAL_LEAKS)
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0)
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
//从ThreadLocal中获取出Looper副本
mLooper = Looper.myLooper();
//如果没有Looper对象,就抛出异常
if (mLooper == null)
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
//从Looper中获取MessageQueue对象,从而可以在Handler中操作入队(enqueue)和出队(next)操作
mQueue = mLooper.mQueue;
//初始化Handler的Callback对象,在dispatchMessage方法中调用
mCallback = null;
/**从ThreadLocal中获取一个Looper副本
public static final Looper myLooper()
return (Looper)sThreadLocal.get();
/**初始化Looper**/
public static final void prepare()
//判断ThreadLocal中是否有已经存在Looper对象
if (sThreadLocal.get() != null)
throw new RuntimeException("Only one Looper may be created per thread");
sThreadLocal.set(new Looper());
/**ActivityThread中的main函数**/
public static void main(String[] args)
SamplingProfilerIntegration.start();
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
EventLogger.setReporter(new EventLoggingReporter());
Process.setArgV0("<pre-initialized>");
//进行Looper对象的准备工作
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null)
sMainThreadHandler = thread.getHandler();
AsyncTask.init();
if (false)
Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
//主函数中Looper对象的准备工作
public static final void prepareMainLooper()
prepare();
setMainLooper(myLooper());
if (Process.supportsProcesses())
myLooper().mQueue.mQuitAllowed = false;
/**最终的发送数据的方法
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
//发送状态
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null)
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
else
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return sent;
/**入队操作**/
final boolean enqueueMessage(Message msg, long when)
if (msg.when != 0)
throw new AndroidRuntimeException(msg + " This message is already in use.");
if (msg.target == null && !mQuitAllowed)
throw new RuntimeException("Main thread not allowed to quit");
synchronized (this)
if (mQuiting)
RuntimeException e = new RuntimeException(msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
return false;
else if (msg.target == null)
mQuiting = true;
msg.when = when;
Message p = mMessages;
if (p == null || when == 0 || when < p.when)
msg.next = p;
mMessages = msg;
this.notify();
else
Message prev = null;
while (p != null && p.when <= when)
prev = p;
p = p.next;
msg.next = prev.next;
prev.next = msg;
this.notify();
return true;
public static final void loop()
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true)
Message msg = queue.next(); // might block
if (msg != null)
if (msg.target == null)
return;
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
msg.target.dispatchMessage(msg);
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
msg.recycle();
public void dispatchMessage(Message msg)
//判断Message对象是否有携带callback接口
if (msg.callback != null)
handleCallback(msg);
else
//判断Handler对象是否携带callback对象
if (mCallback != null)
//如果有则执行回调,并且判断是否消费这个Message,如果返回值定义为false,则继续传递事件,
if (mCallback.handleMessage(msg))
return;
//执行Handler中复写的回调方法
handleMessage(msg);
4、AsyncTask开发需要注意的地方:
a、在android1.6到2.3.2中,AsyncTask使用顺序执行多线程;在2.3.2到3.0之间,AsyncTask实现了多线程并发,但是在多线程访问同一资源时,会出现问题。3.0以后,AsyncTask又改为顺序执行多线程。并且支持多线程并发执行,
使用
CustomAsyncTask task = new CustonAsyncTask();
task.executeOnExecutor(mThreadPoolExecutor);
b、AsyncTask作为内部类的时候,会隐式调用Activity,如果AsyncTask一直在执行,就会导致Activity对象不能被释放。
c、AsyncTask的生命周期和Activity的生命周期是不同步的。在Activity中启动AsyncTask后,如果不使用AsyncTask.cancel
方法取消任务,那么Task就会一直执行下去,即使Activity销毁,程序退出。因此,使用不当将导致内存泄露。引发一些问题:
在横屏Activity中启动一个Task,然后切位竖屏,Task却没销毁,当它执行完成后,更新的UI其实已经不存在了。就会导致强退
3、ListAdapter实现多Item布局显示
重写getViewItemType方法和getItemTypeCount方法
2、StringBuffer和StringBuild的区别:
String 字符串常量
StringBuffer 字符串变量(线程安全)
StringBuilder 字符串变量(非线程安全)
正因为StringBuffer是线程安全的,而StringBuilder是线程不安全的。因此,StringBuilder的效率高
简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后,JVM 的 GC 就会开始工作,那速度是一定会相当慢的。
而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的:
String S1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”); 你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个 String S1 = “This is only a” + “ simple” + “test”; 其实就是: String S1 = “This is only a simple test”; 所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如: String S2 = “This is only a”; String S3 = “ simple”; String S4 = “ test”; String S1 = S2 +S3 + S4; 这时候 JVM 会规规矩矩的按照原来的方式去做
在大部分情况下 StringBuffer > String
StringBuffer
Java.lang.StringBuffer线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。
可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。
StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。
例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append("le") 会使字符串缓冲区包含“startle”,而 z.insert(4, "le") 将更改字符串缓冲区,使之包含“starlet”。
在大部分情况下 StringBuilder > StringBuffer
java.lang.StringBuilder
java.lang.StringBuilder一个可变的字符序列是5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同
1、内部类的作用
a、内部类可以使很好的实现隐藏:一般的非内部类是不允许有private和protected权限的,但是内部类可以
b、内部类拥有外围类的所有元素的访问权限
c、可是变向实现多继承
d、可以避免修改接口而实现同一个类中两个同名方法的调用
以上是关于Android总结随笔的主要内容,如果未能解决你的问题,请参考以下文章