android_问题总结

dalvik

       dalvik与jvm的区别: dalvik基于寄存器,jvm基于栈(stack,执行.class);一个应用对应一个dalvik,每一个 Dalvik应用作为一个独立的Linux进程执行执行dex字节码文件,独立的进程空间。

dalvik作用:完成对象生命周期管理、堆栈管理、线程管理、安全异常管理、垃圾回收

libdvm.so(核心内容实现库)

优势:  1、在编译时提前优化代码而不是等到运行时

    2、 虚拟机很小,使用的空间也小;被设计来满足可高效运行多种虚拟机实例。

    3、常量池已被修改为只使用32位的索引,以 简化解释器

dex整合多个.class文件减少整体文件尺寸(多class冗余),减少I/O,提高类的查找速度

多文件对应多常量池,dex文件一个常量池管理

Zygote是虚拟机实例的孵化器(fork())(复制,减少创建,加载系统库,资源的时间)

Zygote进程是在系统启动时产生的,它会完成虚拟机的初始化,库的加载,预置类库的加载和初始化等等操作

Dalvik两件事:处理JNI,提供Thread

在Dalvik下,应用每次运行的时候,字节码都需要通过即时编译器转换为机器码,这会拖慢应用的运行效率

JIT(Just-In-Time),用来在运行时动态地将执行频率很高的dex字节码翻译成本地机器码,然后再执行。通过JIT,就可以有效地提高Dalvik虚拟机的执行效率重新运行的时候,都要做重做这个翻译工作

安装时dex文件生成odex文件。这个过程由安装服务PackageManagerService请求守护进程installd来执行的

ART

ART(android runtime) 应用在第一次安装的时候,字节码就会预先编译成机器码,使其成为真正的本地应用。这个过程叫做预编译(AOT,Ahead-Of-Time)。这样的话,应用的启动(首次)和执行都会变得更加快速。

ART优点:

1、系统性能的显著提升。

2、应用启动更快、运行更快、体验更流畅、触感反馈更及时。

3、更长的电池续航能力。

4、支持更低的硬件。

ART缺点:

1、更大的存储空间占用,可能会增加10%-20%。

2、更长的应用安装时间,总的来说ART的功效就是“空间换时间”。

art与dalvik区别

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

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

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

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

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

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

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

Android中mvc

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

    1.视图层(view):一般采用xml文件进行界面的描述,使用的时候可以非常方便的引入,当然,如何你对android了解的比较的多了话,就一定 可以想到在android中也可以使用javascript+html等的方式作为view层,当然这里需要进行java和javascript之间的通 信,幸运的是,android提供了它们之间非常方便的通信实现。

 2.控制层(controller):android的控制层的重 任通常落在了众多的acitvity的肩上,这句话也就暗含了不要在acitivity中写代码,要通过activity交割model业务逻辑层处理, 这样做的另外一个原因是android中的acitivity的响应时间是5s,如果耗时的操作放在这里,程序就很容易被回收掉。

 3.模型层(model):对数据库的操作、对网络等的操作都应该在model里面处理,当然对业务计算等操作也是必须放在的该层的。

Activity
生命周期

    onCreate: 在这里创建界面,做一些数据 的初始化工作

 onStart: 到这一步变成用户可见不可交互的

    onResume:变成和用户可交互 的,(在activity 栈系统通过栈的方式管理这些个Activity的最上面,运行完弹出栈,则回到上一个Activity)

 onPause: 到这一步是可见但不可交互的,系统会停止动画 等消耗CPU 的事情从上文的描述已经知道,应该在这里保存你的一些数据,因为这个时候你的程序的优先级降低,有可能被系统收回。在这里保存的数据,应该在

 onstop: 变得不可见,被下一个activity覆盖了

   onDestroy: 这是activity被干掉前最后一个被调用方法了,可能是外面类调用finish方法或者是系统为了节省空间将它暂时性的干掉

Activity变窗口

