Android抽象布局——include、merge 、ViewStub

在布局优化中,Android的官方提到了这三种布局,并介绍了这三种布局各有的优势,下面也是简单说一下他们的优势,以及怎么使用,记下来权当做笔记。

1、布局重用
标签能够重用布局文件,简单的使用如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" 
    android:layout_width=”match_parent”
    android:layout_height=”match_parent”
    android:background="@color/app_bg"
    android:gravity="center_horizontal">

    <include layout="@layout/titlebar"/>

    <TextView android:layout_width=”match_parent”
              android:layout_height="wrap_content"
              android:text="@string/hello"
              android:padding="10dp" />

    ...

</LinearLayout>

1)标签可以使用单独的layout属性,这个也是必须使用的。

2)可以使用其他属性。标签若指定了ID属性,而你的layout也定义了ID,则你的layout的ID会被覆盖。
3)在include标签中所有的android:layout_*都是有效的,前提是必须要写layout_width和layout_height两个属性。
4)布局中可以包含两个相同的include标签,引用时可以使用如下方法解决(参考):

View bookmarks_container_2 = findViewById(R.id.bookmarks_favourite);
bookmarks_container_2.findViewById(R.id.bookmarks_list);

2、减少视图层级

标签在UI的结构优化中起着非常重要的作用,它可以删减多余的层级,优化UI。多用于替换FrameLayout或者当一个布局包含另一个时,标签消除视图层次结构中多余的视图组。例如你的主布局文件是垂直布局,引入了一个垂直布局的include,这是如果include布局使用的LinearLayout就没意义了,使用的话反而减慢你的UI表现。这时可以使用标签优化。

<merge xmlns:android="http://schemas.android.com/apk/res/android">

    <Button
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="@string/add"/>

    <Button
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="@string/delete"/>

</merge>

现在,当你添加该布局文件时(使用标签),系统忽略节点并且直接添加两个Button。更多介绍可以参考《Android Layout Tricks #3: Optimize by merging

3、需要时使用
标签最大的优点是当你需要时才会加载,使用他并不会影响UI初始化时的性能。各种不常用的布局想进度条、显示错误消息等可以使用标签,以减少内存使用量,加快渲染速度。是一个不可见的,大小为0的View。标签使用如下:

<ViewStub
    android:id="@+id/stub_import"
    android:inflatedId="@+id/panel_import"
    android:layout="@layout/progress_overlay"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom" />

当你想加载布局时,可以使用下面其中一种方法:

