首页 > 代码库 > Android

Android

遇见的问题

Outofmemery

1,注意bitmap对象销毁

if(bitmapObject.isRecycled()==false) //如果没有回收 
             bitmapObject.recycle();

1,  除了上次Android开发网提到的 优化Dalvik虚拟机的堆内存分配外,我们还可以强制定义自己软件的对内存大小,我们使用Dalvik提供的 dalvik.system.VMRuntime类来设置最小堆内存为例:

private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ;

VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE);//设置最小heap内存为6MB大小。当然对于内存吃紧来说还可以通过手动干涉GC去处理。

LOCAL_SDK_VERSION := current

Mkfile中设置的话,会使应用程序不能访问hide的api

关联android library project失败

Eclipse中,Properties-Android-Libraryadd一个工程进行关联(该工程的Properties-Android-Library中,is Lirary已打钩),失败,Javabuild path-Libraries中的“Android Dependencies”中没有自动加入关联工程的jar包。

原因:在windows系统下,libraryproject必须和project处于相同的盘符中,因为如果在不同盘符,project.properties中的android.library.reference.1值变成绝对路径,而ADT推荐是在ubuntu下使用的,对windows绝对路径有支持bug。

添加资源

在系统的framework/base/core/res/res中添加等资源(字串、layout等),需要在framework/base/core/res/res/values/symbols.xml中同步添加资源字串(代表系统私有资源,不对app公开),否则编译会出错。在device里添加资源,也要在symbols.xml中同步添加资源,因为device是由framework/base/core/res/resinclude的?

 

样式

Activity:

setContentView() 会导致先前添加的被移除, 即替换性的;而 addContentView() 不会移除先前添加的UI组件,即是累积性的

对话框:

<activityandroid:name=".wifi.MobileToWlanPopUpActivity" android:theme="@android:style/Theme.Dialog"   //指定了activity的样式

自定义:

values 文件夹中创建一个styles.xml 文件,定义好。

android:theme="@style/MyDialogStyle"/>

菜单(option):

菜单不仅仅可以显示在列表中,也可以显示在窗口的某个位置

    <item

        android:id="@+id/send"

        android:title="@string/send_action"

        android:showAsAction="ifRoom|withText"

        android:icon="@drawable/ic_menu_send_holo_light"

        android:alphabeticShortcut="s"

/>

这样就在右上角建立了一个按钮,带提示字符。而menu键打开的菜单中看不到这一项了。

View相关

Dpi:dot per inch的缩写,就是每英寸的像素数,也叫做屏幕密度。dpi高的,单位长度里的像素多。

Dpi/dp: Densityindependent pixel的缩写,指的是抽象意义上的像素。指定长度时尽量用dp替代px(像素个数),这样可以保证不同dpi设备上,显示的物理长度是一致的。

 

android.R是android内置的资源,在xml引用如下:

android:id="@android:id/empty"

在程序里引用如下:

android.R.layout.simple_list_item_1

 

R是本地资源文件,在xml引用如下:

android:id="@+id/my_button"

在程序里引用如下:

R.id.my_button

 

R.java及本地资源文件,使用“@+”声明的资源,系统会自动在R.java中创建。

利用LinearLayout动态添加控件

LinearLayout.addView:可以动态塞n个view进去

getChildCount  getChildAt removeViewAt

关于布局

Layout中有写法如下:

    layout_height="0dip"  或者 layout_width="0dip"  

    这里的意思是不是用具体的数值来计算高度或者宽度,而是和layout_weight一起来使用的。

       <View

           android:layout_width="0dip"

           android:layout_height="match_parent"

           android:layout_weight="1"/>

       <Buttonandroid:id="@+id/remove_account_button"

           android:layout_width="0dip"

           android:layout_height="wrap_content"

            android:layout_weight="2"

           android:layout_marginTop="5dip"

           android:text="@string/remove_account_label"/>

       <View

           android:layout_width="0dip"

           android:layout_height="match_parent"

           android:layout_weight="1"/>

   </LinearLayout>

这几个View宽度的的比例便是1:2:1

 

1fill_parent

设置一个构件的布局为fill_parent将强制性地使构件扩展,以填充布局单元内尽可能多的空间。这跟Windows控件的dockstyle属性大体一致。设置一个顶部布局或控件为fill_parent将强制性让它布满整个屏幕。

2 wrap_content