清单文件activity中android :theme="@android :style/Theme.Dialog"

android:theme="@android :style/Theme.Translucent"//如果是作半透明的效果:

<item name="android:windowBackground">@android  :color/transparent</item>窗口背景色

<item name="android:windowFrame">@null</item>DialogwindowFrame框为无

<item name="android:windowIsFloating">true</item>是否浮现在activity之上

<item name="android:windowIsTranslucent">true</item>窗口是否半透明——是(与第一条配合使用)

<item name="android:windowAnimationStyle">@android  :style/Animation.Dialog</item>窗口弹出效果

<item name="android:backgroundDimEnabled">true</item> 是否允许背景模糊

<item name="android:windowContentOverlay">@null</item>这个不设置的话,可能会出现边框黑线

横竖屏切换生命周期问题

    1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次

    2、设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次

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

Activity四种启动模式

1.Standared(默认)激活该Activity,则会向任务栈中加入新创建的实例,退出Activity则会在任务栈中销毁该实例

       2.SingleTop这种模式会考虑当前要激活的Activity实例在任务栈中是否正处于栈顶,如果处于栈顶则无需重新创建新的实例,会重用已存在的实例,否则会在任务栈中创建新的实例。

       3.SingleTask如果任务栈中存在该模式的Activity实例,则把栈中该实例以上的Activity实例全部移除,调用该实例的newInstance()方法重用该Activity,使该实例处於栈顶位置,否则就重新创建一个新的Activity实例。

       4.SingleInstance当该模式Activity实例在任务栈中创建后,只要该实例还在任务栈中,即只要激活的是该类型的Activity,都会通过调用实例的newInstance()方法重用该Activity,此时使用的都是同一个Activity实例,它都会处于任务栈的栈顶。此模式一般用于加载较慢的,比较耗性能且不需要每次都重新创建的Activity

Activty启动流程

启动新的Activity需要借助于应用程序框架层的ActivityManagerService服务进程  ActivityManagerService和ActivityStack位于同一个进程中,ApplicationThread和ActivityThread位于另一个进程中,  ActivityManagerService是负责管理Activity的生命周期的,ActivityManagerService还借助ActivityStack是来把所有的 Activity按照后进先出的顺序放在一个堆栈中,ActivityThread来表示应用程序的主进程,而每一个ActivityThread都包含有一 个ApplicationThread实例,它是一个Binder对象,负责和其它进程进行通信

     1. 无论是通过Launcher来启动Activity,还是通过Activity内部调用startActivity接口来启动新的Activity,都通过Binder进程间通信进入到ActivityManagerService进程中,并且调用ActivityManagerService.startActivity接口; 

     2. ActivityManagerService调用ActivityStack.startActivityMayWait来做准备要启动的Activity的相关信息;

     3. ActivityStack通知ApplicationThread要进行Activity启动调度了,这里的ApplicationThread代表的是调用ActivityManagerService.startActivity接口的进程,对于通过点击应用程序图标的情景来说,这个进程就是Launcher了,而对于通过在Activity内部调用startActivity的情景来说,这个进程就是这个Activity所在的进程了;

     4. ApplicationThread不执行真正的启动操作,它通过调用ActivityManagerService.activityPaused接口进入到ActivityManagerService进程中,看看是否需要创建新的进程来启动Activity;

    5. 对于通过点击应用程序图标来启动Activity的情景来说,ActivityManagerService在这一步中,会调用startProcessLocked来创建一个新的进程,而对于通过在Activity内部调用startActivity来启动新的Activity来说,这一步是不需要执行的,因为新的Activity就在原来的Activity所在的进程中进行启动;

    6. ActivityManagerServic调用ApplicationThread.scheduleLaunchActivity接口,通知相应的进程执行启动Activity的操作;

    7. ApplicationThread把这个启动Activity的操作转发给ActivityThread,ActivityThread通过ClassLoader导入相应的Activity类,然后把它启动起来。

onSaveInstanceState() 和 onRestoreInstanceState()在什么时候被调用:

    Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并不是生命周期方法,它们不同于 onCreate()、onPause()等生命周期方法,它们并不一定会被触发。当应用遇到意外情况(如:内存不足、用户直接按Home键)由系统销毁一个Activity时,onSaveInstanceState()才会被调用。但是当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()就不会被调用。因为在这种情况下,用户的行为决定了不需要保存Activity的状态。通常onSaveInstanceState()只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。
    另外,当屏幕的方向发生了改变, Activity会被摧毁并且被重新创建,如果你想在Activity被摧毁前缓存一些数据,并且在Activity被重新创建后恢复缓存的数据。可以重写Activity的 onSaveInstanceState() 和 onRestoreInstanceState()方法。

android view的刷新:

    Android中对View的更新有很多种方式,使用时要区分不同的应用场合。我感觉最要紧的是分清:多线程和双缓冲的使用情况。
    1.不使用多线程和双缓冲
     这种情况最简单了,一般只是希望在View发生改变时对UI进行重绘。你只需在Activity中显式地调用View对象中的invalidate()方法即可。系统会自动调用 View的onDraw()方法。
    2.使用多线程和不使用双缓冲
    这种情况需要开启新的线程,新开的线程就不好访问View对象了。强行访问的话会报:android.view.ViewRoot$CalledFromWrongThreadException:Only the originalthread that created a view hierarchy can touch its views.
    这时候你需要创建一个继承了android.os.Handler的子类,并重写handleMessage(Messagemsg)方法。android.os.Handler是能发送和处理消息的,你需要在Activity中发出更新UI的消息,然后再你的Handler(可以使用匿名内部类)中处理消息(因为匿名内部类可以访问父类变量,你可以直接调用View对象中的invalidate()方法 )。也就是说:在新线程创建并发送一个Message,然后再主线程中捕获、处理该消息。
    3.使用多线程和双缓冲
    Android中SurfaceView是View的子类,她同时也实现了双缓冲。你可以定义一个她的子类并实现SurfaceHolder.Callback接口。由于实现SurfaceHolder.Callback接口,新线程就不需要android.os.Handler帮忙了。SurfaceHolder中lockCanvas()方法可以锁定画布,绘制玩新的图像后调用unlockCanvasAndPost(canvas)解锁(显示),还是比较方便得。

Application类的作用:

    如果想在整个应用中使用全局变量,在java中一般是使用静态变量,public类型;而在android中如果使用这样的全局变量就不符合Android的框架架构,但是可以使用一种更优雅的方式就是使用Application context。 
    首先需要重写Application,主要重写里面的onCreate方法,就是创建的时候,初始化变量的值。然后在整个应用中的各个文件中就可以对该变量进行操作了。 
    启动Application时,系统会创建一个PID,即进程ID,所有的Activity就会在此进程上运行。那么我们在Application创建的时候初始化全局变量,同一个应用的所有Activity都可以取到这些全局变量的值,换句话说,我们在某一个Activity中改变了这些全局变量的值,那么在同一个应用的其他Activity中值就会改变

android view,surfaceview,glsurfaceview的区别:

    SurfaceView是从View基类中派生出来的显示类,直接子类有GLSurfaceView和VideoView,可以看出GL和视频播放以及Camera摄像头一般均使用SurfaceView
SurfaceView和View最本质的区别在于,surfaceView是在一个新起的单独线程中可以重新绘制画面而View必须在UI的主线程中更新画面。 
    那么在UI的主线程中更新画面 可能会引发问题,比如你更新画面的时间过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应按键,触屏等消息。 
当使用surfaceView 由于是在新的线程中更新画面所以不会阻塞你的UI主线程。但这也带来了另外一个问题,就是事件同步。比如你触屏了一下,你需要surfaceView中thread处理,一般就需要有一个event queue的设计来保存touch event,这会稍稍复杂一点,因为涉及到线程同步。 


你可能感兴趣的:(android_问题总结)