您的位置:首页 > 移动开发 > Android开发

Android平台<软硬整合实践技术>_答问集 推荐

2013-12-14 09:15 766 查看

欢迎访问 ==>高老师的博客网页

高焕堂:MISOO(大数据.大思考)联盟.台北中心和东京(日本)分社.总教练




EE EE
Android平台<软硬整合实践技术>_答问集
** 高焕堂老师回答 **
Q-01:在每一个进程里,Android都会创建一个VM的对象。如下图:

请问:为什么不让这些进程来共享同一个VM对象呢?答:设计的考虑视角很多,其中之一是:这样可以避免不同进程里的代码共享一个VM对象,可化解不同App之间的多线程(Multi-threading)开发的可能冲突问题。
Q-02:Android选择了Java与C/C++混合型语言架构。请问:如果将Java改为Python或JavaSctipt等动态语言,会有什么不一样的效果或难题呢?答:设计的考虑视角很多,其中之一是:使用动态语言不融一建构稳定可靠的应用框架(Framework)及其API。反之,Java和 C++强型态(Strong-Typing)语言,能在编译时间(Compiling-Time)进行API规格的检验,可以减少执行时间(Run-time)的可能错误,大幅提升平台(框架)的稳定度。
Q-03:在Android启动过程中,由谁来创建SystemServer进程呢?答:由Linux内核启动用户空间的Init进程,解析脚本文件:Init.rc。这Init.rc是Android的初始化脚本。此时,由Init进程创建ServiceManager和Zygote进程。由Zygote创建了VM进程。

也创建了SystemServer进程。




Q-04:例如有一个App的AndroidManifest.xml文件,其内容如下:
// AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> ……………… <activity android:name=".FirstActivity" ……………… <activity android:name=".LoadActivity"> ……………… <service android:name=".LoadService" android:process=":remote"> ………………</manifest>请问:这支App总共占用了多少个进程呢? 而FirstActivity、LoadActivity和LoadService三者,各在那一个进程里执行呢?答:FirstActivity和LoadActivity背布署于预设(Default)的App进程里。而LoadService则被布署于名称为“remote”的进程里。此App共占用了 2个进程。如下图:



Q-05: 在Android的System Server进程里,需要一个VM对象吗? 如果需要,它的任务是什么?答:在System Server进程里的Android Service是以Java写成的。需要一个VM的对象来执行这些Java代码。如下图:



Q-06:AMS(Activity Manager Service)系统服务执行于那一个进程里呢? 它的职责是什么?答:被布署于System Server进程里。它的主要职责是:1)管理Activity的生命周期; 2)管理应用层的SDK Service(亦即,App里所定义的Service.java的子类)。
Q-07:谁来实际创建出App进程呢?答:由Zygote所Fork出来的。如下图:


