第一篇:Android源码编译整理总结
1.必要的软件环境
sudo apt-get install build-essential sudo apt-get install make sudo apt-get install gcc sudo apt-get install g++ sudo apt-get install libc6-dev sudo apt-get install patch sudo apt-get install texinfo sudo apt-get install libncurses-dev sudo apt-get install git-core gnupg sudo apt-get install flex bison gperf libsdl-dev libesd0-dev libwxgtk2.6-dev build-essential zip curl sudo apt-get install ncurses-dev sudo apt-get install zlib1g-dev sudo apt-get install valgrind sudo apt-get install python2.5
笔者发现这里已经比较全来,不过还有一些应该是linux系统自带的,如果缺少就按照提示install一下
安装java环境,这里有必要说一下,大家装环境的时候很多人会一起装,不过笔者建议java和其他的分开,因为装java很可能会失败,从而导致其他的也fail sudo apt-get install sun-java6-jdk
这里就说到上面说很多人会安装java失败的问题,笔者也是从网上找的解决办法现在一起整理出来:
ubuntu10.04 lucid 去掉了sun-java6-jre,sun-java6-jdk的源,所以如果是直接apt-get install 提示是
现在没有可用的软件包 sun-java6-jdk,但是它被其它的软件包引用了。
这可能意味着这个缺失的软件包可能已被废弃,或者只能在其他发布源中找到
E: 软件包 sun-java6-jdk 还没有可供安装的候选者
解决办法(选择一个即可):
1、系统->系统管理->软件源->“其它软件”下添加一个 deb http://archive.canonical.com/ lucid partner
之后,再执行apt-get install 如果是下载java5就添加deb http://us.archive.ubuntu.com/ubuntu/ jaunty multiverse”
2、自己从sun网站下载相应的Jre,JDK安装即可
3、从新立德软件管理器中search openJDK,用openJDK代替
注: 官方文档说如果用sun-java6-jdk可出问题,得要用sun-java5-jdk。经测试发现,如果仅仅make(make不包括make sdk),用sun-java6-jdk是没有问题的。而make sdk,就会有问题,严格来说是在make doc出问题,它需要的javadoc版本为1.5。
因此,我们安装完sun-java6-jdk后最好再安装sun-java5-jdk,或者 只安装sun-java5-jdk。这里sun-java6-jdk和sun-java5-jdk都安装,并只修改javadoc.1.gz和 javadoc。因为只有这两个是make sdk用到的。这样的话,除了javadoc工具是用1.5版本,其它均用1.6版本: sudo apt-get install sun-java5-jdk 修改javadoc的link cd /etc/alternatives sudo rm javadoc.1.gz
sudo ln-s /usr/lib/jvm/java-1.5.0-sun/man/man1/javadoc.1.gz javadoc.1.gz sudo rm javadoc sudo ln-s /usr/lib/jvm/java-1.5.0-sun/bin/javadoc javadoc
2、设置环境变量 vim ~/.bashrc 在.bashrc中新增或整合PATH变量,如下 #java 程序开发/运行的一些环境变量 JAVA_HOME=/usr/lib/jvm/java-6-sun JRE_HOME=${JAVA_HOME}/jre export ANDROID_JAVA_HOME=$JAVA_HOME export CLASSPATH=.:${JAVA_HOME}/lib:$JRE_HOME/lib:$CLASSP ATH export JAVA_PATH=${JAVA_HOME}/bin:${JRE_HOME}/bin export JAVA_HOME;export JRE_HOME;export CLASSPATH;HOME_BIN=~/bin/ export PATH=${PATH}:${JAVA_PATH}:${JRE_PATH}:${HOME_BIN};#echo $PATH;最后,同步这些变化: source ~/.bashr 3.安装repo(用来更新android源码)
创建~/bin目录,用来存放repo程序,如下: $ cd ~ $ mkdir bin 并加到环境变量PATH中,在第2步中已经加入 下载repo脚本并使其可执行:
$ curl http://android.git.kernel.org/repo >~/bin/repo $ chmod a+x ~/bin/repo 4.初始化repo
repo是android对git的一个封装,简化了一些git的操作。创建工程目录: $ mkdir android $ cd android repo初始化
$ repo init-u git://android.git.kernel.org/platform/manifest.git 这里包含了android最新的源码
在此过程中需要输入名字和email地址。初始化成功后,会显示: repo initialized in /android 在~/android下会有一个.repo的隐藏目录。
如果想拿某个branch而不是主线上的代码,我们需要用-b参数制定branch名字,比如:
repo init-u git://android.git.kernel.org/platform/manifest.git-b cupcake 这 里抓下来的分支是cupcake,网上关于编译到文章大多是针对cupcake分支,是andoird 1.5版本,但是之前我没有输入后面的参数,以致于下到的代码是主线上的代码,是android 2.1版本。两者目录结构有一些差别,导致当我按照网上的说明步骤来执行遇到错误时,不知道是版本不同的原因还是其他什么原因。因此很奇怪为什么网上的文 章都是说cupcake的,而没有怎么讲主线的源代码编译。5.同步源代码 $ repo sync 这一步要很久,要看个人的网络速度
6.编译android源码,并得到~/android/out目录 $ cd ~/andoird
$ make-j2 笔者的电脑是双核所以是-j2,以此类推8核就可以-j8 这一过程很久,主要看机器的配置
如果是cupcake,那么直接make的时候,会出现以下错误:
1.frameworks/policies/base/PolicyConfig.mk:22: *** No module defined for the given PRODUCT_POLICY(android.policy_phone).Stop.错误。
解决办法:
在build/tools/findleaves.sh中的第89行,这一句find “${@:0:$nargs}” $findargs-type f-name “$filename”-print |
改为find “${@:1:$nargs-1}” $findargs-type f-name “$filename”-print |
2.frameworks/base/tools/aidl/AST.cpp:10: error: 'fprintf' was not declared in this scope的错误
解决办法:
下载gcc-4.3和g++-4.3
apt-get install gcc-4.3 g++-4.3
因为ubuntu 9.10自带到是gcc 4.4,因此需要重新下载gcc 4.3,最后设置gcc软连接到gcc 4.3
进入/usr/bin cd /usr/bin
建个软连接
ln-s gcc-4.3 gcc
ln-s g++-4.3 g++
然后进入android目录下,执行make,就可以了。
主线代码则没有此问题 7.在模拟器上运行编译好的android
编译好android之后,emulator在~/android/out/host/linux-x86/bin 下,ramdisk.img,system.img和userdata.img则在~/android/out/target/product /generic下 $ cd ~/android/out/host/linux-x86/bin 增加环境变量 $ emacs ~/.bashrc 在.bashrc中新增环境变量,如下 #java 程序开发/运行的一些环境变量
export ANDROID_PRODUCT_OUT=~/android/out/target/product/g eneric ANDROID_PRODUCT_OUT_BIN=~/android/out/host/linux-x 86/bin export PATH=${PATH}:${ANDROID_PRODUCT_OUT_BIN}:${ANDROID_ PRODUCT_OUT};最后,同步这些变化: $ source ~/.bashrc $ cd ~/android/out/target/product/generic
$ emulator-system system.img-data userdata.img-ramdisk ramdisk.img 最后进入android桌面,就说明成功了。8.编译模块
android中的一个应用程序可以单独编译,编译后要重新生成system.img 在源码目录下执行
$.build/envsetup.sh(.后面有空格)就多出一些命令:
-croot: Changes directory to the top of the tree.mm: Builds all of the modules in the current directory.cgrep: Greps on all local C/C++ files.resgrep: Greps on all local res/*.xml files.-godir: Go to the directory containing a file.可以加—help查看用法
我们可以使用mmm来编译指定目录的模块,如编译联系人: $ mmm packages/apps/Contacts/ 编完之后生成两个文件: out/target/product/generic/data/app/ContactsTests.apk out/target/product/generic/system/app/Contacts.apk 可以使用 $ make snod 重新生成system.img,再运行模拟器 9.编译SDK
直接执行make是不包括make sdk的。make sdk用来生成SDK,这样,我们就可以用与源码同步的SDK来开发android了。
a)修改/frameworks/base/include/utils/Asset.h „UNCOMPRESS_DATA_MAX = 1 * 1024 * 1024‟ 改为 „UNCOMPRESS_DATA_MAX = 2 * 1024 * 1024‟
原因是eclipse编译工程需要大于1.3M的buffer;
这一步,笔者编译的是主线程的,在Asset.h文件里没找到上面的常量,所以就没做这一步,但是也成功了。b)编译ADT。
如果想用eclipse开发android应用程序,最好是安装ADT,这样就可以在eclipse下创建android的工程。
产生ADT eclipse plugins $ development/tools/eclipse/scripts/build_server.sh ~/adt/
使用前建议设定一下ECLIPSE_HOME的环境变量,不然会以为没有装eclipse,然后帮你download下来。
这里要非常注意,本人就曾经卡在这里,始终编译不过。一开始会提示eclipse的什么什么jar找不到,因此fail。这主要是因为我到 ECLIPSE_HOME到环境变量设置错误。我之前装的eclipse只从新力得上面抓下来的,好像找不到eclipse所在到目录是哪个,结果就设置 了一个名为eclipse的文件夹作为环境变量。因此后来直接从eclipse的官网上下了一个,以为这样就可以。结果杯具的是下到是一个eclipse Galileo,到头来还是提示eclipse什么什么文件找不到。最后实在没法,索性把eclipse删个干净,让程序自己去下eclipse,发现抓 的是eclipse ganymede。在此要郑重说明一下,自己去下的话应该下载jee的ganymade,而不能是java 的ganymade,具体原因试试就知道了。
主线代码编译ADT的时候方法相同,但是没有development/tools/eclipse这个目录,而是在/sdk/eclipse这个目录 c)执行make sdk。
注意,这里需要的javadoc版本为1.5,所以你需要在步骤1中同时安装sun-java5-jdk $ make sdk
编译很慢。编译后生成的SDK存放在out/host/linux-x86/sdk/,此目录下有android-sdk_eng.xxx_linux-x86.zip和android-sdk_eng.xxx_linux-x86目录。android-sdk_eng.xxx_linux-x86就是 SDK目录
实际上,当用mmm命令编译模块时,一样会把SDK的输出文件清除,因此,最好把android-sdk_eng.xxx_linux-x86移出来
此后的应用开发,就在该SDK上进行,所以把7)对于~/.bashrc的修改注释掉,增加如下一行:
export PATH=${PATH}:~/android/out/host/linux-x86/sdk/andr oid-sdk_eng.xxx_linux-x86/tools 注意要把xxx换成真实的路径;
同样笔者编译的是主线程,所以编译完之后,发现~/android/out/host/linux-x86/sdk/android-sdk_eng.x xx_linux-x86/目录下有2个文件夹一个是tools一个是platform-tools,然后用eclipse指向这个目录的时候会提示找不到ADB,这时候只要把platform-tools下的ADB拷贝到tools文件夹就OK了 d)关于环境变量、android工具的选择 目前的android工具有:
A、我们从网上下载的SDK,如果你下载过的话(tools下有许多android工具,lib/images下有img映像)
B、我们用make sdk编译出来的SDK(tools下也有许多android工具,lib/images下有img映像)
C、我们用make编译出来的out目录(tools下也有许多android工具,lib/images下有img映像)
那么我们应该用那些工具和img呢?
首先,我们一般不会用A选项的工具和img,因为一般来说它比较旧,也源码不同步。其次,也不会用C选项的工具和img,因为这些工具和img没有经过 SDK的归类处理,会有工具和配置找不到的情况;事实上,make sdk产生的很多工具和img,在make编译出来out目录的时候,已经编译产生了,make sdk只是做了copy而已。e)安装、配置ADT
~/adt/android-eclipse/下的文件压缩,然后从eclipse中install就行了,当然还有其他方法 10.编译linux内核映像 a)准备交叉编译工具链
android代码树中有一个prebuilt项目,包含了我们编译内核所需的交叉编译工具。b)设定环境变量 $ emacs ~/.bashrc 增加如下两行:
export PATH=$PATH:~/android/prebuilt/linux-x86/toolchain/ arm-eabi-4.4.0/bin export ARCH=arm 保存后,同步变化: $ source ~/.bashrc c)获得合适的内核源代码 $ cd ~/android 获得内核源代码仓库
$ git clone git://android.git.kernel.org/kernel/common.git kernel $ cd kernel $ git branch 显示 * android-2.6.27
说明你现在在android-2.6.27这个分支上,也是kernel/common.git的默认主分支。显示所有head分支: $ git branch-a 显示 * android-2.6.27 remotes/origin/HEAD-> origin/android-2.6.27 remotes/origin/android-2.6.25 remotes/origin/android-2.6.27 remotes/origin/android-2.6.29 remotes/origin/android-goldfish-2.6.27 remotes/origin/android-goldfish-2.6.29
我们选取最新的android-goldfish-2.6.29,其中goldfish是android的模拟器模拟的CPU。
$ git checkout-b android-goldfish-2.6.29 origin/android-goldfish-2.6.29 $ git branch 显示 android-2.6.27 * android-goldfish-2.6.29 我们已经工作在android-goldfish-2.6.29分支上了。d)设定交叉编译参数
打开kernel目录下的Makefile文件,把CROSS_COMPILE指向刚才下载的prebuilt中的arm-eabi编译器
CROSS_COMPILE ?= arm-eabi-把 LDFLAGS_BUILD_ID = $(patsubst-Wl$(comma)%,%, $(call ld-option,-Wl$(comma)build-id,))
这一行注释掉,并且添加一个空的LDFLAGS_BUILD_ID定义,如下: LDFLAGS_BUILD_ID = e)编译内核映像 $ cd ~/android/kernel $ make goldfish_defconfig $ make f)测试生成的内核映像
$ emulator-avd myavd-kernel ~/android/kernel/arch/arm/boot/zImage
第二篇:Ubuntu 11.10编译Android源码错误
Ubuntu 11.10编译Android源码错误
问题1:
frameworks/base/libs/utils/RefBase.cpp: 在成员函数
‘void android::RefBase::weakref_type::trackMe(bool, bool)’中:
frameworks/base/libs/utils/RefBase.cpp:483:67: 错误: 将
‘constandroid::RefBase::weakref_impl’作为
‘voidandroid::RefBase::weakref_impl::trackMe(bool, bool)’的‘this’实参时丢弃了类型限定[-fpermissive]
make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libutils_intermediates/RefBase.o] 错误 1 原因:Ubuntu 11.10的gcc 4.6版本太高了,android编译需要gcc 4.4
解决办法:更换gcc、g++版本4.6为4.4
sudo apt-get install gcc-4.4
sudo apt-get install g++-4.4
sudo rm-rf /usr/bin/gcc /usr/bin/g++
sudo ln-s /usr/bin/gcc-4.4 /usr/bin/gcc
sudo ln-s /usr/bin/g++-4.4 /usr/bin/g++
问题2:
g++: 错误: –fpermissive:没有那个文件或目录
make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libutils_intermediates/RefBase.o] 错误 1 解决办法:sudoapt-get install g++-4.4-multilib
经过此操作编译可顺利进行。
第三篇:android有关sensor的源码总结
android有关sensor的源码总结
虽然这篇文章写得很差,因为赶时间,所以就匆匆忙忙地写出来自己作一个笔记。但是我想对大家应该有一点帮助。
1、有关sensor在Java应用程序的编程(以注册多个传感器为例,这程序是我临时弄出来的,可能有错)
package com.sensors.acc;
import android.app.Activity;import android.os.Bundle;
import android.util.Log;import android.widget.TextView;import android.hardware.SensorManager;import android.hardware.Sensor;import android.hardware.SensorEvent;import android.hardware.SensorEventListener;
public class acc extends Activity { float x, y, z;SensorManager sensormanager = null;Sensor accSensor = null;Sensor lightSensor = null;Sensor proximitySensor = null;TextView accTextView = null;/** Called when the activity is first created.*/ @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState);setContentView(R.layout.main);sensormanager =(SensorManager)getSystemService(SENSOR_SERVICE);accSensor = sensormanager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);lightSensor = sensormanager.getDefaultSensor(Sensor.TYPE_LIGHT);proximitySensor = sensormanager.getDefaultSensor(Sensor.TYPE_PROXIMITY);accTextView =(TextView)findViewById(R.id.textview_name);}
SensorEventListener lsn = new SensorEventListener(){ public void onSensorChanged(SensorEvent e){ if(e.sensor == accSensor){ Log.d(“sensor”, “found acc sensor”);x = e.values[SensorManager.DATA_X];y = e.values[SensorManager.DATA_Y];z = e.values[SensorManager.DATA_Z];accTextView.setText(“x = ” + x + “, ny = ” + y + “, nz = ” + z);} else if(e.sensor == lightSensor){ Log.d(“sensor”, “found light sensor”);accTextView.setText(“data is ” + e.values[0]);} else if(e.sensor == proximitySensor){ Log.d(“sensor”, “found proximity sensor”);accTextView.setText(“distance is ” + e.values[0]);} }
public void onAccuracyChanged(Sensor s, int accuracy){ } };@Override protected void onResume(){ super.onResume();// register this class as a listener for the orientation and accelerometer sensors sensormanager.registerListener(lsn, accSensor, SensorManager.SENSOR_DELAY_NORMAL);sensormanager.registerListener(lsn, lightSensor, SensorManager.SENSOR_DELAY_NORMAL);sensormanager.registerListener(lsn, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL);// sensormanager.unregisterListener(lsn);} @Override protected void onStop(){ // unregister listener sensormanager.unregisterListener(lsn, accSensor);sensormanager.unregisterListener(lsn, lightSensor);sensormanager.unregisterListener(lsn, proximitySensor);super.onStop();} }
在onCreate()函数中,调用getSystemService(SENSOR_SERVICE)初始化一个SensorManager实例,为什么要用getSystemService函数,而不直接用new SensorManager呢?我们看此函数的实现,在ApplicationContext.java中,if(SENSOR_SERVICE.equals(name)){ return getSensorManager();然后getSensorManager()的实现
private SensorManager getSensorManager(){ synchronized(mSync){ if(mSensorManager == null){ mSensorManager = new SensorManager(mMainThread.getHandler().getLooper());} } return mSensorManager;} 看到没有?初始化SensorManager的时候需要mMainThread.getHandler().getLooper()这个参数,之个应该是用来传递消息用的,在SensorManager类的构造函数中会把此参数传给类成员mMainLooper。如果用new SensorManager()就需要另外获取mainLooper参数传递进去。
2、在android中跟sensor有关的一些文件有SensorManager.java,位于frameworksbasecorejavaandroidhardware目录下,SensorService.java,位于frameworksbaseservicesjavacomandroidserver目录下,android_hardware_SensorManager.cpp,位于frameworksbasecorejni目录下,与SensorManager.java相对应,com_android_server_SensorService.cpp,在frameworksbaseservicesjni目录下,与SensorService.java相对应。还有SystemServer.java文件,HardwareLibhardwareIncludeHardware目录下的Sensor.h头文件。另外我们需要根据Sensor.h实现自己的一个源文件,一般取名为sensors_xxx.c或者sensors_xxx.cpp。
3、SensorManager类分析 有几个函数比较重要,必须清晰理解它们的实现,才能了解整个传感器系统的实现。从而更好地去实现硬件抽象层的实现。几个比较重要的函数有构造函数SensorManager(), registerListener()和unregisterListener(),其中registerListener()和unregisterListener()有多个,标志为 @Deprecated的是过时的,就不要看了。(1)构造函数SensorManager(Looper mainLooper)这个函数首先获取得传感器系统服务,并赋给类成员mSensorService,mSensorService = ISensorService.Stub.asInterface(ServiceManager.getService(Context.SENSOR_SERVICE));这里我要说一句,就是关于这个传感器系统服务,很多书上都说用getSystemService()是获得传感器的系统服务,而它返回的是SensorManager类型,所以以为整个系统都是使用同一个SensorManager类的实例,以为我们在任何地方使用的SensorManager实例都是同一个,它们的公共成员是共享的。但是经过这两天的分析,这种说法是错误的。其实每次调用getSystemService()函数时都初始化一个新的SensorManager实例,而这个SensorManager实例会在构造函数里通过取得传感器系统服务SensorService来实现对下层传感器的一些控制。而这个SensorService才是系统的传感器服务,说服务,不如说它只是SensorService类的一个实例罢了。它只在系统初始化时初始化一次。Android中的系统服务机制应该跟传感器的都差不多一个样,都是由不同的Manager调用下层相同的Service。你可以列举其它的Manager。那它是什么时候初始化呢?它是系统初始化在SystemServer进程里创建的,SystemServer是一个管理很多系统服务的进程,我们转到SystemServer.的main函数里,可以看到一直到调用int2()函数,它会创建一个ServerThread,最终调用AdbSettingsObserver类的run()函数,在run()函数里有这么有一句
// Sensor Service is needed by Window Manager, so this goes first Log.i(TAG, “Sensor Service”);ServiceManager.addService(Context.SENSOR_SERVICE, new SensorService(context));这里就创建SensorService实例了。在创建这个实例时会在SensorService构造函数中调用jni函数 public SensorService(Context context){ if(localLOGV)Log.d(TAG, “SensorService startup”);_sensors_control_init();} 我们看_sensors_control_init();对应的为 static jint android_init(JNIEnv *env, jclass clazz){ sensors_module_t* module;if(hw_get_module(SENSORS_HARDWARE_MODULE_ID,(const hw_module_t**)&module)== 0){ if(sensors_control_open(&module->common, &sSensorDevice)== 0){ const struct sensor_t* list;int count = module->get_sensors_list(module, &list);return count;} } return 0;} 它主要调用了sensor.h中的sensors_control_open()static inline int sensors_control_open(const struct hw_module_t* module, struct sensors_control_device_t** device){ return module->methods->open(module, SENSORS_HARDWARE_CONTROL,(struct hw_device_t**)device);} 之后在系统任何地方使用的都是这个SensorService实例。最后run()函数调用Looper.loop();就进行消息循环等待了,这就是SystemServer进程的消息服务了。这才真正叫做系统服务嘛。
我们继续看SensorManager类的构造函数,取得SensorService后,nativeClassInit();这是一个jni函数,SensorManager类调用的jni函数都在com_android_server_SensorService.cpp里,我们看这函数 static void nativeClassInit(JNIEnv *_env, jclass _this){ jclass sensorClass = _env->FindClass(“android/hardware/Sensor”);SensorOffsets& sensorOffsets = gSensorOffsets;sensorOffsets.name = _env->GetFieldID(sensorClass, “mName”, “Ljava/lang/String;”);sensorOffsets.vendor = _env->GetFieldID(sensorClass, “mVendor”, “Ljava/lang/String;”);sensorOffsets.version = _env->GetFieldID(sensorClass, “mVersion”, “I”);sensorOffsets.handle = _env->GetFieldID(sensorClass, “mHandle”, “I”);sensorOffsets.type = _env->GetFieldID(sensorClass, “mType”, “I”);sensorOffsets.range = _env->GetFieldID(sensorClass, “mMaxRange”, “F”);sensorOffsets.resolution = _env->GetFieldID(sensorClass, “mResolution”,“F”);sensorOffsets.power = _env->GetFieldID(sensorClass, “mPower”, “F”);} 这个函数只是获取和设置一些信息吧,我们不关心。接着 sensors_module_init();我们看这函数 static jint sensors_module_init(JNIEnv *env, jclass clazz){ int err = 0;sensors_module_t const* module;err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,(const hw_module_t **)&module);if(err == 0)sSensorModule =(sensors_module_t*)module;return err;} 它获取了sensor的模块信息,并把它赋给sSensorModule全局变量,之后传的modules参数都为这个。接着在构造函数里
final ArrayList fullList = sFullSensorsList;int i = 0;do { Sensor sensor = new Sensor();i = sensors_module_get_next_sensor(sensor, i);
if(i>=0){ Log.d(TAG, “found sensor: ” + sensor.getName()+ “, handle=” + sensor.getHandle());sensor.setLegacyType(getLegacySensorType(sensor.getType()));fullList.add(sensor);sHandleToSensor.append(sensor.getHandle(), sensor);} } while(i>0);这里主要是通过jni函数sensors_module_get_next_sensor(sensor, i);获取传感器列表,并把它加入自己的fullList列表中。我们看sensors_module_get_next_sensor()函数 static jint sensors_module_get_next_sensor(JNIEnv *env, jobject clazz, jobject sensor, jint next){ if(sSensorModule == NULL)return 0;
SensorOffsets& sensorOffsets = gSensorOffsets;const struct sensor_t* list;int count = sSensorModule->get_sensors_list(sSensorModule, &list);if(next >= count)return-1;
list += next;
jstring name = env->NewStringUTF(list->name);jstring vendor = env->NewStringUTF(list->vendor);env->SetObjectField(sensor, sensorOffsets.name, name);env->SetObjectField(sensor, sensorOffsets.vendor, vendor);env->SetIntField(sensor, sensorOffsets.version, list->version);env->SetIntField(sensor, sensorOffsets.handle, list->handle);env->SetIntField(sensor, sensorOffsets.type, list->type);env->SetFloatField(sensor, sensorOffsets.range, list->maxRange);env->SetFloatField(sensor, sensorOffsets.resolution, list->resolution);env->SetFloatField(sensor, sensorOffsets.power, list->power);next++;return next } 它主要是调用HAL层的get_sensors_list()函数取得传感器列表信息。接着在sensorManger构造函数最后
sSensorThread = new SensorThread();创建一个SensorThread()线程。但并未运行,但在SensorThread类的构造函数里会执行jni函数 sensors_data_init();我们看此函数static jint sensors_data_init(JNIEnv *env, jclass clazz){ if(sSensorModule == NULL)return-1;int err = sensors_data_open(&sSensorModule->common, &sSensorDevice);return err;} 它调用了HAL层的sensors_data_open函数,而这个函数位于sensor.h中,它调用的是 static inline int sensors_data_open(const struct hw_module_t* module, struct sensors_data_device_t** device){ return module->methods->open(module, SENSORS_HARDWARE_DATA,(struct hw_device_t**)device);} Modules->methods->open函数。而在SensorThread类的析构函数finalize()里会调用 sensors_data_uninit();static jint sensors_data_uninit(JNIEnv *env, jclass clazz){ int err = 0;if(sSensorDevice){ err = sensors_data_close(sSensorDevice);if(err == 0)sSensorDevice = 0;} return err;} 在sensor.h里
static inline int sensors_data_close(struct sensors_data_device_t* device){ return device->common.close(&device->common);} 那什么时候sSensorThread线程会运行呢?我们在下面看registerListener()函数。
(2)public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate){ return registerListener(listener, sensor, rate, null);} 它调用的是 public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate, Handler handler)在这函数中,先验证rate,然后检测注册的listener在不在本类的sListeners列表中。for(ListenerDelegate i : sListeners){ if(i.getListener()== listener){ l = i;break;} } 如果不在就申请一个listener,并把它加入全局列表sListener中,并调用mSensorService的enableSensor()函数使能传感器,这个enableSensor()函数最终会调用HAL层的active函数和set_delay()函数,使用后然后判断sListener列表是否为空,当然,第一次为空时加入一个新的listener就不为空了,此时就执行sSensorThread的startLocked运行sSensorThread线程了
l = new ListenerDelegate(listener, sensor, handler);result = mSensorService.enableSensor(l, name, handle, delay);if(result){ sListeners.add(l);sListeners.notify();} if(!sListeners.isEmpty()){ sSensorThread.startLocked(mSensorService);} 另一方面,如果注册的listener在sListeners列表中,则先调用mSensorService的enableSensor()函数使能传感器,然后把注册的传感器加入到已存在的listener中。result = mSensorService.enableSensor(l, name, handle, delay);if(result){ l.addSensor(sensor);} 接下来我们看看startLocked函数,它在SensorThread中,void startLocked(ISensorService service){ try { if(mThread == null){ Bundle dataChannel = service.getDataChannel();mThread = new Thread(new SensorThreadRunnable(dataChannel), SensorThread.class.getName());mThread.start();} } catch(RemoteException e){ Log.e(TAG, “RemoteException in startLocked: ”, e);} } 第一次mThread为null,然后它调用了service.getDataChannel()函数,此函数在SensorService类中,主要调用了jni函数_sensors_control_open(),public Bundle getDataChannel()throws RemoteException { // synchronize so we do not require sensor HAL to be thread-safe.synchronized(mListeners){ return _sensors_control_open();} } SensorService类中调用的jni函数主要都在com_android_server_SensorService.cpp文件 中,我们看一下这个函数 static jobject android_open(JNIEnv *env, jclass clazz){ native_handle_t* handle = sSensorDevice->open_data_source(sSensorDevice);if(!handle){ return NULL;}
// new Bundle()jobject bundle = env->NewObject(gBundleOffsets.mClass, gBundleOffsets.mConstructor);
if(handle->numFds > 0){ jobjectArray fdArray = env->NewObjectArray(handle->numFds, gParcelFileDescriptorOffsets.mClass, NULL);for(int i = 0;i < handle->numFds;i++){ // new FileDescriptor()jobject fd = env->NewObject(gFileDescriptorOffsets.mClass, gFileDescriptorOffsets.mConstructor);env->SetIntField(fd, gFileDescriptorOffsets.mDescriptor, handle->data[i]);// new ParcelFileDescriptor()jobject pfd = env->NewObject(gParcelFileDescriptorOffsets.mClass, gParcelFileDescriptorOffsets.mConstructor, fd);env->SetObjectArrayElement(fdArray, i, pfd);} // bundle.putParcelableArray(“fds”, fdArray);env->CallVoidMethod(bundle, gBundleOffsets.mPutParcelableArray, env->NewStringUTF(“fds”), fdArray);}
if(handle->numInts > 0){ jintArray intArray = env->NewIntArray(handle->numInts);env->SetIntArrayRegion(intArray, 0, handle->numInts, &handle->data[handle->numInts]);// bundle.putIntArray(“ints”, intArray);env->CallVoidMethod(bundle, gBundleOffsets.mPutIntArray, env->NewStringUTF(“ints”), intArray);}
// delete the file handle, but don't close any file descriptors native_handle_delete(handle);return bundle;} 它主要调用了HAL层的open_data_source()函数。取得一些文件描述符等信息。接下来SensorThread创建一个线程,调用start()就进入SensorThreadRunnable类的run()函数了,所以我们接着去看run()函数,它首先调用open()函数 if(!open()){ return;} 在open()函数中调用了 jni函数sensors_data_open(fds, ints);static jint sensors_data_open(JNIEnv *env, jclass clazz, jobjectArray fdArray, jintArray intArray){ jclass FileDescriptor = env->FindClass(“java/io/FileDescriptor”);jfieldID fieldOffset = env->GetFieldID(FileDescriptor, “descriptor”, “I”);int numFds =(fdArray ? env->GetArrayLength(fdArray): 0);int numInts =(intArray ? env->GetArrayLength(intArray): 0);native_handle_t* handle = native_handle_create(numFds, numInts);int offset = 0;
for(int i = 0;i < numFds;i++){ jobject fdo = env->GetObjectArrayElement(fdArray, i);if(fdo){ handle->data[offset++] = env->GetIntField(fdo, fieldOffset);} else { handle->data[offset++] =-1;} } if(numInts > 0){ jint* ints = env->GetIntArrayElements(intArray, 0);for(int i = 0;i < numInts;i++){ handle->data[offset++] = ints[i];} env->ReleaseIntArrayElements(intArray, ints, 0);}
// doesn't take ownership of the native handle return sSensorDevice->data_open(sSensorDevice, handle);} 这函数最终调用了HAL层的data_open(),之后run()函数就进入一个while循环了。while(true){ // wait for an event final int sensor = sensors_data_poll(values, status, timestamp);
int accuracy = status[0];synchronized(sListeners){ if(sensor ==-1 || sListeners.isEmpty()){ if(sensor ==-1){ // we lost the connection to the event stream.this happens // when the last listener is removed.Log.d(TAG, “_sensors_data_poll()failed, we bail out.”);}
// we have no more listeners or polling failed, terminate the thread sensors_data_close();mThread = null;break;} final Sensor sensorObject = sHandleToSensor.get(sensor);if(sensorObject!= null){ // report the sensor event to all listeners that // care about it.final int size = sListeners.size();for(int i=0;i ListenerDelegate listener = sListeners.get(i);if(listener.hasSensor(sensorObject)){ // this is asynchronous(okay to call // with sListeners lock held).listener.onSensorChangedLocked(sensorObject, values, timestamp, accuracy);} } } } 它调用了jni函数sensors_data_poll()一直读数据。static jint sensors_data_poll(JNIEnv *env, jclass clazz, jfloatArray values, jintArray status, jlongArray timestamp){ sensors_data_t data;int res = sSensorDevice->poll(sSensorDevice, &data);if(res >= 0){ jint accuracy = data.vector.status;env->SetFloatArrayRegion(values, 0, 3, data.vector.v);env->SetIntArrayRegion(status, 0, 1, &accuracy);env->SetLongArrayRegion(timestamp, 0, 1, &data.time);}
return res;} 把传感器得到的值都放在value数组中,根据返回的传感器标志sensor,把它分派给在sListener列表中所有的listener,如果listener中有监听这个sensor,就把它分派给这个listener,此时就会引起onSensorChange()了。
好了,获取传感器数据主要是这样一个途径。最后我们去分析一下unregisterListener()函数。
private void unregisterListener(Object listener){ if(listener == null){ return;} try { synchronized(sListeners){ final int size = sListeners.size();for(int i=0;i ListenerDelegate l = sListeners.get(i);if(l.getListener()== listener){ // disable all sensors for this listener for(Sensor sensor : l.getSensors()){ String name = sensor.getName();int handle = sensor.getHandle();mSensorService.enableSensor(l, name, handle, SENSOR_DISABLE);} sListeners.remove(i);break;} } } } catch(RemoteException e){ Log.e(TAG, “RemoteException in unregisterListener: ”, e);} } 不用想这个函数会做一些与registerListener相反的事情,至少差不多。它先在sListeners列表中找到这个listener,然后先调用enableSensor()函数禁止这个传感器。我们跟踪一下这函数,在SensorService类中。synchronized(mListeners){ if(enable!=SENSOR_DISABLE &&!_sensors_control_activate(sensor, true)){ Log.w(TAG, “could not enable sensor ” + sensor);return false;}
Listener l = null;int minDelay = enable;for(Listener listener : mListeners){ if(binder == listener.mToken){ l = listener;} if(minDelay > listener.mDelay)minDelay = listener.mDelay;}
if(l == null && enable!=SENSOR_DISABLE){ l = new Listener(binder);binder.linkToDeath(l, 0);mListeners.add(l);mListeners.notify();}
if(l == null){ // by construction, this means we're disabling a listener we // don't know about...Log.w(TAG, “listener with binder ” + binder + “, doesn't exist(sensor=” + name + “, id=” + sensor + “)”);return false;}
if(minDelay >= 0){ _sensors_control_set_delay(minDelay);}
if(enable!= SENSOR_DISABLE){ l.addSensor(sensor, enable);} else { l.removeSensor(sensor);deactivateIfUnusedLocked(sensor);if(l.mSensors == 0){ mListeners.remove(l);binder.unlinkToDeath(l, 0);mListeners.notify();} }
if(mListeners.size()== 0){ _sensors_control_wake();_sensors_control_close();} } return true;你们看到它的实现了吧。如果enable是true的话,就调用_sensors_control_activate(),如果是false的话,就调用deactivateIfUnusedLocked(),它们最终都会调用 HAL层的active()函数。最后,如果是禁止传感器的话,如果mListeners为空了,它就会调用 _sensors_control_wake();_sensors_control_close();这两个jni函数,最终会调用HAL层的wake()和close_data_source()函数。当调用wake()函数时,会使SensorManager类线程的run()函数中的sensor_data_poll()函数立即返回,此时在run()函数中调用sensors_data_close();最终会调用HAL层的data_close()函数。至此,一个传感器从初始到结束的流程就分析完了。
所以在java使用一个传感器在HAL层具体调用的函数流程为: 首先,sensors_control_open(),只在系统初始化时调用一次。用来初始化control_device结构体。
以下的是每次使用传感器一般经过的流程,注意,是一般而已,有些并不执行(1)sensors_data_open(2)get_sensors_list(3)activate(4)set_delay(5)open_data_source(6)data_open(7)poll 一直读数据。。。。。。退出时(8)activate(9)sensors_control_close(10)data_close
当然其它的细节你们可以继续去研究。也可以在我博客里提出来大家交流和讨论一下!发表于 @ 2010年04月15日 09:25:00 | 评论(15 AddFeedbackCountStack(“5487476”))| 编辑| 举报| 收藏
var CurrentEntryId = '5487476';var CurArticleTitle = '阅读android有关sensor的源码总结';var AllowComment = 'True';var AllowAnonymousComment = /^true$/i.test('False');匿名用户 发表于Saturday, April 24, 2010 4:10:24 PM IP:举报回复删除挺好的,可是我有一点疑问呢?匿名用户 发表于Wednesday, May 05, 2010 10:44:44 AM IP:举报回复删除代码中怎么没有看到hal stub的东西啊?我想知道open等操作的具体实现(非kenne层)匿名用户 发表于Thursday, May 06, 2010 11:42:40 PM IP:举报回复删除回复 匿名用户: check sensors_device_open()in sensor.c 匿名用户 发表于Friday, May 07, 2010 12:12:08 AM IP:举报回复删除我看了详细代码,讲得很好。流程大概就是这样了。估计你没有hal层代码,因为那是芯片厂商提供或者自己写的。很难写。匿名用户 发表于Saturday, May 08, 2010 12:04:55 AM IP:举报回复删除Hal usually has folling functions: 1.Sampling Device manager notifies sensor drivers via ioctl to refresh sensor data.Sensor drivers usually utialize i2c bus API functions(i.e.i2c_transfer())to fetch data.2.Reporting After sampling, sensor device drivers report sensor data through input device via input device API functions(i.e.input_report_xxx()and input_sync())3.in sensor_xxx.c or sensor_xxx.cpp, dev->device.poll = sensors_data_poll;sensors_data_poll()is a static function to pick sensor, poll and read sensor data.In Platform: 1.in android_hardware_SensorManager.cpp jni function sensors_data_poll()is provided for SensorManager.java to poll sensor data.sensors_data_poll()actually calls sensors_data_poll()in sensor_xxx.c /sensor_xxx.cpp.2.In SensorManager.java.registerListener()would call sSensorThread.startLocked().sSensorThread.startLocked()would create a new thread based on SensorThreadRunnable()that calls sensors_data_poll().3.In SensorThreadRunnable()listener.onSensorChangedLocked()is called to notify the Sensor event listener after polling sensor data.tigerhily 发表于Thursday, June 03, 2010 10:08:06 PM IP:举报回复删除jerry: 讲得真好!顶一个。请问你有HAL的具体实现吗?我想参考一下。或者讲讲sensors_data_open(3)activate(4)set_delay(5)open_data_source(6)data_open(7)poll 这些接口的具体实现!谢谢匿名用户 发表于Saturday, June 05, 2010 12:15:03 AM IP:举报回复删除Tigerhily: 1.poll()is usually via input_event.Please get poll()reference from EventHup.cpp is you do not have sensor_xxx.c or sensor_xxx.cpp.input_event is device independent abstraction layer provided by the kernel.2.set_delay()starts from SensorManager.java, it calls native delay function in snesor_xxx.c or sensor_xxx.cpp.sensor_xxx.c or sensor_xxx.cpp calls ioctl to set delay value to sendor device driver.sensor device driver usually creates a miscdevice to accept ioctl command.3.Sensor device driver utilizes delay to adjust sampling rate and retrieves data via i2c bus and saves the data via input_event to let application pull sensor data.tigerhily 发表于Sunday, June 06, 2010 8:48:21 PM IP:举报回复删除回复 匿名用户:hi jerry:Thanks for your help.Actually I don't have sensro_xxx.c and i am going to implement it.I will try and consult if needed.Thanks.lz_fine 发表于Tuesday, August 03, 2010 2:08:17 PM IP:举报回复删除你好,我现在也在做这块,但是我遇到一个问题,我在HAL层的sensor.c中control__activate()函数中打开设备文件/dev /sensor成功,并且能执行ioctl操作,但是到了data__poll()函数中再执行ioctl就失败了,报告的错误是Bad file number,errno是EBADF,看起来好像是这个fd被关闭了,这个怎么也想不通,因为看起来SensorThread还在跑,而且在 sensor.c中也没有执行close操作,这种情况有没有遇到过啊,能解释一下吗,感激不尽lz_fine 发表于Wednesday, August 04, 2010 3:55:43 PM IP:举报回复删除找到ioctl失败的原因了,是在SensorManager.java中关闭fd的,不过正常情况下sensor.c中应该先复制一个fd,因此加上一句复制fd的语句就可以了,终于搞定了,内牛满面啊iceskyang 发表于Thursday, August 05, 2010 11:02:16 AM IP:举报回复删除问一下,如果加入后台进程用来辅助计算加速度磁场的值,那么这个进程为什么会在一开机后就运行的。我在int.rc中明明设置了disabled。
第四篇:32位Ubuntu 11.10下android2.3.7源码下载与编译小结
32位Ubuntu 11.10下android2.3.7源码下载与编译小结
1、我是在vmware下安装ubuntu 11.10的,这个网上资料很多,不多说了。我给ubuntu分了25g硬盘和1g内存。
2、请参照http://source.android.com/source。初始化编译环境 检查一下包是否安装: Python 2.4-2.7 Git 1.5.4 或更高版本
没有话可以sudo apt-get install..安装一下
JDK 6 因为是编译android2.3以上,如果编译2.2以下需要JDK5 安装JDK6:
$ sudo add-apt-repository“deb http://archive.canonical.com/ lucid partner” $ sudo apt-get update $ sudo apt-get install sun-java6-jdk 如果下载速度不行,可以先把ubuntu的更新源改成网易的源,可参考:http://bolg.malu.me/html/2010/279.html。其他需要安装的包:
我安装了如下包:官网上那是64位需要安装的包,我是32位的有些不一样。
$ sudo apt-get install git-core gnupg flex bison gperf libsdl1.2-dev libesd0-dev libwxgtk2.6-dev build-essential zip curl libncurses5-dev zlib1g-dev x11proto-core-dev libx11-dev libgl1-mesa-dev g++-multilib mingw32 tofrodos python-markdown libxml2-utils
3、下面开始下载源码
首先安装repo(是一个便于git管理的工具)$ mkdir~/bin $ PATH=~/bin:$PATH $ curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo > ~/bin/repo $ chmod a+x~/bin/repo 初始化repo client $ mkdir android2.3.7 $ cd android2.3.7 初始化repo,我是使用的下面的地址,使用官网地址时出现了网络错误
$ repo init-u http://android.googlesource.com/platform/manifest.git-b android-2.3.7_r1
按照提示输入用户名和邮箱。接着 $ repo sync 开始同步源码,根据你的网速,我的持续了50分钟左右。
还有一步验证git tags可参照官网。下完后就可以在刚才创建的android2.3.7文件夹下看见已下载的源码。
4、开始编译 初始化:
$ source build/envsetup.sh $ lunch full-eng 上面代表编译的一个target,full是针对emulator编译全部包括app、输入法等,eng是指针对开发者编译,有最高权限。具体可参见官网。
接着就可以编译了,在源码目录下直接make就行,需要一段时间。编译过程中有几个问题需要指出一下: 问题1:
由于我们是32位系统,所以有些文件需要修改一下:将./external/clearsilver/cgi/Android.mk./external/clearsilver/java-jni/Android.mk./external/clearsilver/util/Android.mk./external/clearsilver/cs/Android.mk 四个文件中的
LOCAL_CFLAGS+=-m64 LOCAL_LDFLAGS+=-m64
注释掉,或者将“64”换成“32”
LOCAL_CFLAGS+=-m32 LOCAL_LDFLAGS+=-m32
然后,将./build/core/main.mk 中的
ifneq(64,$(findstring64,$(build_arch)))
改为:
ifneq(i686,$(findstring i686,$(build_arch)))
问题2:
frameworks/base/libs/utils/RefBase.cpp:483:67: android::RefBase::weakref_impl‟
as
„this‟
error:
passing
of
„const „void
argument android::RefBase::weakref_impl::trackMe(bool, bool)‟ discards qualifiers [-fpermissive] make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libutils_intermediates/RefBase.o] error 1 如下解决:
$ gedit frameworks/base/libs/utils/Android.mk 将下面一行
LOCAL_CFLAGS+=-DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS)改成
LOCAL_CFLAGS+=-DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS)–fpermissive 问题3:
版本过高造成的,可参考这篇文章修改:http://hi.baidu.com/designhouse/blog/item/fec5cdbf8d6a231618d81fc1.html。至此编译完毕。
make编译的并不是所有内容,不包含内核和SDK。映像生成在out/target/product/generic
下:android
源码编译后得到system.img,ramdisk.img,userdata.img映像文件。其中,ramdisk.img是一个分区映像文件,在kernel启动时,ramdisk被用来调用init,以及把真正的root file system mount起来。system.img包括了主要系统,系统app等,会被挂载到/下,可对应查看./system该目录,可以发现在其下app/下有一些系统自带的应用程序。userdata.img包括了一些用户数据,被挂载到/data下,对应可查看./data/目录,emulator加载这3个映像文件。
5、编译SDK 编译SDK可以得到与源码同步的SDK,还会生成一些tools,在源码根目录下:
$ sudo make PRODUCT-sdk-sdk 编译生成的SDK在out/host/linux-x86/SDK下。之后如果在ubuntu下使用eclipse进行开发,可以使用你编译的SDK。
下面就在模拟器中运行镜像,建议切到root用户下,首先配置几个环境变量,将自己编译的SDK设为优先级最高,在源码根目录下执行:
$sudo update-alternatives
--install/usr/bin/AndroidSDK
AndroidSDK
/home/zhaolin/AndroidSource_GB/out/host/linux-x86/sdk/android-sdk_eng.root_linux-x86255 这样会在/etc/alternatives下生成一个指向该SDK目录的软连接AndroidSDK,这个目录主要存放一些系统默认打开的程序的信息和配置。那么/usr/bin/AndroidSDK就指向这个软连接。接着执行:
gedit~/.bashrc 在文件末尾添加:
export ANDROID_SDK_HOME=/usr/bin/AndroidSDK export PATH=$ANDROID_SDK_HOME/tools:$PATH export ANDROID_PRODUCT_OUT=~/android2.3.7/out/target/product/generic 接着就可以执行:
$ emulator 运行的就是你编译的映像。执行emulator 命令时,如果不带任何参数,则Linux Kernel镜像默认使用~/Android/prebuilt/android-arm/kernel目录下的kernel-qemu文件,而
Android镜像文件则默认使用ANDROID_PRODUCT_OUT目录下的system.img、userdata.img和ramdisk.img。模拟器运行需要这四个文件,如果你编译了内核则可以使用自己的Kernel镜像,可用于android移植等。
6、单独编译模块
如果你不想编译整个系统,就想编译某一个应用程序,可以使用mmm命令,使用之前,在源码目录下先要执行:
$ build/envsetup.sh
这样会生成一些命令,有m即make、mm编译当前目录下所有模块、mmm编译指定目录下所有模块。你可以把packages/apps/Music应用的application name改成MyMusic(AndroidManifest.xml中),然后执行:
$ mmm packages/apps/Music 在out/target/product/generic/system/app中就可以看见Music.apk,然后执行:
$ make snod 重新生成system.img。
第五篇:Android总结
Android四大组件:
Activity—表现屏幕界面
Service—后台服务
BroadcastReceiver—实现广播机制
ContentProvider—实现数据存储
Intent类:用来启动程序并传递信息的类
用于Activity、Receiver、Service之间进行交互的类,通过无参构造方法创建对象,增加其action、category、data、extra等属性进行信息传递,并通过Activity中的startActivity(Intent intent)进行界面的跳转;通过Context中的StartService(Intent intent)进行服务跳转;通过Context中的registerReceive(Intent intent)对广播进行注册,并通过sendBroadcast()进行无序消息发送,或可以通过SendOrderedBroadcast()进行有序的消息发送。Handler类:
用来发送和处理消息,并配合主线程完成UI的更新;消息Message/Runnable传递通过MessageQueue(消息队列,先进先出)进行传递,并通过Lopper进行接收,传递的消息可以为Message对象,也可以是Runnable对象;接收方法通过HandleMessage(Message msg)进行获取。SharedPreferences类:
一般用于第一次登录时的设置,或者是各个界面的一些小型格式设置,如字体等。是本地的小型共享数据库,可以通过Context的静态方法getSharedPreferences获得其对象,对象内的值均为键值对进行储存。通过SharedPreferences对象调用editor()获取SharedPreferences.Editor对象,向共享数据库中增加数据,putString(),并提交数据,commit();通过SharedPreferences对象获取共享数据库中的数据,getString()。
ViewPager:实现界面滑动的类;
通过设置OnPagerChangedListener设置ViewPager的监听事件;
实现流程:
①布局文件中设置ViewPager控件;
②代码中进行绑定控件;
③通过继承PagerAdapter抽象类进行设置适配器,并传递数据源;
④适配器中实现两个抽象方法,两个重写方法:getCount()—获取滑动界面的数量,isViewFromObject()—判断视图是否是来自于Object文件中;重写两个方法,分别为destoryItem—销毁指定位置的视图;InstantiateItem(),设置指定位置的视图;
Timer与TimerTask类:
Timer为计时器的类,通过无参构造方法可以获取对象,通过Timer.schedule(TimerTask task,long time)进行设置多久后执行某任务,当任务执行完后,取消计时的功能,Timer.cancle();TimerTask类为抽象类,实例化时,必须重写run方法;执行的内容,均在run方法中进行设置,并且执行时,已在子线程中进行执行。自定义View:用到的类有Paint、Canvas、Spec、SpecF、Path、View.MeasureSpec、Timer、TimerTask;
抽象类,通过子类继承,获取对象;在布局文件中绑定后,通过代码,设置自定义View的属性;自定义View中,通过重写OnMeasure方法,对布局文件中的尺寸进行测量,并由View中的setMeasureDimenson()方法,进行数据的保存;通过重写Ondraw方法,进行绘图;当需要绘制动态图形时,使用计时器Timer的schedule(TimerTask,long time,delay time2)方法,在time时间后,每隔time2时间,重写执行run方法中的内容;将耗时的操作设置在run方法中,并通过View中的invalidate()方法刷新主线程中的绘的图形,通过postInvalidate()刷新子线程中的图形。数据库:
常用的数据库有Oracle,需要安装和配置的大型收费数据库;MySQL是中型数据库,同样需要安装配置,但不需要收费;Sqlite是小型免费的嵌入式数据库,占用内存低,最新版本为3.0。Sqlite数据库需要通过SqliteDatabaseOpenHelper进行创建数据库,并通过SqliteDatabase进行数据库的操作。辅助类是抽象类,通过继承,重写两个方法,并在子类的构造方法中通过OpenHelper的构造方法(Context context,String SqlName,SqliteDatabase.CursorFactory factory,int version)进行数据库的创建,在onCreate方法中,进行数据库表的创建,在onUpdate中进行数据库的版本更新。在数据库的操作类中,执行exect方法,通过sql语句对数据库进行操作。Create table student(_id integer primary key auto increament ,name text);insert into student(_id,name)values(1,zx);delete from student where _id=1;update student set _id=2 where name=zx;select *from student;ListView、GridView适配器的优化:
将布局文件中的控件进行封装,当视图加载时,判断可变视图是否存在,当不存在时,通过布局文件获取视图,并新建封装类,将地址通过setTag()进行发送;当视图存在时,重复利用地址—getTag()。反射:
存储数据的方式:
共享数据库、数据库、文件、网络、内容提供者
广播:
广播传播时,需要接收者、发送者、广播频道;根据发送者的发送方式不同,分为有序广播、无序广播;有序广播为接收者有接收顺序,根据设置的优先级不同,确定先后顺序,接收者同时也是发送者,向后面的广播发送消息,发送过程中,可以添加信息,也可以停止广播的传输;无序广播,接收者之间无联系,均从发送者处接收信息;广播在传输过程中,不能被添加信息,也不可能被停止。广播在发送前,需要对接收者进行注册,注册方式有两种,动态注册、静态注册。动态注册,是在代码中进行,通过Context对象调用静态方法进行注册,所有的广播均可以用动态注册,其生命周期依赖于应用,相对于静态注册,比较节省内存;静态方法在清单文件中进行注册,部分系统广播不能通过静态注册进行,其生命周期依赖于系统,当系统启动,即运行接收广播,较耗内存。广播接收者需要继承BroadcastReceiver,并实现抽象方法onReceive(),通过回调接口,进行数据的传输。注意:广播发送前,必须进行接收者的注册,并且,当显示跳转时,不需要意图过滤器。安卓布局:九种布局
线性布局,水平或垂直方向两种格式,主要特点为权重,即规定各控件在视图中的占有的比例;
相对布局,相对于父控件或兄弟控件的布局,各控件需指定相对位置; 绝对布局,指定各控件在视图中的绝对位置,几乎不再使用; 表格布局,子布局放在行中,列由控件表示(TableRow); 帧布局:覆盖前面布局的布局,一般用于暂停按钮等; 风格布局:可以跨行、跨列的布局,占满换行;
左右侧滑:可以实现左右侧滑,通过设置主菜单和二级菜单设置左右两个菜单; 下拉刷新:设置下拉刷新、上拉加载的功能; 抽屉布局;
安卓版本及对应的API:
1.6—4;2—7;3—11;4—15;4.3—18;5—20;5.1—21;6—23;7—25; 安卓四层架构:
应用层:Java语言开发,主要从事App开发;
运行库层:Java语言与C语言,View视图、管理类等的开发; 架构层:C语言与Linux语言,各种框架、浏览器等; 内核层:Linux、C语言,开发各种驱动; 安卓四大组件:
Activity:界面,实现程序与用户之间的交换,有自己的生命周期,七个生命周期;4种启动模式 Service:
BroadcastReceive:三要素,发送者、接收者、发送频道(Intent);类型:有序(接收有序,有数据传送,可以拦截数据)、无序广播(相对);注册方式:静态注册,持久监听,占用内存比较高生命周期跟随系统,动态注册(代码中),所有广播都可以动态注册,部分系统广播不能动态注册,临时监听,占用内存较少,生命周期随应用进行;
ContentProvide:不能存放数据,五种存放数据方式之一,特点为:①为数据的获取等操作添加一个统一的接口②可以实现跨应用访问数据;③可以实现Android中通讯录、消息、音频、视频等的访问或操作;通过ContentReceive进行数据的访问,可以对数据进行增删改查操作。
动画: IO流: 序列化: AlertDialog:
Set实现类: 手机电量检测:
自定义SurfaceView:
自定义View:三个构造方法的区别
Message:Handler.obtain/new/Message.obtain
HttpUriConnection访问网络
gride 异步任务 动画
抽象类和接口 反射 克隆 序列化 侧滑的实现 数据库 Socket:
Gson解析
异步任务和子线程区别 WebView 版本更新 照片的圆角化
Collection与Collections Sql语句
MVP框架与MVC: TCP与UDP的区别: 一键分享的流程: Http协议的理解: 不使用框架访问网络: List集合与set集合: 自定义View的流程: 线性布局的特点: ViewPager的原理: 服务的启动方式:
Activity的启动方式: Xml数据解析: