• 转:Android性能优化

    http://rayleeya.iteye.com/blog/1961005

     

    文章都为原创,转载请注明出处,未经允许而盗用者追究法律责任。  

    编写者:李文栋

    Android性能优化

    根据Android的层次结构,性能优化也是分层次进行的,本文会分别对Application、Framework、Native、Kernel各层做总结,每层主要会从性能优化的基本思想、优化技巧、优化工具几个方面进行说明。

    第一章Android应用性能优化(概述)

    应用程序的性能问题是最明显、最容易体现的一类,表现形式也五花八门,举几个例子:

    • 应用程序第一次启动速度慢,或者进入某一界面速度慢;
    • 启动某一有动画效果的界面,动画执行过程不流畅,或者动画执行前卡顿时间长;
    • ListView列表滑动过程中卡顿,不流畅;
    • 应用程序自定义的某特定界面执行速度慢,例如Launcher应用桌面左右滑动效果不平滑;
    • 响应某一用户事件时长时间无响应(ANR);
    • 操作数据库时,执行大量数据的增删改查操作,执行速度慢;
    • 应用长时间运行后,随机出现卡顿现象;

    除了表现形式复杂,原因也很复杂。以上的问题的原因可能不只一个,并且很多情况下并不是应用本身的问题,也有可能是系统其他层次有问题,只不过体现在 应用层。所以说应用层总是首当其冲,开发人员在处理性能问题时,需要做的第一件事情就是判断是否是应用自身引起的性能问题,然后再对症下药;但有些时候应 用本身逻辑正常,明显是系统的硬件配置不足引起,此时就要根据产品或项目需求,采取一些更加激进的方式优化性能,以弥补硬件配置的不足。

    以下从几个不同的角度总结一下应用程序性能优化的一些方法。

    一、基本思想

    应用层的性能优化通常可以从以下几个方面考虑:

    1. 了解编程语言的编译原理,使用高效编码方式从语法上提高程序性能;
    2. 采用合理的数据结构和算法提高程序性能,这往往是决定程序性能的关键;
    3. 重视界面布局优化;
    4. 采用多线程、缓存数据、延迟加载、提前加载等手段,解决严重的性能瓶颈;
    5. 合理配置虚拟机堆内存使用上限和使用率,减少垃圾回收频率;
    6. 合理使用native代码;
    7. 合理配置数据库缓存类型和优化SQL语句加快读取速度,使用事务加快写入速度;
    8. 使用工具分析性能问题,找出性能瓶颈;

    当然肯定还有很多其他的性能优化方法,此处仅列出一些经常会用到的方法。限于篇幅,以下会对其中一部分内容做介绍,希望能够对大家做性能优化工作有所帮助。

    二、编程技巧

    (一)Performance Tips (For Java)

    Google官网上有一些关于应用程序性能提升的技巧,之前公司内也有很多总结提到过,在此简单罗列一下,详细内容可以从官网获取。

    http://developer.android.com/training/articles/perf-tips.html

    需要说明的是,文章列出的优化技巧主要是一些微小的性能提升,决定程序整体性能的仍然取决于程序的业务逻辑设计、代码的数据结构和算法。研发人员需要将这些优化技巧应用到平时的编码过程中,积少成多,也会对性能有很大的影响。

    写出高效的代码需要遵循两条原则:

    • 不执行不必要的操作;
    • 不分配不必要的内存;

    两条原则分别针对CPU和内存,完成必要操作的前提下尽可能的节省CPU和内存资源,自然执行效率要高。单纯这样说听起来很虚,毕竟没有一个统一的标准判断什么是必要和不必要的,需要结合具体情况具体分析了。

    1. 避免创建不必要的对象

    创建太多的对象会造成性能低下,这谁都知道,可是为什么呢?首先分配内存本身需要时间,其次虚拟机运行时堆内存使用量是有上限的,当使用量到达一定程度 时会触发垃圾回收,垃圾回收会使得线程甚至是整个进程暂停运行。可想而知,如果有对象频繁的创建和销毁,或者内存使用率很高,就会造成应用程序严重卡顿。

         2.合理使用static成员

    主要有三点需要掌握:

    • 如果一个方法不需要操作运行时的动态变量和方法,那么可以将方法设置为static的。
    • 常量字段要声明为“static final”,因为这样常量会被存放在dex文件的静态字段初始化器中被直接访问,否则在运行时需要通过编译时自动生成的一些函数来初始化。此规则只对基本类型和String类型有效。
    • 不要将视图控件声明为static,因为View对象会引用Activity对象,当Activity退出时其对象本身无法被销毁,会造成内存溢出。
    1.       避免内部的Getters/Setters

    面向对象设计中,字段访问使用Getters/Setters通常是一个好的原则,但是在Android开发中限于硬件条件,除非字段需要被公开访 问,否则如果只是有限范围内的内部访问(例如包内访问)则不建议使用Getters/Setters。在开启JIT时,直接访问的速度比间接访问要快7 倍。

    1.       使用for-each循环

    优先使用for-each循环通常情况下会获得更高的效率;除了一种情况,即对ArrayList进行遍历时,使用手动的计数循环效率要更高。

    1.       使用package代替private以便私有内部类高效访问外部类成员

    私有内部类的方法访问外部类的私有成员变量和方法,在语法上是正确的,但是虚拟机在运行时并不是直接访问的,而是在编译时会在外部类中自动生成一些包 级别的静态方法,执行时内部类会调用这些静态方法来访问外部类的私有成员。这样的话就多了一层方法调用,性能有所损耗。

    一种解决这个问题的方法就是将外部类的私有成员改为包级别的,这样内部类就可以直接访问,当然前提是设计上可接受。

    1.       避免使用浮点类型

    经验之谈,在Android设备中浮点型大概比整型数据处理速度慢两倍,所以如果整型可以解决的问题就不要用浮点型。

    另外,一些处理器有硬件乘法但是没有除法,这种情况下除法和取模运算是用软件实现的。为了提高效率,在写运算式时可以考虑将一些除法操作直接改写为乘法实现,例如将“x / 2”改写为“x * 0.5”。

    1.       了解并使用库函数

    Java标准库和Android Framework中包含了大量高效且健壮的库函数,很多函数还采用了native实现,通常情况下比我们用Java实现同样功能的代码的效率要高很多。所以善于使用系统库函数可以节省开发时间,并且也不容易出错。

    (二)布局性能优化

    布局直接影响到界面的显示时间。关于界面布局的性能优化在技术上并没有难点,个人认为最重要的是是否认识到布局优化的重要性。起初我也会觉得布局本身 不会是性能瓶颈,并且也很难优化,好不容易写了复杂的布局文件,或者原生代码就是那样,而且也用log查看了setContentView的时间,似乎没 什么问题,实在是不想去研究。但实际上布局问题没有想象的那么简单。

    布局的性能优化之所以重要,因为以下两个方面:

    •          布局文件是一个xml文件,inflate布局文件其实就是解析xml,根据标签信息创建相应的布局对象并做关联。xml中的标签和属性设置越多,节点树的深度越深,在解析时要执行的判断逻辑、函数的嵌套和递归就越多,所以时间消耗越多;
    •       inflate操作只是布局影响的第一个环节,一个界面要显示出来,在requestLayout后还要执行一系列的measure、 layout、draw的操作,每一步的执行时间都会受到布局本身的影响。而界面的最终显示是所有这些操作完成后才实现的,所以如果布局质量差,会增加每 一步操作的时间成本,最终显示时间就会比较长。

    那么布局如何优化?总结如下几点:

    1. 遵循一条规则:布局层次尽量少

    也就是说,在达到同样布局效果的前提下,xml文件中树的深度尽量的潜。要做到这一点需要合理的使用布局控件:

    • 典型的情况是你可以使用RelativeLayout来代替LinearLayout实现相同的布局效果;
    • 还有一种是如果布局树的A节点只有一个子节点B,而B只有一个子节点C,那么B通常是可以去掉的;
    • 合理的使用<merge>标签,如果布局X可以被include到Y中,那么需要考虑X的根节点是否可以设置为<merge>,这样在解析时会将<merge>的子节点添加到Y中,而<merge>本身不会添加。
    1. 使用Lint分析布局

    Lint是SDK中tools目录下的工具,ADT中集成了Lint的可视化控制界面。用Lint扫描应用程序,它会从很多方面对应用进行分析,并提示那些可能有缺陷的地方,其中就包含与性能相关的内容。你可以在Google官网上了解详细信息。

    http://developer.android.com/tools/debugging/improving-w-lint.html

    http://developer.android.com/tools/help/lint.html

    1. 使用HierarchyViewer分析布局

    HierarchyViewer(以下简称HV)也是SDK中tools目录下的工具,ADT中也集成了HV的可视化控制界面。可以使用HV查看当前界面的布局,它能提供很多信息,其中有两个可以帮助我们分析性能问题:

    •          HV的树视图展现了视图控件的相互关系,可以用来检查是否有第1点中提到的情况。
    •         树视图中可以显示每个节点measure、layout、draw的时间,并且每一项用一个圆点表示其耗时是否正常,每个圆点分别用绿色、黄色、红 色表示耗时正常、警告、危险,这样就可以很方便的找到有性能瓶颈了。如果树视图中没有显示这些时间,你可以点击“Obtain layout times for tree rooted at selected node”按钮刷新界面显示。

    http://developer.android.com/tools/debugging/debugging-ui.html

    1.       使用ViewStub延迟加载视图

    ViewStub是一个没有尺寸大小并且不会在布局中嵌套或渲染任何东西的轻量级的视图。如果界面中有一部分视图控件不需要立即显示,则可以将其写到 一个单独的layout文件中,用ViewStub标签代替,当要真正显示这部分内容时再通过ViewStub将视图加载进来。

    http://developer.android.com/training/improving-layouts/loading-ondemand.html

    三、工具使用

    遵循好的编码习惯可以让程序执行更有效率,但是实际运行时仍然会遇到各种各样的性能问题。幸好有很多强大的工具能帮助我们分析性能瓶颈,找到问题所 在。以下介绍的工具想必大家已经很熟悉了,网上有很多相关文章写的都很不错,在此不再赘述,仅对这些工具在使用时的一些关键点做一些说明。关于这些工具的 详细使用方法请见网上的一篇文章:http://blog.csdn.net/innost/article/details/9008691

    (一)Traceview

    做性能优化的最直接的方法,就是复现有性能问题的场景,并监控此过程中程序的执行流程,如果能够方便的分析程序中函数的调用关系和执行时间,自然也就很容易找出性能瓶颈了。

    Traceview就是用来分析函数调用过程的工具,利用它可以方便的分析性能问题。它的使用方式需要以下几步:

    • 使用Android的Debug API,或者DDMS监控程序运行过程;
    • 复现有性能问题的场景,用第1步的方法获取程序过程中的函数调用日志文件,即trace文件;
    • 使用Traceview导入trace文件即可;

    Traceview的界面很直观,但是在分析过程中需要特别注意以下几点:

    1. Profile Panel中的各列的含义
    • Incl – 指函数本身和内部嵌套的其他函数的执行时间;
    • Excl –  指函数本身,不包含内部嵌套的其他函数的执行时间;
    • Cpu Time – 指函数执行时所占用的CPU时间片的总和,不包含等待调度的时间;
    • Real Time – 指函数执行过程的真实时间,包含等待调度的时间;
    • Cpu Time/Call – 指函数平均每次调用的CPU时间;
    • Real Time/Call – 指函数平均每次调用的真实时间;
    • Calls+Recur Calls/Total – 指函数调用的总次数+递归调用次数百分比;
    • % – 带有%的列是指函数的执行时间占总采样时间的百分比;
    1. 如何分析性能瓶颈

    首先通常需要关心的是CPU时间,可以找出程序自身的问题,真实时间会受到系统其他因素的影响。然后可以从四个方面进行分析:

    1)分析有哪些函数单次执行时间长

    可以点击“Cpu Time/Call”一列,按照降序排列,并找出那些执行时间相对较长同时也是我们关心的函数,然后再查看其函数内部的详细执行过程;

    2)分析有哪些函数调用次数过多

    可以点击“Calls+RecurCalls/Total”一列,按照降序排列,并找出哪些执行次数相对较多同时也是我们关心的函数,然后再查看其函数内部的详细执行过程;

    3)分析有哪些函数总执行时间长

    有些函数的单次执行时间不是特别长,总调用次数也不是特别多,但是二者相乘得出的总的执行时间较长,可以点击“Incl Cpu Time”,按照降序排列,找出这些函数;

    4)有时我们很明确需要查看一些特定类的特定方法,可以在页面最下方的搜索条中搜索,不过好像只支持全小写输入。

    1.       提示一点:利用API或工具采样trace信息时,会禁用JIT功能,同时因为采样本身也需要占用系统资源,所以用Traceview查看函数的执行时间都要比正常运行时慢不少,我们只要关心相对的时间消耗即可。

    (二)dmtracedump

    trace文件除了可以用TraceView分析外,还可以利用另外一个工具dmtracedump,它的功能也很强大。如果你觉得在Traceview中查找类和函数很痛苦,不妨试试这个工具。

    dmtracedump是SDK的tools目录下的可执行文件,你可以查看它的帮助信息,并执行类似如下的命令:

    dmtracedump -h -g tracemap.png path-to-your-trace-file > path-to-a-html-file.html

    然后就可以得到两样东西,一个是各函数调用的树状图,可以一目了然的查看函数关系;另一个是可操作的html的文件,用浏览器打开就可以方便的查找你关心的类或函数。

    (三)systrace

    Systrace是从4.1引入的一个强大的性能分析工具,依赖于Kernel的ftrace功能,可以对系统中很多重要模块,特别是图形显示模块做 性能分析。它功能包括跟踪系统的I/O操作、内核工作队列、CPU负载以及Android各个子系统的运行状况等。

    Systrace的使用方法也是需要先通过Android提供的API或者DDMS开启跟踪监控模式,然后运行程序生成日志文件,最后分析日志文件即 可。Systrace输出的是一个html文件,直接用浏览器查看即可。如果你使用最新版本的ADT,可以很方便的通过界面操作,不用再用命令了。更详细 的内容可以在网上搜索。

    四、关于性能优化的思考

    性能优化是一个很大的话题,除了讨论如何优化外,还有一个更重要的就是是否需要优化。早在几十年前,就有很多关于性能优化的讨论,然后得出一个深刻的 真理:优化更容易带来伤害,而不是好处,特别是不成熟的优化。在优化过程中,你产生的软件可能既不快速,也不正确,而且还不容易被修正。

    不要因为性能而牺牲合理的结构。努力编写好的程序而不是快的程序。

    但是,这并不意味着,在完成程序之前你就可以忽略性能问题。实现上的问题可以通过后期的优化而被改正,但遍布全局并且限制性能的结构缺陷几乎是不可能 被改正的,除非重新编写程序。在系统完成之后再改变你的设计的某个基本方面,会导致你的系统结构病态,从而难以维护和改进。因此你应该在设计过程中考虑性 能问题。

     

    努力避免那些限制性能的设计。考虑你的代码设计的性能后果。为获得好的性能而对代码进行曲改,是一个非常不好的想法。在每次做优化之前和之后,需要对性能进行测量。

  • Android UI 优化-使用theme 预加载

    http://www.oschina.net/question/54100_34081

    在很多时候,我们需要给一个Layout设置一个背景。例如,我们下下面的layout中使用了这样一个背景:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <?xml version=”1.0″ encoding=”utf-8″?>
    <LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”    android:orientation=”vertical”
    android:layout_width=”fill_parent”
    android:layout_height=”fill_parent”
    android:background=”@drawable/antelope_canyon”>
    <TextView android:text=”@+id/TextView01″
    android:id=”@+id/TextView01″
    android:layout_width=”wrap_content”
    android:layout_height=”wrap_content” >
    </TextView>
    </LinearLayout>

    其中的LinearLayout使用了 背景图片antelope_canyon。

    如果仔细观察程序的运行过过程,我们首先看到了黑色的activity背景,然后才看到背景图被加载,那是因为在activity start以后,我们才能调用setContentView设置我们的layout,然后才绘制我们在layout中放置的背景图。而在此之前,程序中绘 制的是android中默认黑色背景。 这样会给用户感觉我们的activity启动较慢。
    然而,如果将背景图定义在一个主题中,如下:

    1
    2
    3
    4
    5
    6
    7
    <?xml version=”1.0″ encoding=”utf-8″?>
    <resources>
    <style name=”Theme.Droidus” parent=”android:Theme”>
    <item name=”android:windowBackground”>@drawable/antelope_canyon</item>
    <item name=”android:windowNoTitle”>true</item>
    </style>
    </resources>

    然后在activity中使用这个主题 :

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <?xml version=”1.0″ encoding=”utf-8″?>
    <manifest xmlns:android=”http://schemas.android.com/apk/res/android”
    package=”com.droidus”
    android:versionCode=”1″
    android:versionName=”1.0″>
    <application android:icon=”@drawable/icon” android:label=”@string/app_name”>
    <activity android:name=”.SpeedUpStartupActivity”
    android:label=”@string/app_name”
    android:theme=”@style/Theme.Droidus”
    >
    <intent-filter>
    <action android:name=”android.intent.action.MAIN” />
    <category android:name=”android.intent.category.LAUNCHER” />
    </intent-filter>
    </activity>
    </application>
    <uses-sdk android:minSdkVersion=”4″ />
    </manifest>

    运行程序,可以看到背景图马上显示了,没有再看到黑色的背景图。

    为什么会有这样的现象呢?那是因为 程序的主题是在程序启动的时候加载的,而不是在activity启动之后加载!
    而如果在layout使用背景,背景图是在activity启动之后才加载,故而会让用户看到一个黑色背景闪动的过程。

  • Android 布局优化

    布局优化
    --------
    1. setContentView调用花费的时间取决于布局的复杂性:资源数据越大解析越慢,而更多的类也让布局实例化变慢
    2. 调用setContentView()几乎占用了从onCreate()开始到onResume()结束之间所有时间的99%
    3. 要节约时间,大多数基于同样的原则:减少创建对象的数量。消除不必要的对象,或者推迟创建对象
    4. 采用嵌套的线性布局会深化布局层次,从而导致布局和按键处理变慢。
    5. 合并布局。另一种减少布局层次的技巧是用<merge />标签来合并布局。
        Android布局的父视图是一个FrameLayou,如果你的布局的最上层也是一个FrameLayout,就可以用<merge />标签代替它,减少一层布局
    6. 重用布局,Android支持在XML布局中使用<include /> 标签,用来包含另一个布局。
        <include /> 标签可用于两个目的:
        1) 多次使用相同的布局
        2) 布局有一个通用的组成部分,或有部分依赖于设置配置(例如,屏幕方向纵向或横向)
    7. ViewStub
        推迟初始化是个方便的技术,可以推迟实例化,提高性能,还可能会节省内存(如果对象从未创建过)
        ViewStub是轻量级且不可见的视图,当需要时,在自己的布局中可以用它来推迟展开布局。
         下次遇到相关代码后,将代码整理在这里
    布局工具
    --------
    1. hierarchyviewer  用来查看布局的
    2. layoutopt  用于检测布局文件质量的
  • 基本界面控件

    五、基本界面控件

    大多数的界面控件都在android.view和android.widget包中,android.view.View为他们的父类,还有Dialog系列,android.app.Dialog为父类,等等。

    Android的原生控件,一般是在res/layout下的 xml文件中声明。然后在Activity通过使用super.setContentView(R.layout.某布局layout文件名)来加载 layout。在Activity中获取控件的引用需要使用super.findViewById(R.id.控件的ID),接着就可以使用这个引用对控 件进行操作,例如添加监听,设置内容等。当然也可以通过代码动态的使用控件。

     

    View子类结构图:

     

     

    TextView子类结构:

     

     

    ViewGroup子类结构图:

     

     

    FrameLayout子类结构:

     

     

    android.app.Dialog子类结构:

     

    第一部分,基本控件

    1.文本类:

    http://limingnihao.iteye.com/blog/851386

    TextView、EditText、AutoCompleteTextView、MultAutoCompletTextView 、(TextSwitcher) 、(DigitalClock)

     

    ExtractEditText、CheckedTextView、Chronometer

     

    2.按钮类:

    http://limingnihao.iteye.com/blog/851396

    Button、CheckBox、RadioButton(RadioGroup) 、ToggleButton 、(ImageButton )

     

    CompoundButton

     

    缩放按钮:

    ZoomButton、ZoomControls

     

    3.图片类:

    http://limingnihao.iteye.com/blog/851408

    ImageView、ZoomButton、ImageButton、(ImageSwitcher )

     

    QuickContactBadge

     

    4.时间控件:

    http://limingnihao.iteye.com/blog/852493

    DigitalClock、AnalogClock、TimePicker、DatePicker

     

    5.进度显示:

    http://limingnihao.iteye.com/blog/852498

    ProgressBar、AbsSeekBar、SeekBar、RatingBar

     

    6.导航:

    TabHost、TabWidget。

     

    7.视频媒体:

    VideView、MediaController

     

    8.Dialog对话框

    CharacherPickerDialog、AlertDialog、DatePickerDialog、ProgressDialog、TimePickerDialog

     

    第二部分,布局类

    1.布局类:

    AbsoluteLayout、LinearLayout、RadioGroup 、TableLayout、 TableRow、RelativeLayout、FrameLayout

     

    2.需要适配器的布局类:

    AdapterView、AbsListView、GridView、ListView、AbsSpinner、Gallery Spinner

     

    3.滚动条:

    HorizontalScrollView、ScrollView

     

    第三部分,其他

    网页:

    WebView

     

    动画:

    ViewAimator、ViewFilpper、ViewSwitcher、ImageSwitcher、TextSwitcher

     

    其他:

    KeyboardView

    SurfaceView(照相时会使用) GLSurfaceView

    ViewStub DialerFilter TwolineListItem SlidingDrawer GestureOverlayView

     

    其中:

    ListView一般与ListActivity一一起使用。TabActivity: http://limingnihao.iteye.com/

    TabHost、TabWidget一般与TabActivity一起使用。ListActivity: http://limingnihao.iteye.com/

  • setContentView

    http://android-developers.blogspot.in/2009/03/android-layout-tricks-3-optimize-with.html

    Android中visibility属性VISIBLE、INVISIBLE、GONE的区别

    在Android开发中,大部分控件都有visibility这个属性,其属性有3个分别为“visible ”、“invisible”、“gone”。主要用来设置控制控件的显示和隐藏。有些人可能会疑惑Invisible和gone是有什么区别的???那 么,我们带着这个疑问看下面:

    其在XML文件和Java代码中设置如下:

     

     

    可见(visible)

    XML文件:android:visibility=”visible”

    Java代码:view.setVisibility(View.VISIBLE);

     

    不可见(invisible)

    XML文件:android:visibility=”invisible”

    Java代码:view.setVisibility(View.INVISIBLE);

     

    隐藏(GONE)

    XML文件:android:visibility=”gone”

    Java代码:view.setVisibility(View.GONE);

     

     

    为了区别三者,我建了一个Dome进行演示,先上Dome的代码,演示后就知道它们的区别:

    XML文件:

    1. <?xml version=“1.0” encoding=“utf-8”?>
    2. <LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”
    3.     android:layout_width=“fill_parent”
    4.     android:layout_height=“fill_parent”
    5.     android:orientation=“vertical”>
    6.     <LinearLayout
    7.         android:layout_width=“fill_parent”
    8.         android:layout_height=“wrap_content”
    9.         android:orientation=“horizontal”
    10.         android:layout_marginBottom=“20dip” >
    11.         <TextView
    12.             android:layout_width=“wrap_content”
    13.             android:layout_height=“wrap_content”
    14.             android:layout_weight=“1”
    15.             android:background=“#F00”
    16.             android:text=“TextView1”
    17.             android:textSize=“23sp”
    18.             android:visibility=“visible” />
    19.         <TextView
    20.             android:id=“@+id/mainTV2”
    21.             android:layout_width=“wrap_content”
    22.             android:layout_height=“wrap_content”
    23.             android:layout_weight=“1”
    24.             android:background=“#00F”
    25.             android:text=“TextView2”
    26.             android:textSize=“23sp”
    27.             android:visibility=“visible” />
    28.     </LinearLayout>
    29.     <Button
    30.         android:id=“@+id/mainBtn1”
    31.         android:layout_width=“fill_parent”
    32.         android:layout_height=“wrap_content”
    33.         android:text=“TextView2为VISIBLE”
    34.         android:onClick=“mianOnClickListener”/>
    35.     <Button
    36.         android:id=“@+id/mainBtn2”
    37.         android:layout_width=“fill_parent”
    38.         android:layout_height=“wrap_content”
    39.         android:text=“TextView2为INVISIBLE”
    40.         android:onClick=“mianOnClickListener”/>
    41.     <Button
    42.         android:id=“@+id/mainBtn3”
    43.         android:layout_width=“fill_parent”
    44.         android:layout_height=“wrap_content”
    45.         android:text=“TextView2为GONE”
    46.         android:onClick=“mianOnClickListener”/>
    47. </LinearLayout>

    后面三个Button只要是控制TextView的visibility的属性

    Java代码:

    1. package com.chindroid.visibility;
    2. import android.app.Activity;
    3. import android.os.Bundle;
    4. import android.view.View;
    5. import android.widget.TextView;
    6. public class MainActivity extends Activity {
    7.     /** TextView2 */
    8.     private TextView mainTV2 = null;
    9.     @Override
    10.     public void onCreate(Bundle savedInstanceState) {
    11.         super.onCreate(savedInstanceState);
    12.         setContentView(R.layout.main);
    13.         //初始化数据
    14.         initData();
    15.     }
    16.     /** 初始化控件的方法 */
    17.     private void initData() {
    18.         mainTV2 = (TextView)findViewById(R.id.mainTV2);
    19.     }
    20.     /**
    21.      * MainActivity中响应按钮点击事件的方法
    22.      * 
    23.      * @param v
    24.      */
    25.     public void mianOnClickListener(View v){
    26.         switch (v.getId()){
    27.             case R.id.mainBtn1:{    //按钮1的响应事件
    28.                 //设置TextView2可见
    29.                 mainTV2.setVisibility(View.VISIBLE);
    30.                 break;
    31.             }
    32.             case R.id.mainBtn2:{    //按钮2的响应事件
    33.                 //设置TextView2不可见
    34.                 mainTV2.setVisibility(View.INVISIBLE);
    35.                 break;
    36.             }
    37.             case R.id.mainBtn3:{    //按钮3的响应事件
    38.                 //设置TextView2隐藏
    39.                 mainTV2.setVisibility(View.GONE);
    40.                 break;
    41.             }
    42.             default:
    43.                 break;
    44.         }
    45.     }
    46. }

    由于程序一启动两个TextView都是可见的

    当我们点击第1个按钮,把TextView2visibility属性设置为INVISIBLE时,程序如下如下图所示:

    当我们点击第3个按钮,把TextView2visibility属性设置为GONE时,程序如下如下图所示:

    当我们再点击第1个按钮,把TextView2visibility属性设置为VISIBLE时,TextView2又呈现出来了,如下图所示:

     

    由上面的演示可知

    VISIBLE:设置控件可见

    INVISIBLE:设置控件不可见

    GONE:设置控件隐藏

     

    而INVISIBLE和GONE的主要区别是:当控件visibility属性为INVISIBLE时,界面保留了view控件所占有的空间;而控件属性为GONE时,界面则不保留view控件所占有的空间。

     

  • Java条件编译

    http://www.mamicode.com/info-detail-650763.html

     

    学习过C语言或者C++语言的同学都知道它们支持条件编译,那么今天我们来学习下在Java语言中如何实现条件编译。Java语言本身没有提供条件编译,但是Java编译器对.java文件编译为.class文件做了优化,下面通过一个例子给大家详细讲解。

    下面先给出HelloWorld.java文件:

     1 package com.test;
     2 
     3 /**
     4  * Test Demo
     5  */
     6 public class HelloWorld {
     7 
     8     public static void main(String[] args) {
     9         if (BuildConfig.FLAG) {
    10             System.out.println("Hello World");
    11         } else {
    12             System.out.println("Java条件编译测试");
    13         }
    14     }
    15 
    16 }

    再来看看BuildConfig.java文件:

    package com.test;
    
    /**
     * Created by Administrator on 2015/5/24.
     */
    public final class BuildConfig {
    
        public static final boolean FLAG = false;
    }

     

    再来看看该.java文件被转化为.class文件的内容:

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package com.test;
    
    public class HelloWorld {
        public HelloWorld() {
        }
    
        public static void main(String[] args) {
            System.out.println("Java条件编译测试");
        }
    }

    可以知道的是BuildConfig.FLAG永远都为false,if块内的代码当然也不会被执行,这部分代码就不会被编译到.class文件中。

    如果FLAG是字符串会怎么样?字符串之间如果使用equals进行比较,在转化为.class文件时不会得到优化。

    HelloWorld.java文件:

    package com.test;
    
    /**
     * Test Demo
     */
    public class HelloWorld {
    
        public static void main(String[] args) {
            if (BuildConfig.FLAG.equals("false")) {
                System.out.println("Hello World");
            } else {
                System.out.println("Java条件编译测试");
            }
        }
    
    }

    HelloWorld.class文件:

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package com.test;
    
    public class HelloWorld {
        public HelloWorld() {
        }
    
        public static void main(String[] args) {
            if("false".equals("false")) {
                System.out.println("Hello World");
            } else {
                System.out.println("Java条件编译测试");
            }
    
        }
    }

    如果真的需要字符串比较,实现条件编译的话可以使用 “==”。

    HelloWorld.java文件:

    package com.test;
    
    /**
     * Test Demo
     */
    public class HelloWorld {
    
        public static void main(String[] args) {
            if (BuildConfig.FLAG == "false") {
                System.out.println("Hello World");
            } else {
                System.out.println("Java条件编译测试");
            }
        }
    
    }

    HelloWorld.class文件:

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package com.test;
    
    public class HelloWorld {
        public HelloWorld() {
        }
    
        public static void main(String[] args) {
            System.out.println("Hello World");
        }
    }

     

  • Handler and Activity’s life cycle, take care about orphan threads!!

    http://android2ee.blogspot.com/2011/11/handler-and-activity-life-cycle-take.html

    Handler and Activity’s life cycle, take care about orphan threads!!

    Hello,

    You have an Activity which uses a Handler. You create your handler and overwrite the handleMessage method, you launch the handler’s thread and that’s it for the handler management… Most of us do such a thing and it’s a huge mistake!!! What happens to your thread when your activity pauses and resumes and worst when it dies and (re)creates?
    You thread becomes an orphan thread !
    So you have written something like that :

    (BAD CODE EXAMPLE DO NOT USE)

    /**

    * The handler

    */

    private final Handler slowDownDrawingHandler;

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

    // handler definition

    slowDownDrawingHandler = new Handler() {

    /** (non-Javadoc)*/

    @Override

    public void handleMessage(Message msg) {

    super.handleMessage(msg);

    redraw();

    }

    };

    // Launching the Thread to update draw

    Thread background = new Thread(new Runnable() {

    /**

    * The message exchanged between this thread and the handler

    */

    Message myMessage;

    // Overriden Run method

    public void run() {

    try {

    while (true) {

    // Sleep

    Thread.sleep(100);

    // Do something

    myMessage = slowDownDrawingHandler.obtainMessage();

    // then send the message

    slowDownDrawingHandler.sendMessage(myMessage);

    }

    }

    } catch (Throwable t) {

    // just end the background thread

    }

    }

    });

    // start the thread

    background.start();

    Using such a code, when your activity pauses or dies your thread is still alive and become an orphan thread. Nothing can stop it, neither inter-acts with it and it continues to run. This is a big fail.

    What is the right way to do it: You have to manage your thread state according to your activity state. In other words, when your activity pauses, you have to pauses your thread, when it resumes you have to resume your thread, when your activity dies, you thread must die….

    A simple way to do that is to use two atomic Booleans (synchronized boolean), isPausing and isStopping, change their value in the onResume, onPause, onCreate and onDestroy methods of your activity and use that boolean to pause or stop your thread.

    So the right code should look like that:
    Good Code Example CAN BE USED

    /** * The handler  */

    private final Handler slowDownDrawingHandler;

    /** * An atomic boolean to manage the external thread’s destruction */

    AtomicBoolean isRunning = new AtomicBoolean(false);

    /** * An atomic boolean to manage the external thread’s destruction */

    AtomicBoolean isPausing = new AtomicBoolean(false);

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

    // handler definition

    slowDownDrawingHandler = new Handler() {

    @Override

    public void handleMessage(Message msg) {

    super.handleMessage(msg);

    redraw();

    }

    };

    // Launching the Thread to update draw

    Thread background = new Thread(new Runnable() {

    /**

    * The message exchanged between this thread and the handler

    */

    Message myMessage;

    // Overriden Run method

    public void run() {

    try {

    while (isRunning.get()) {

    if(isPausing.get()) {

    Thread.sleep(2000);

    }else {

    // Sleep

    Thread.sleep(100);

    // Do something

    myMessage = slowDownDrawingHandler.obtainMessage();

    // then send the message

    slowDownDrawingHandler.sendMessage(myMessage);

    }

    }

    }

    } catch (Throwable t) {

    // just end the background thread

    }

    }

    });

    // Initialize the threadSafe booleans

    isRunning.set(true);

    isPausing.set(false);

    background.start();

    }

    /*(non-Javadoc) */

    @Override

    protected void onPause() {

    //and don’t forget to stop the thread

    isPausing.set(true);

    super.onPause();

    }

    /*(non-Javadoc) */

    @Override

    protected void onResume() {

    //and don’t forget to relaunch the thread

    isPausing.set(false);

    super.onResume();

    }

    /*(non-Javadoc) */

    @Override

    protected void onDestroy() {

    //and don’t forget to kill the thread

    isRunning.set(false);

    super.onDestroy();

    }
    So, Thanks who?
    Thanks, Android2ee, the Android Programming Ebooks :o)

    Mathias Séguy
    mathias.seguy.it@gmail.com
    Auteur Android2EE
    Ebooks to learn Android Programming.

    Retrouvez moi sur Google+
    Suivez moi sur Twitter
    Rejoignez mon réseau LinkedIn ou Viadeo

  • Android Activity Launch Mode

    Activity的launchMode:singleTop,singleTask与singleInstance

     

    相关内容,可以参见官方网址:http://developer.android.com/guide/components/tasks-and-back-stack.html

    如图所示,如果ABC三个Activity的launchMode都是standard,那么按照图示顺序调用后,堆栈为ABCBB;
    而如果界面ActivityB的launchMode为singleTop,同样的调用关系下,堆栈为ABCB,栈顶的B,被复用了。

    singleTop模式,适合于与用户交互时保持信心更新的界面Activity,比如联系人的搜索界面界面等;

    singleTop仅作为栈顶Activity时才可能被复用,同一个Activity在系统中,还是会存在多个的现象。
    singleTasksingleInstance,在整个系统中,仅会有一个对象存在,以节省内存开销。
    如果运行模式不是默认的standard模式,那么,该Activity需要重载onNewIntent的函数。
    standard和singleTop,对它的调用,不会引起任务切换;而singleTask和singleInstance,则相反。
    换句话说,而singleTask和singleInstance,其Activity的对象,仅可作为任务的根Activity而存在,
    而standard和singleTop,其Activity的对象,则可能存在Activity堆栈的任何位置。

    如图所示,当B的运行模式为singleTask和singleInstance时,所有对B的调用,
    都会跳转到以B为根的任务中进行,而与调用Activity所在的任务,毫无关联。

    singleTask和singleInstance唯一的区别是:
    singleInstance,其所在的任务中,包含且只包含一个该Activity的对象,不会再有其他的Activity对象;
    而singleTask,其任务中,则可能包含多个其他相关的Activity对象。

    singleTask和singleInstance适用于消耗内存较多的单实例界面,比如浏览器和音乐播放器等。

    摘自《Android开发精要》

  • dnstap

    http://dnstap.info/slides/dnstap_nanog61.pdf

     

    dnstap

     –  What  is  it?

    • High  speed  DNS  logging  without  packet  capture
    • Encoding  uses  Protocol  Buffers
    • Binary  clean
    • Efficient  encoding
    • Extendable
    • Implementa6ons  available  for  many  programming