[歡迎光臨高煥堂的博客首頁:http://www.cnblogs.com/myEIT/ ]。
Q-08:ServiceManager进程的用途时什么呢?答:ServiceManager协助管理系统服务(System Service),如AMS(Activity Manager Service、WMS(Window Manager Service等)。也协助App来绑定(Bind)系统服务。
Q-09:UI线程是什么?答:如果某个进程里含有Activity组件的话,该进程的主线程(Main Thread)就会去关照UI事件;此时,这个主线程就是俗称的UI线程。
Q-10:关照UI事件(Event)是主线程的重要职责,而且是它的专属职责,其它的子线程并不可以插手存取有关UI画面上的对象属性。请问,为什么会有这样的限制呢? 原因是什么呢?答:在默认情况下,有关UI画面上的对象属性(Attribute)都是单线程(Single-Threading)环境;因而,由UI线程所创建的有关UI画面上的对象的属性值,其它线程不能去存取它。
Q-11:在App执行过程中,有时候Android就会显示出ANR(Activity is Not Responding)小窗口, 向用户询问是否愿意耐心继续等候。请问:会出现ANR告示的主要原因是什么呢?答:当Android发现UI线程的MQ里有些UI事件没来得及(5秒钟内)处理时,Android就会显示出ANR(Activity is Not Responding)小窗口(如下图),向用户道歉。例如,如果App让主线程去执行耗时的任务(如下载云端的影片,或去播放音乐等),常常导致UI线程的MQ里有些UI事件没来得及(5秒钟内)处理。

Q-12:小线程与UI线程的通信途径是由小线程将Message丢到UI线程的信箱(就是Message Queue)里。请问:反过来,UI线程与小线程的通信途径是什么呢?答:由UI线程将Message丢到小线程的信箱(但App需要替小线程创建Message Queue)。如下图:

==>參考:认识EIT造形
Q-13:App如何创建小线程的Message Queue呢? 如何写这段代码呢?答:兹撰写范例代码如下:// ac01.java //……public class ac01 extends Activity implements OnClickListener { private Thread t; private Handler h; private String str; public void onCreate(Bundle icicle) { //…….. t = new Thread(new Task()); t.start(); } public void onClick(View v) {switch(v.getId()){ case 101: Message m = h.obtainMessage(1, 33, 1, null); h.sendMessage(m); break; case 102: setTitle(str); break; case 103: h.getLooper().quit(); finish(); break;}}class Task implements Runnable { public void run() { Looper.prepare(); h = new Handler(){ public void handleMessage(Message msg) { str = Thread.currentThread().getName() + ", value=" + String.valueOf(msg.arg1); }};Looper.loop(); }}}
Q-14:在View类别里有个多形(Polymorphic)的onDraw()函数。请问:为什么只限UI线程才能执行这个onDraw()函数呢? 理由是什么?答:因为在撰写onDraw()函数的实现代码时,都默认其为单线程(Single-Threading)环境。所以,只限UI线程才能执行这个onDraw()函数。如下图:

Q-15:在撰写游戏控制循环(Game Loop)的代码时,UI线程可调用框架基类的invalidate()函数,触发重新调用onDraw(),来刷新画面上的绘图。如下图:

请问:小线程也可以调用此invalidate()函数吗?答:其invalidate()函数会处理到UI,而UI是单线程环境,所以小线程不可以调用此invalidate()函数;但小线程能调用postInvalidate()函数,来间接触发主线程去调用invalidate()函数。例如,有个Gameloop类别的代码如下:public class GameLoop extends Thread { myView mView; GameLoop( myView v ) { mView = v; } public void run() { mView.onUpdate(); mView.postInvalidateDelayed(1000); }} 于是,小线程可调用View类别里的postInvalidate()函数来请求UI线程转而调用View类别的inalidate()函数。如下图:

其中,GameLoop的详细任务,如下图:




[歡迎光臨高煥堂的博客首頁:http://www.cnblogs.com/myEIT/ ]。

Q-16:在View类别体系里,SurfaceView类别比较特殊;请问,其特殊点在哪里?答:小线程可以透过它来绘制UI上的图像。View类别体系是由UI 线程(主线程所执行)。如果需要去迅速更新UI画面或者UI画图需要较长时间(避免阻塞主线程),就使用SurfaceView。它可以由背景线程(background thead)来执行,而View只能由UI(主)线程执行。这SurfaceView内含高效率的rendering机制,能让背景线程快速更新surface的内容,适合演示动画(animation)。如下图:


在程序里,可以通过SurfaceHolder接口来处理Surface,只要呼叫getHolder()函数就可以取得此接口。当Surface诞生和删除时,框架互呼叫SurfaceCreated()和 SurfaceDestroyed()函数。如下图:




Q-17:在执行Android应用程序的Java代码时,如果Java需要与本地代码(如以C写成的*so动态库)沟通时,VM(虚拟机)扮演甚么角色呢?答:Java代码在VM上执行。如下图:

在执行Java代码的过程中,如果Java需要与本地代码(如以C写成的*so动态库)沟通时,VM就会把*.so视为插件(Plug-in)而加载到VM里,然后让Java函数顺利地呼叫到这插件里的C函数。
Q-18:请问:接续上一题,VM在那一个时间点,会去加载所需要的插件呢?答:请参考下述的代码范例:// MediaPlayer.java类 public class MediaPlayer{ static { System.loadLibrary("media_jni"); } ……..} 当这个Java类被加载(Load)时,就会执行System.loadLibrary()函数,而加载这个media_jni.so插件。如下图:


Q-19:为什么Java与C函数不能直接互相调用呢?答:Java代码执行于VM,它透过VM来调用*.so插件,并不直接调用插件里的本地add()函数。如下图:

C代码执行于CPU,必须透过VM才能获得Java代码的攸关资源,例如取得Java类里的属性及函数ID等。
Q-20:本地C函数(如add()函数)的第1个参数是:JNIEnv *env;如下述代码:// com_misoo_pk01_addActivity.cpp………JNIEXPORT jlong JNICALL Java_com_misoo_pk01_addActivity_add (JNIEnv *env, jobject thiz, jint x, jint y){ // ………. }// ………请问,这个JNIEnv类的内涵是什么? 这个env指针(Pointer)有什么用途呢?答:在Android环境里,每一个线程(Thread)第一次进入VM去调用本地函数时,VM会替它诞生一个相对映的JNIEnv对象,记录该线程的状态。而且,该线程每次调用本地函数时,都会将其对映的JNIEnv对象指针值传递给本地函数。不同的线程,会使用不同的JNIEnv对向来与 VM通信。这样有助于化解多线程的冲突问题。如下图:


Q-21:有两个本地函数f1()和f2(),其代码片段如下:JNIEXPORT jlong JNICALL Java_com_misoo_pk01_addActivity_f1(JNIEnv *env_1, jobject thiz){ // ………. }JNIEXPORT jlong JNICALL Java_com_misoo_pk01_addActivity_f2(JNIEnv *env_2, jobject thiz){ // ………. }}请问:当同一条线程去执行f1()和f2()函数,此时env_1和env_2各指向那一个JNIEnv对象呢?如果有两条线程(如th-x和th-y)都执行f1()函数时,又如何呢?

答:此时env_1和env_2都指向同一个JNIEnv对象。如下图:


如果有两条线程(如th-x和th-y)都执行f1()函数时,此时env_1指向不同的JNIEnv对象。如下图:


如果由不同的线程分别去执行f1()和f2(),此时env_1和env_2各指向不同的JNIEnv对象。如下图:


Q-22:当 UI线程经由VM而去执行本地C函数时,UI线程如何去创建一个小线程呢?答:兹写代码范例如下:/* com.misoo.counter.CounterNative.cpp */#include <stdio.h>#include <pthread.h>#include "com_misoo_counter_CounterNative.h"jmethodID mid;jclass mClass; JavaVM *jvm;pthread_t thread;int n, sum;void* trRun( void* );void JNICALLJava_com_misoo_counter_CounterNative_nativeSetup(JNIEnv *env, jobject thiz) { jclass clazz = env->GetObjectClass(thiz); mClass = (jclass)env->NewGlobalRef(clazz); mid = env->GetStaticMethodID(mClass, "callback", "(I)V"); }void JNICALL Java_com_misoo_counter_CounterNative_nativeExec(JNIEnv *env, jobject thiz, jint numb){ n = numb; pthread_create( &thread, NULL, trRun, NULL); }void* trRun( void* ){ int status; JNIEnv *env; bool isAttached = false; status = jvm->GetEnv((void **) &env, JNI_VERSION_1_4); if(status < 0) { status = jvm->AttachCurrentThread(&env, NULL); if(status < 0) return NULL; isAttached = true; } sum = 0; for(int i = 0; i<=n; i++) sum += i; env->CallStaticVoidMethod(mClass, mid, sum); if(isAttached) jvm->DetachCurrentThread(); return NULL;}在本地C函数里所创建的小线程,VM并没有给它专属的JNIEnv对象。所以调用AttachCurrentThtread()函数,向VM索取一个JNIEnv对象。取得JNIEnv对象之后,就能调用CallStaticVoidMethod()等函数,请VM协助存取Java层的资源(如调用Java层函数)。
Q-23:Android不允许A进程的函数直接调用另一个B进程里的函数;为什么呢?答:保护 B进程里的数据,避免被别进程的函数去恶意取得或破坏。
Q-24:Android在Java层和C/C++层都定义了IBinder接口。如下图:

其代码定义是:
//IBinder.java
public interface IBinder {
// ..........
public
boolean transact( int code, Parcel data,
Parcel reply,int flags)
throws RemoteException;
// ...........
}

以图形表示如下:



其典型的角色为:

在C&C++层也定义了IBinder接口,如下图:



请问:这个IBinder接口的主要用途是什么?答:做为跨进程(IPC)通信的通用性接口(Interafce)。基于这通用性接口,Binder System驱动(Driver)就能掌控IPC通信,例如进行有效的转址、转型态、高速传递大量数据等工作。
Q-25:什么是Binder线程呢?答:当A进程的myActivity类想调用B进程里的MediaPlayer类别去拨放mp3音乐时,会透过BD(Binder Driver)去进行跨进程的IPC通信,如下图:

A进程里执行myActivity的<A线程>会到BD(Binder Driver)去启动一个<Binder线程>去执行B进程里的MediaPlayer类别。

此刻<A线程>会等待,直到<Binder线程>执行(MediaPlayer类别的事情)完毕才返回,恢复后续工作。AA DD
[ Go Back ]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息