设置一个视图的尺寸为wrap_content将强制性地使视图扩展以显示全部内容。以TextView和ImageView控件为例,设置为wrap_content将完整显示其内部的文本和图像。布局元素将根据内容更改大小。设置一个视图的尺寸为wrap_content大体等同于设置Windows控件的Autosize属性为True。

3match_parent
   Android2.2中match_parent和fill_parent是一个意思 .两个参数意思一样,match_parent更贴切,于是从2.2开始两个词都可以用。那么如果考虑低版本的使用情况你就需要用fill_parent了

Application类的意义

可以不用自定义实现,但可以自定义用来存放全局数据,以及在特定时刻自动调用定义的OnCreate等方法。

如果自定义了,要在androidManifest.xml中注册:

<application   android:name="完整包名类名"  (如果在xml中定义了包名就只需要写类名,如:<original-package android:name="com.android.XXX" />)

获取实例:(MyApplication)getApplication();  

android:persistent: 被android:persistent修饰的应用会在系统启动之后被AM启动。

intent

intent发送的三种基本形态:

startActivity/startService/sendBroadcast,系统会根据intent-filter的注册情况,安排接收者。

代码中使用:

    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)

    public static final StringACTION_PHONE_STATE_CHANGED =

           "android.intent.action.PHONE_STATE";

的方式(括号内可变),就可以用Intent.ACTION_PHONE_STATE_CHANGED来发送、接收intent了。SdkConstant注解指定了SDK中可以被导出的常量字段值

Intent-filter

用于匹配Activity可以接收到哪些intent后被打开。Action,category,data都是intent的属性。

<action android:name="android.intent.action.INSERT_OR_EDIT"/>

<category android:name="android.intent.category.DEFAULT" />

<data android:mimeType="vnd.android.cursor.item/person"/> (type/subtype)

如果定义的Activity需要接收隐式intent(implicitintent),必须配置“android.intent.category.DEFAULT”属性。

 

vnd.android.cursor.dir/vnd.google.note 返回的是 数据的 URI
vnd.android.cursor.item/vnd.google.note 
返回的是 数据的 内容

如果该数据可能包含多条记录,MIME类型字符串以vnd.android.cursor.dir/开头,如果该数据只包含一条数据,以vnd.android.cursor.item/开头。

type/subtype是可以自定义的。

  • Android:scheme

定义:

<intent-filter>

    <categoryandroid:name="android.intent.category.DEFAULT"></category>

    <actionandroid:name="android.intent.action.VIEW"></action>

    <dataandroid:scheme="sh"></data>

</intent-filter>

调用:

startActivity(newIntent(Intent.ACTION_VIEW, Uri.parse("sh://123123123")));

获得data:

this.getIntent().getScheme();//获得Scheme名称

this.getIntent().getDataString();//获得Uri全部路径

  • Android:icon

供用户查看的代表所属 Activity、Service 或 BroadcastReceiver 的图标,表示这些组件拥有过滤器所描述的功能。

比如让用户选择“通过XX程序打开”,列表中的icon就是定义在intent-filter中的相应icon,当然如果没有特别指定,将会用application的icon代表。

 

broadcast

1,  静态注册

在androidManifest.xml中注册,无论该应用是否活动,都处于监听状态

2,  动态注册

使用InterFilter注册,当应用关闭后,就不再监听。

OnSaveInstanceState (Bundle outState)

当系统存在“未经你许可”时销毁了我们的activity的可能时,则onSaveInstanceState()会被系统调用.如果调用,调用将发生在onPause()或onStop()方法之前。(虽然测试时发现多数在onPause()前)

由于onSaveInstanceState()方法方法不一定会被调用, 因此不适合在该方法中保存持久化数据, 例如向数据库中插入记录等. 保存持久化数据的操作应该放在onPause()中。若是永久性值,则在onPause()中保存;若大量,则另开线程吧,别阻塞UI线程。

the data you place in the Bundle here willbe available in the Bundle given to onCreate(Bundle),onCreateView(LayoutInflater, ViewGroup, Bundle), and onActivityCreated(Bundle). 保存用outState.putBoolean(XX),outstate.putBundle(XX)等,然后可以用相应的get方法取出来

严苛模式(StrictMode)

它将报告与线程及虚拟机相关的策略违例。一旦检测到策略违例(policy violation),你将获得警告,其包含了一个栈trace显示你的应用在何处发生违例。你可以强制用警告代替崩溃(crash),也可以仅将警告计入日志,让你的应用继续执行。

  1. StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()  
  2.     .detectDiskReads()  
  3.     .detectDiskWrites()  
  4.     .detectNetwork()  
  5.     .penaltyLog()  
  6.     .build()); 