((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
// or
View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();

当调用inflate()函数的时候,ViewStub被引用的资源替代,并且返回引用的view。 这样程序可以直接得到引用的view而不用再次调用函数findViewById()来查找了。
注:ViewStub目前有个缺陷就是还不支持 标签。

更多标签介绍可以参考《Android Layout Tricks #3: Optimize with stubs

转自 http://blog.csdn.net/xyz_lmn/article/details/14524567

Android 背景图片平铺

一般布局设置的背景图都是做拉伸处理,有时候我们需要背景图片做平铺处理,类似于网页开发中CSS的repeat。
在Android中可以使用如下方法使背景图片平铺。在drawable目录下创建一个repeat_bg.xml:

<?xml version="1.0" encoding="utf-8"?>  
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"   
    android:src="@drawable/bg"
    android:tileMode="repeat" />

然后在布局的xml文件中可以这样引用:

<LinearLayout 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:background="@drawable/repeat_bg"> 
</LinearLayout>

使用Eclipse通过WiFi调试Android程序

通过如下步骤,可以很方便的通过wifi调试Android程序:

1、root手机;

2、到市场下载Android Terminal Emulator应用并安装(Android Terminal Emulator是一款安卓手机上使用的终端模拟器,可以进行linux命令集),或者到从GitHub 下载源代码自己编译,地址为 https://github.com/jackpal/Android-Terminal-Emulator,源代码编译的时候注意要增加NDK支持,底层是需要 C/C++层支持的。

3、安装后打开,输入如下命令:

su //获取超级用户权限

setprop service.adb.tcp.port 5555  //设置监听的端口,端口可以自定义,如5554,5555是默认的

stop adbd  //关闭adbd

start adbd  //重新启动adbd

4、看一下手机的IP,并记下来,比如:192.168.1.111;

5、在电脑上,上运行cmd命令提示符,切换目录至adb文件所对应文件夹,如:D:\Android\android-sdk\platform-tools,键入如下命令:

adb connect 192.168.1.111:5555

如果提示连接成功,则说明搞定了。

6、在Eclipse中运行调试应用

Proguard不混淆内部匿名类(keep Inner Anonymous Class)

今天在使用Proguard keep一个 静态内部类的时候,混淆完之后一直找不到那个静态内部类,内心抓狂啊。

最后在stackoverflow上找到了答案:

-keepattributes Exceptions,InnerClasses,...
-keep class [packagename].A{
    *;
}
-keep class [packagename].A$* {
    *;
}

其中 A$* 表示所有A的内部类都保留下来,也可以如下使用:

-keepattributes Exceptions,InnerClasses,...
-keep class com.xxx.A{ *; }
-keep class com.xxx.A$B { *; }
-keep class com.xxx.A$C { *; }

这样可以根据需要只保留A的某一个内部类

以下是proguard文件一部分

#-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
-keepattributes Exceptions,InnerClasses,...
-keep class com.yulore.reverselookup.api.YuloreWindowConfiguration{ *; }
-keep class com.yulore.reverselookup.api.YuloreWindowConfiguration$Builder{ *; }

原文 http://blog.csdn.net/fx_sky/article/details/18225501

Mac Gradle 编译报告Failure initializing default system SSL context

Mac 10.9 版本下使用Gradle 编译 Android 项目,报告错误

Failure initializing default system SSL context

使用 -debug 参数,得到的详细输出如下

2:34:15.273 [ERROR] [org.gradle.BuildExceptionReporter]     at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:50)
22:34:15.278 [ERROR] [org.gradle.BuildExceptionReporter]     at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:32)
22:34:15.279 [ERROR] [org.gradle.BuildExceptionReporter]     at org.gradle.launcher.GradleMain.main(GradleMain.java:26)
22:34:15.281 [ERROR] [org.gradle.BuildExceptionReporter] Caused by: java.io.FileNotFoundException: /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home/lib/security/cacerts (No such file or directory)
22:34:15.284 [ERROR] [org.gradle.BuildExceptionReporter]     at java.io.FileInputStream.open(Native Method)
22:34:15.285 [ERROR] [org.gradle.BuildExceptionReporter]     at java.io.FileInputStream.<init>(FileInputStream.java:106)
22:34:15.286 [ERROR] [org.gradle.BuildExceptionReporter]     at org.apache.http.conn.ssl.SSLSocketFactory.createSystemSSLContext(SSLSocketFactory.java:299)
22:34:15.288 [ERROR] [org.gradle.BuildExceptionReporter]     at org.apache.http.conn.ssl.SSLSocketFactory.createSystemSSLContext(SSLSocketFactory.java:366)
22:34:15.289 [ERROR] [org.gradle.BuildExceptionReporter]     ... 147 more

可以看到,异常信息为

22:34:15.281 [ERROR] [org.gradle.BuildExceptionReporter] Caused by: java.io.FileNotFoundException: /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home/lib/security/cacerts (No such file or directory)

到具体的目录下面去看,这个文件果然是不存在的,有些版本链接到了一个不存在的目录,这种情况一般是经历过系统升级,往往会造成这个现象,另外,就是系统安装的Java 是Apple 提供的 Java 版本,而不是 Orcale 官网下载的独立版本。

解决方法是可以到Orcale 官网下载最新版本的 Java ,安装替换即可解决问题。

使用 Homebrew 安装指定版本的软件

在命令行下使用

$ brew install FORMULANAME

就可以安装 FORMULANAME 对应的工具,它会处理好依赖关系,非常方便。默认情况下,安装最新版本。但是现在在使用 Gradle 的时候,最新版本的 Gradle 是1.10,但是编译Android 的项目失败,只能降级成 1.9 版本的才行,解决方法如下

1.查看 brew 支持哪些版本的 gradle

$ sudo brew versions gradle
Warning: brew-versions is unsupported and may be removed soon.
Please use the homebrew-versions tap instead:
  https://github.com/Homebrew/homebrew-versions