Builder类使得设置变得很简单,Builder函数定义所有策略都返回Builder对象,从而这些函数能像列表2-9那样串连在一起。最后调用build()函数返回一个ThreadPolicy对象作为StrictMode对象的setThreadPolicy()函数的参数。

  1. StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()  
  2.     .detectLeakedSqlLiteObjects()  
  3.     .penaltyLog()  
  4.     .penaltyDeath()  
  5.     .build());  

类似于线程策略(ThreadPolicy),严苛模式(StrictMode)有虚拟机策略(VmPolicy)。虚拟机策略(VmPolicy)能检查内存泄漏,虚拟机策略(VmPolicy)不能通过一个对话框提供警告。

开关:

<application>字段的属性之一是android:debuggable

  1. if ((appFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {  …

Uri

Android的Uri由以下三部分组成: scheme://host:port/path(绿色表示可省略)

举些例子,如: 

所有联系人的Uri:content://contacts/people

某个联系人的Uri:content://contacts/people/5

所有图片Uri:content://media/external

某个图片的Uri:content://media/external/images/media/4

Android根据“数据的路径”来找到对应注册过的数据发布者。

URI,是uniformresource identifier,统一资源标识符,用来唯一的标识一个资源。而URL是uniformresource locator,统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。一个URI实例可以代表绝对的,也可以是相对的,只要它符合URI的语法规则。而URL类则不仅符合语义,还包含了定位该资源的信息,因此它不能是相对的,schema必须被指定。

用URL表示文件时,服务器方式用file表示,后面要有主机IP地址、文件的存取路径(即目录)和文件名等信息。有时可以省略目录和文件名,但“/”符号不能省略。

例一:file://ftp.yesky.com/soft/file/robots.txt

代表存放主机ftp.yesky.com上的soft/file/目录下的一个文件,文件名是robots.txt。

Manifest

1.添加权限声明。比如要用到网络,添加<uses-permissionandroid:name="android.permission.INTERNET"></uses-permission>;
2.添加新的Activity。比如增加的Home.java类,继承Activity,添加<activity android:name="Home"android:configChanges="orientation|keyboardHidden|navigation" />
3.为额外的库添加声明。比如要用到Google Map的时候,不是Android内部包,引入包后,添加<uses-libraryandroid:name="com.google.android.maps"/>
4.程序运行的最低版本声明。添加<uses-sdkandroid:minSdkVersion="3"></uses-sdk>
5.为自己的后台Service声明。添加<service
      android:name=".MyService"
      android:exported="true"
      android:process=":remote">
    </service>

如service不发布给其他应用,可不声明 intent filter.这样就只能显示地以Service类名来启动。此外,可以设置android:exported为false,使Service为当前应用所私有。

6.其它情况,比如加入Admob广告:添加<meta-dataandroid:value="http://www.mamicode.com/yourID" android:name="ADMOB_PUBLISHER_ID"/>;
广播事件:<receiver android:name="HippoCustomIntentReceiver" >
      <intent-filter>
           <actionandroid:name="android.intent.action.BOOT_COMPLETED" />
        <actionandroid:name="HIPPO_ON_SERVICE_001" />
        <categoryandroid:name="android.intent.category.HOME" />
      </intent-filter>
    </receiver>

擦除UFS分区

make_ext4fs/dev/block/sda6

 

WindowManager

隐藏NavigationBar

\device\sscr\p632x\overlay_DVT2\frameworks\base\core\res\res\values\config.xml

<boolname="config_showNavigationBar">false</bool>

技术分享

技术分享

1,公共界面的窗口。这种窗口没有任何窗口类来封装,获取WindowManager的service后,((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))调用mWindowManager.addView(View,lp)来把自定义的view添加到WindowManager中。SystemUI就是这张绘制StatusBar和NavigationBar的。如果在app中这么做,应该可以画出最顶层的一个窗口或全屏界面。

2,client窗口。和应用相关的窗口表示类是PhoneWindow和Window,PhoneWindow继承于Window,针对手机屏幕做了一些优化工作。PhoneWindow里面核心的是mDecorView这个变量,mDecorView是一个顶层的View,在应用初始化的时候,会首先生成一个Activity对象,此时该activity还没有属于他的一个窗口。紧接着通过调用attach()函数,在attach()函数里面该activity会调用PolicyManager.makeNewWindow()创建一个新的PhoneWindow,然后在activity的onCreate()生命周期里,一般应用都会调用setContentView()设置该activity的显示界面。这个布局对应的就是PhoneWindow里面的mDecorView(即自定义的view最终拼到了DecorView里)。最后在activity将要显示出来之前,通过getWindow().getDecorView()获取到DecorView,并通过WindowManager.addView(DecorView,lp)把DecorView添加到WindowManager中。

View view = mainActivity.getLocalActivityManager().startActivity(screen_id, intent).getDecorView();        

            LinearLayout layout = (LinearLayout) mainActivity.findViewById(R.id.main_linearLayout_principal);

            layout.removeAllViews();

            layout.addView(view, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

窗口管理

技术分享

服务端的实现代码是在/framework/base/services/java/com/android/server/wm/里。

WindowManagerService负责完成窗口的管理工作;

WindowState和客户端窗口一一对应,应用调用WindowManager.addView()时,最终会在WindowManagerService添加一个WindowState与之一一对应(WMS中有成员变量“ArrayList<WindowState>   mWindows”管理所有的WindowState)。

窗口绘制

技术分享

一个WindowState想要显示在屏幕上,必须申请一个显示缓存,这个显示缓存的管理和维护是在底层图形模块实现的,在java层有一个操作的封装对象Surface。ViewRoot有了这块显示缓存的引用之后,即可以通过lockCanvas来获取绘画画布,绘制完毕之后通过unlockAndPostCanvas来将绘制内容刷新到显示缓存中。Client负责绘制Surface的内容,Server负责控制Surface在屏幕上的大小位置等。

APP UI层次查看

可使用SDK中自带的Monitor工具

JNI

开发步骤

可以跳出jvm,访问native,并实现数据格式转换。

技术分享

system.loadLibrary(String libname) lets you load from the default path -- The Java library path.
system.load(String filename)lets you load it from an absolute path, which you must specify as your filename.

Jni程序开发步骤如下:

l        编写java中的调用类 (.java -> .class)

l        用javah生成c/c++原生函数的头文件 (.class -> .h)

Javah –jni xxx.xxx.xxx (完整包+类名,不带文件后缀)

l        c/c++中实现原生函数 (.c/.cpp -> .so/.dll)

JNIEXPORT xxx(xxx)   如果是SWIG生成的,是SWIGEXPORT xxx(xxx)

文件名:java_ + jni包和类名 +函数名

l        将native代码打成库,并加入java项目

1,Native代码目录中建立Android.mk:

LOCAL_PATH := $(call my-dir)

Include $(CLEAR_VARS)

LOCAL_MODULE := xxxx

LOCAL_SRC_FILES := xxxx.c

Include $(BUILD_SHARED_LIBRARY)

这样,就被被打成库文件

2,java项目的Android.mk中加入:

APP_PROJECT_PATH:= $(call my-dir)/project

APP_MODULES := xxx

l        生成java程序

JNI调用Java方法的步骤:

先使用FindClass方法获取指定类class,在使用GetStaticMethodID方法或者GetMethodID获取静态和非静态的方法id;GetFieldID获得成员变量。在使用CallObjectMethod或者CallStaticObjectMethod方法调用静态非静态方法,对于没有返回值的方法,函数为CallVoidMethod/CallStaticVoidMethod形式。

1) 获取jmethodID;

GetMethodID

jmethodIDGetMethodID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
jclass ClassCJM =(*env)->FindClass(env,"com/example/cjm/CJM");  //获取java类

jmethodID MethodDisplayMessage = (*env)->GetMethodID(env, ClassCJM, "displayMessage","(Ljava/lang/String;)V");

2) 调用Java方法;

NativeType Call<type>Method(JNIEnv *env, jobjectobj,jmethodID methodID, ...);
jstring value =http://www.mamicode.com/(*env)->NewStringUTF(env,"HelloWorld!");

(*env)->CallVoidMethod(env,thiz, MethodDisplayMessage, value); // displayMessage有一个String类型的参数,通过“value”传入。返回void

Instance Method Calling Routines:

CallVoidMethod

void

CallObjectMethod

jobject

CallBooleanMethod

jboolean

CallByteMethod

jbyte

CallCharMethod

jchar

CallShortMethod

jshort

CallIntMethod

jint

CallLongMethod

jlong

CallFloatMethod

jfloat

CallDoubleMethod

jdouble

Logcat

原理:

写log:将log写入/dev/log目录,会再细化分别放入main,radio和events目录。(mkdir,open打开或创建文件,write)

读log:open,select阻塞等待log的到来,read

 

logcat -b radio |grep XXXX

 

NDK 如何输出log

  1. mkfile中引入androidNDK库
  2. #include<android/log.h>
  3. 使用LOGD,LOGE…或者直接用__android_log_print(ANDROID_LOG_DEBUG,LOG,__VA_ARGS__) 

最终就是向设备文件写入log,设备文件如下:

1

#define LOGGER_LOG_MAIN     "log/main"

 

2

#define LOGGER_LOG_RADIO    "log/radio"

 

3

#define LOGGER_LOG_EVENTS   "log/events"

 

4

#define LOGGER_LOG_SYSTEM   "log/system"

AIDL

只有当你允许来自不同的客户端访问你的服务并且需要处理多线程问题时你才必须使用AIDL”,其他情况下你都可以选择其他方法,如使用Messager,也能跨进程通讯。可见AIDL是处理多线程、多客户端并发访问的。而Messager是单线程处理。

发布服务:

1,   创建AIDL文件IXXService.aidl,自动生成.java文件IXXService.java

2,   定义一个Service类,使用内嵌类实现接口(Stub子类)

Public class XXXService extendsService

{

   @Override

Public class XXServiceImp extends IXXService.Stub

{

 

@Override

Public IBinder onBind(Intentintent)

{

   Return new XXServiceImp();

}

3,   发布服务

3.1)配置manifest.xml,声明定义的Service的服务名

<serviceandroid:name=”. IXXService”>

         <intent-filter>

                   <action android:name=”myintent.xxxxx”/>

</service>

这样发布后,客户端可以用bindService(new Intent(myintent.xxxxx),…)来获取IBinder

 

3.2)通过代码注册服务

ServiceManager.addService(DEVINFO_SERVICE, devInfo);  

这样就可以通过ServiceManager.getService(XXX)来获取IBinder了

 

使用服务:(->IBinder->Service)

1,   使用bindService获取服务的IBinder

bindService(new Intent(myintent.xxxxx),mServiceConnection,Context.BIND_AUTO_CREATE)

bind/unbind成功后会回调ServiceConnection的onServiceConnected和onServiceDisconnected方法

2,    实现ServiceConnection 的onServiceConnected接口和OnServiceDisconnect来通过IBinder实例获得Service对象

myServcie = XXX.Stub.asInterface(service);

3,   调用service的接口

 IXXX mService

 private ServiceConnection mServiceConnection = new ServiceConnection() {  

        public void onServiceConnected(ComponentName className,  

                IBinder service) {  

            mService = XXX.Stub.asInterface(service);  

            try {  

                mService.registerTestCall(mCallback);}  

            catch (RemoteException e) {  

                  

            }  

            }  

        public void onServiceDisconnected(ComponentName className) {  

            Log("disconnect service");  

            mService = null;  

            }  

        };  

 

在Android中想要跨进程传递对象,必须使用AIDL(Android Interface Definition Language)服务。例如ImsCallForwardInfo.aidl:

 

package com.android.ims;

 

parcelable ImsCallForwardInfo;

然后ImsCallForwardInfo.java:

public class ImsCallForwardInfo implementsParcelable

然后通过一个aidl定义的服务类,进行set、get

为什么需要aidl

不需要aidl 的binder的IPC通讯过程,表面上结构很简单,但是有个困难就是,客户端和服务端进行通讯,你得先将你的通讯请求转换成序列化的数据,然后调用transact()函数发送给服务端,而且还得制定一个小协议,参数谁先谁后,服务端和客户端都必须一致,否则就会出错。

技术分享

IxxxxService.Stub.asInterface(IBinder obj)  

首先当bindService之后,客户端会得到一个Binder引用,拿到Binder引用后,调用IxxxxService.Stub.asInterface(IBinder obj) 即可得到一个IxxxxService 实例。不管服务端和客户端是否在同一个进程,

AIDL的最终效果就是让 IPC的通讯就像调用函数那样简单。自动的帮你完成了参数序列化(aidl自动编译出来的代码包含了这部分内容)发送以及解析返回数据的那一系列麻烦。

 

另外,在android中想要跨进程传递对象,必须使用AIDL服务。例:

AIDL文件中就写两行:

package aidlpackage.entity;  

parcelable School;  

关键字package声明School.java类在哪个包中,parcelable是在系统中注册这个类名称。

系统服务

系统服务类似于AIDL。在有了aidl文件及其实现,并后,还需要通过

1)在frameworks/base/core/java/android/content/Context.java中增加Service名称定义,例:

public static final String DEVINFO_SERVICE = "devinfo";  

2)在frameworks/base/services/java/com/android/server/SystemServer.java中注册服务(ServiceManager.addService)

3)在frameworks/base/Android.mk文件中的LOCAL_SRC_FILES增加aidl的声明,例:

@@ -112,6 +112,7 @@ LOCAL_SRC_FILES += \

+        core/java/android/app/IDevInfoManager.aidl \

关机充电

技术分享

流程只走到init这一部分,就没有往后走了。

UBOOT中把androidboot.mode设定为charger状态,内核正常流程启动,然后到init时要对charger这种状态处理。

Activity启动 / Task

启动一个Activity时,Ams首先会去查询该Activity所在的应用是否开启,如果没有开启则会启动一个进程去Run这个Application,因此无论通过Launcher还是通过常规的程序内部调用startActivity来启动一个Activity,所要启动的Activity都是跑在其注册的apk所在的Application进程中(或者该组件android:process指定的进程中),而其TaskID一般是和启动它的组件所属的TaskId一直,但是也不尽然,这就要看下面的具体分析了。

通过对service的应用,可以得出结论,一个apk,即一个应用(Application)可以跑在多个进程中,一个进程在一个虚拟机中运行,也即一个apk可以启动多个虚拟机。通过shareuserID可以将多个apk,跑在同一个进程中。从而得出结论:一个虚拟机只能跑一个进程,一个进程里可以跑多个应用,一个应用也可以跑在多个进程中。

影响Activity启动关键点大致有三个因素:Activity注册信息中的launchMode、启动Activity时Intent中的launchFlags和Activity注册信息中的taskAffinity、allowTaskReparenting、clearTaskOnLaunch、alwaysRetainTaskState、finishOnTaskLaunch等信息。

standard

standard是默认模式,Ams只是简单的创建一个新的Activity实例,将其放到ActivityStack

singleTop

Ams会查询AS:假如在AS顶端正是要启动的Activity实例,那么Ams就不会重新启动一个Activity实例,而是调用AS栈顶的该Activity实例的OnNewIntent函数(自然不会修改原来的TaskId值);假如在AS栈顶不是该Activity的实例,那么就会创建一个新的实例,将其压入AS,其TaskId与调用者Activity相同。这种方式主要用于避免自调自过程中,产生多个实例的情况。

以往基于应用(application)的程序开发中,程序具有明确的边界,一个程序就是一个应用,一个应用为了实现功能可以采用开辟新线程甚至新进程来辅助,但是应用与应用之间不能复用资源和功能。而Android引入了基于组件开发的软件架构,虽然我们开发android程序,仍然使用一个apk工程一个Application的开发形式,但是对于Aplication的开发就用到了Activity、service等四大组件,其中的每一个组件,都是可以被跨应用复用的哦,这个就是android的神奇之处。

另外值得一提的是,虽然组件可以跨应用被调用,但是一个组件所在的进程必须是在组件所在的Aplication进程中。由于android强化了组件概念,弱化了Aplication的概念,所以在android程序开发中,A应用的A组件想要使用拍照或录像的功能就可以不用去针对Camera类进行开发,直接调用系统自带的摄像头应用(称其B应用)中的组件(称其B组件)就可以了,但是这就引发了一个新问题,A组件跑在A应用中,B组件跑在B应用中,自然都不在同一个进程中,那么从B组件中返回的时候,如何实现正确返回到A组件呢?Task就是来负责实现这个功能的,它是从用户角度来理解应用而建立的一个抽象概念。因为用户所能看到的组件就是Activity,所以Task可以理解为实现一个功能而负责管理所有用到的Activity实例的栈。

dtb

dts --> dtb文件  Device Tree Source的缩写,用来描述设备的硬件细节。Linux采用DTS这种新的数据结构来描述硬件设备。采用Device Tree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码。dtb里面最后被kernel解析,并创建为platform device, 相应的 你也必须要有platform driver 才行。

 

查看dts设备节点
------------------------------------
# ls -al /proc/device-tree

 

Android