1.10     git checkout 2b10422 Library/Formula/gradle.rb
1.9      git checkout 5bab5e9 Library/Formula/gradle.rb
1.8      git checkout 9214e60 Library/Formula/gradle.rb
1.7      git checkout f826cc9 Library/Formula/gradle.rb
1.6      git checkout fff7c0b Library/Formula/gradle.rb
1.5      git checkout 57931e0 Library/Formula/gradle.rb
1.4      git checkout 0b7303a Library/Formula/gradle.rb
1.3      git checkout c259bda Library/Formula/gradle.rb
1.2      git checkout 9b7d294 Library/Formula/gradle.rb
1.1      git checkout 7941972 Library/Formula/gradle.rb
1.0      git checkout dff67fb Library/Formula/gradle.rb
1.0-rc-3 git checkout 5f9e348 Library/Formula/gradle.rb
1.0-rc-2 git checkout f72e33f Library/Formula/gradle.rb
1.0-rc-1 git checkout e2438cf Library/Formula/gradle.rb
1.0-milestone-9 git checkout c27c667 Library/Formula/gradle.rb
1.0-milestone-8a git checkout 69eb948 Library/Formula/gradle.rb
1.0-milestone-8 git checkout 34da975 Library/Formula/gradle.rb
1.0-milestone-7 git checkout 6a8c437 Library/Formula/gradle.rb
1.0-milestone-6 git checkout dae625d Library/Formula/gradle.rb
1.0-milestone-5 git checkout baff305 Library/Formula/gradle.rb
1.0-milestone-3 git checkout d9f2e06 Library/Formula/gradle.rb
1.0-milestone-4 git checkout 4b1230c Library/Formula/gradle.rb
1.0-milestone-2 git checkout 6801464 Library/Formula/gradle.rb
1.0-milestone-1 git checkout 0476235 Library/Formula/gradle.rb
0.9.2    git checkout 38b9338 Library/Formula/gradle.rb
0.9.1    git checkout f986d7d Library/Formula/gradle.rb
0.9      git checkout 45e09d7 Library/Formula/gradle.rb
0.8      git checkout e6f608f Library/Formula/gradle.rb

可以看到,支持 1.9 版本的。

2. 进入 brew 所在的git仓库

$ cd `brew --prefix`

3.复制粘贴刚才 brew versions gradle 命令的提示,我们需要1.9 版本的,因此执行

$ git checkout 5bab5e9 Library/Formula/gradle.rb

此时,本地仓库中的gradle 就被替换成了 1.9 的链接地址信息。

4. 安装

$ sudo brew install gradle
==> Downloading http://services.gradle.org/distributions/gradle-1.9-bin.zip

可以看到输出的信息已经是 1.9 的版本了。

java.lang.ClassNotFoundException:org.gradle.api.artifacts.result.ResolvedModuleVersionResult

使用 Gradle 升级到 1.10 版本,编译 Android 项目的时候报告类似如下的异常信息

15:35:52.069 [ERROR] [org.gradle.BuildExceptionReporter] Caused by: java.lang.NoClassDefFoundError: org/gradle/api/artifacts/result/ResolvedModuleVersionResult
15:35:52.073 [ERROR] [org.gradle.BuildExceptionReporter]    at com.android.build.gradle.AppPlugin.$getStaticMetaClass(AppPlugin.groovy)
15:35:52.077 [ERROR] [org.gradle.BuildExceptionReporter]    at com.android.build.gradle.BasePlugin.<init>(BasePlugin.groovy:1627)
15:35:52.101 [ERROR] [org.gradle.BuildExceptionReporter]    at com.android.build.gradle.AppPlugin.<init>(AppPlugin.groovy:73)
15:35:52.105 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.internal.DependencyInjectingInstantiator.newInstance(DependencyInjectingInstantiator.java:62)
15:35:52.123 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.internal.plugins.DefaultPluginRegistry.loadPlugin(DefaultPluginRegistry.java:67)
15:35:52.132 [ERROR] [org.gradle.BuildExceptionReporter]    ... 43 more
15:35:52.135 [ERROR] [org.gradle.BuildExceptionReporter] Caused by: java.lang.ClassNotFoundException: org.gradle.api.artifacts.result.ResolvedModuleVersionResult
15:35:52.157 [ERROR] [org.gradle.BuildExceptionReporter]    ... 48 more

搜索了一下,找到答案如下

请注意 ResolvedModuleVersionResult 是丢失在这里
http://www.gradle.org/docs/1.10/javadoc/org/gradle/api/artifacts/result/package-summary.html
但这里存在
http://www.gradle.org/docs/1.9/javadoc/org/gradle/api/artifacts/result/package-summary.html
所以降级到 1.9 就可以了

也就是说Gradle 1.9 以上的版本编译 Android 代码目前是存在问题的。

Linux下NDK:error trying to exec 'cc1': execvp: No such file or directory

android-ndk-r9c 下编译时候报告

error trying to exec 'cc1': execvp: No such file or directory

修改

CC="$NDK_ROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/arm-linux-androideabi/bin/gcc"

CC="$NDK_ROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc"

即可。

Ubuntu 中,有时候编译器安装的太多版本的情况下,如果只设置PATH 到 toolchains 目录,CC只写编译器名字,让系统根据PATH中的路径来自动寻找,有时候是无效的,此时需要直接指定CC的绝对路径就可以了。

参考链接

http://www.cnblogs.com/pengwang/archive/2013/03/06/2945720.html

arm-eabi-gcc: error trying to exec 'cc1': execvp: No such file or directory arm-eabi-gcc: error trying to exec 'cc1': execvp: No such file or directory

在使用ndk编译本地文件时出错,最后发现是交叉编译工具的权限问题,chmod +x 就可以了我的NDK版本是android-ndk-r5b,CC1在android-ndk-r5b/toolchains/arm- linux-androideabi-4.4.3/prebuilt/linux-x86/libexec/gcc/arm-linux- androideabi/4.4.3目录下面。

Mac OS X 10.9 Android NDK r9c 编译 FFTW 3.3.3

在Mac OS X 10.9 上使用 NDK  r9c 编译 FFTW 3.3.3

1.下载FFTW源代码

2.建立一个Android 工程,并且添加 NDK 支持

3.解压缩FFTW的源代码到刚刚建立的Android 目录下面 文件夹名字为 fftw-3.3.3

4.建立编译脚本 build.sh 并在命令行下执行

#!/bin/sh
# build.sh
# Compiles fftw3 for Android
# Make sure you have NDK_ROOT defined in .bashrc or .bash_profile

INSTALL_DIR="`pwd`/jni/fftw3"
SRC_DIR="`pwd`/fftw-3.3.3"

cd $SRC_DIR

export
PATH="$NDK_ROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64/bin/:$PATH"
export SYS_ROOT="$NDK_ROOT/platforms/android-8/arch-arm/"
export CC="arm-linux-androideabi-gcc --sysroot=$SYS_ROOT"
export LD="arm-linux-androideabi-ld"
export AR="arm-linux-androideabi-ar"
export RANLIB="arm-linux-androideabi-ranlib"
export STRIP="arm-linux-androideabi-strip"

mkdir -p $INSTALL_DIR
./configure --host=arm-eabi  --prefix=$INSTALL_DIR LIBS="-lc -lgcc" --enable-float

make
make install

exit 0
  • INSTALL_DIR tells make to install the compiled library in our project's jni directory
  • PATH tells make to look for our tool chain in the NDK directory. Note that you might have to change this value - explore your NDK directory to make sure that the path exists
  • SYS_ROOT tells make where to look for system libraries and header files
  • ./configure --host=arm-eabi  tells make that we are cross-compiling a ARM architecture.

5.修改Android.mk 文件

# jni/Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := fftw3

LOCAL_SRC_FILES := fftw3/lib/libfftw3.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/fftw3/include

include $(PREBUILT_STATIC_LIBRARY)

华为Android手机在MAC系统下ADB识别

使用MACOS发现在Android开发环境完整的情况下,接入小米,SAMSUNG,HTC,ZTE等手机都可以自动识别,如果暂时不能识别,只需要在 adb_usb.ini 中设置之后也可以识别,并可以在DDMS中查看LOGCAT,唯独华为的手机不可识别。USB开发调试也设置了,但是在Windows下却可以识别,为什么呢?别急,有工程模式:

在拨号界面输入:

*#*#2846579#*#*

找到->"ProjectMenu"->“后台设置”->“USB端口设置” 改成 "GOOGLE模式"

注意,此时手机提示要重启,但是不要重启。重启之后会还原为正常模式的。

如果还是不能识别,则切换成其他模式,反复切换一下,最后设置成"GOOGLE模式" ,或者重新插拔一下数据线,就可以识别到了。