如果你想看Android源碼,強無敵,so,c++,jni,java都有
1. Android生命周期大家都知道,但你知道什么時候走onStop和onPuase,onDestory么,區別呢?
Activity的活動狀態與Activity在棧中的位置有密切的關系,而且,Android在系統資源不足的時候,也是從Activity棧中選擇哪些Activity是可以終止的,一般來講,Activity系統會優先選擇終止處于目前是停止狀態并且比較靠近Activity棧底的Activity。
也就是說onDestory并不是那么快,那為什么我應用總onStop直接onDestory呢,因為你項目越是龐大,需求的資源就越多,所以系統認為需要GC。
結合實例:
Activity的生命周期是指Activity從啟動到銷毀的過程。
Activity有四種狀態:活動狀態 暫停狀態 停止狀態 非活動狀態
先看下Actvity的七個生命周期函數以及說下這幾個函數都是在什么時候調用的:
- 那么說明onDestory并不是來得飛快
- 那么說明onStop只有被全部遮擋,就調用
- 那么說明onPause只要被遮擋,就調用(除了幾個特殊)
- 1.鎖屏的時候,會依次調用onPause()和onStop()。
- 2.Toast、Dialog、Menu,三者都不會使Activity調用onPause()
- 3.一個非全屏的Activity在前面時,后面的Activity只調用onPause()
再補充一點:這篇文章很贊,兩個activity切換生命周期你真懂么?
再擴展發下思維:不同生命時期,調用finish會發生啥
結合前面知識你應用很清楚認識到這個啟動的流程的生命周期了。
再總結下:
2. Actvity啟動你了解過底層么,流程大致呢,繼承Actvity,自己是否一定要實現oncreate的方法?
轉載:Android Application啟動流程分析
凡是涉及父類源碼中要調用getApplication().dispatchActivityXXX(this)時要重寫super.XXX(),因為這是binder回調過程,需要通知和更新當前生命周期。當然binder還要回饋給遠端System Server
3. Android官方優化工具會用么,區別呢?
- 本人只會用Traceview而且很好用,分析方法調用棧以及其執行時間, 優化方法執行。絕大部分是優化時間效率
- 控件樹的優化,其實你在開發需求的時候就定死,你不可能腦殘到循環嵌套那么多層,用Hierarchy Viewer查看把深度的控件樹,變成廣度控件樹能提升。Hierarchy Viewer在ddms中其他window中,能單步反應出每個控件的效率在相對這棵樹的情況,保持綠色小圓點最優,保持16ms渲染速度,3個小圓點,Measure, Layout, Draw,保持draw在10ms以下基本最優。
你要有個概念GPU和CPU,你布局邏輯計算是CPU完成的,GPU只是貼圖和柵格化,主線程拿不到CPU片斷你也會掉幀。
什么是掉幀,源碼是SurfaceFlinger真正繪制,發送Vsync通過Choreographer不停的loop向主線程,16ms一次,其中就被阻塞,如果當次在16ms沒有繪制完,系統發出的Vsync沒有得到回收,該幀被丟棄,等待下一個Vsync才開始繪制,導致了可能在16ms*2內顯示同一個畫面,這就是卡頓的原因。
推薦個很牛的博客,底層分析
來自網絡圖片 - 還有內存和oom,這個本人使用LeackCanary和Memory Monitor去分析了,大量的GC,內存波動,你就要想這個需求是否正確了,LeackCanary會報很多GC不能回收的錯誤,debug時候開啟它,盡量在開發時候就解決,到后期優化,你要跳樓的。LeackCanary生成內存分析報文hrof文件,在as中直接查看,如果你想忽略其中報錯,加入LeackCanary白名單代碼map,或者
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
關于LeackCanary抓取回收dump文件過程,不詳細介紹,網上一大把。
大致:Application ====》install()====》LeackCanary:RefWatcher這貨去監聽了Context的生命周期回調
AndroidWatchExextor線程處理收集信息 =====》Dump文件 ====》回調DumpService中Listener去刷新界面和通知欄
1.RefWactcher.watch()會監控對象來創建一個keyedweadkRerence弱引用對象。
2.在AndroidWatchExextor后臺線程來檢查弱引用的對象被請出沒有,如果沒有,GC一次,然后再看
3.如果沒有干掉說明,內存泄露,系統導出hprof文件
所有的強引用是鏈接在GC樹上的,只有瞬時的對象和臨時對象會自動回收不在鏈接樹。
GC ROOT 你沒有懂?看這個,我第一次就瞬間懂了
- Android ANR解決案例由dropboxmanagerservice生成的log還是有價值的
4. Android生命周期長短比較?
getApplicationContext()(全局appliction的上下文) > getApplication()(全局appliction對象) > this(context)
關于上面錯誤感謝評論區:lockeez童鞋指針,錯誤我先留這了,大家利用評論區,學習總結下。
每個Application對應于子進程創建次數,都會調用onCreate(),Application和Service一樣沒有onResume
5. JobServices?
在android7.0以后谷歌官方推薦用JobServices做調度作業,起到優化作用。
在以下場景很適用:
1.最小延時 2.是否空閑
3.是否有網絡 4.最晚執行
5.是否充電。
滿足之一,需要調用權限。
6. AsyncTaskLoader和AsyncTask?
區別于AsyncTask一般做數據查詢,在Activity配置沒有改變,只更新數據源,loader用來開啟異步任務加載數據庫或者Uri數據,只支持不耗時操作。
7. Android進程優先級你真了解完全了?
命令查看進程
補充優先級和拉活知識
據說手Q,保持活就是前臺一個像素activity
再補充一句,adb shell 默認端口你了解過么,5037!
adb shell dumpsys activity top 獲取最上層的Activity
8. 非UI線程能更新UI?
非UI線程能更新UI,只要它有自己的ViewRoot。因為,報錯是報,你的view不在原來的線程。
轉載:Android子線程真的不能更新UI么
9. Activity啟動模式小知識
- 1.不同TaskAffiny和不同進程都能StartActivityForResult回調,這個過程谷歌官方說是安全的,就調用相機,一定會有回掉,但數據有沒有不能保證。但!,很重要一點,除了singleTop或者singleInstance特殊,activityA 通過startActivityForResult()方法來啟動另一個ActivtyB,那么系統將直接返回Activity.Result_Canceled而不會繼續等待。這是由于FrameWork曾對2者做的限制,不同Task之間,默認是不能傳遞數據的,如果你需要,那就Intent。
- 2.getApplicationContext()能不能startActivity()?可以的。
在ContextImpl.startActivity方法中,那我們去看下其源碼,如下:
@Override
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
// 就是下面這個檢測干的好事!!!
if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity) null, intent, -1, options);
}
通過上面的源碼我們發現了問題的根本原因,要fix這個問題也很簡單,添加如下代碼intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);即可。
- 3.onActivityResult特性:
/**
* Called when an activity you launched exits, giving you the requestCode
* you started it with, the resultCode it returned, and any additional
* data from it. The <var>resultCode</var> will be
* {@link #RESULT_CANCELED} if the activity explicitly returned that,
* didn't return any result, or crashed during its operation.
*
* <p>You will receive this call immediately before onResume() when your
* activity is re-starting.
*
* <p>This method is never invoked if your activity sets
* {@link android.R.styleable#AndroidManifestActivity_noHistory noHistory} to
* <code>true</code>.
*
* @param requestCode The integer request code originally supplied to
* startActivityForResult(), allowing you to identify who this
* result came from.
* @param resultCode The integer result code returned by the child activity
* through its setResult().
* @param data An Intent, which can return result data to the caller
* (various data can be attached to Intent "extras").
*
* @see #startActivityForResult
* @see #createPendingResult
* @see #setResult(int)
*/
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
}
也就是說,如果你給requestCode并且大于0,那么就會有數據返回,這和底層binder通信有關,非oneway的形式。如果返回沒有結果,或者崩潰了在傳遞過程中,resultCode將等于RESULT_CANCELED。這個過程是onResume之前的。如果你的activity在AndroidManifest設置了noHistory為true,將不會有回調。
10. Bitmap用完一定要bitmap.recycle()么?
不需要,你調用也沒有錯,自動Android 3.0之后,由于Bitmap放到java heap上,其內存有GC管理,之前版本是在系統Native上的。
11.Android中為什么主線程不會因為Looper.loop()里的死循環卡死?
- 也就是說,Android本身主線程是帶阻塞的,然而又為什么不會卡界面其他響應呢,因為是Android系統操作會繪制是事件驅動行的,每次做個操作或者完成繪制,改變狀態是一個事件Post到主線程的,然后繼續運行,休眠。
- 再補充一點為什么ActivityThread本身是一個普通類,不是Runnable和Thread怎么實現線程機制和界面刷新的。在ActivityThread::main()===>attach()中完成了looper創建和ViewRootImpl創建(這就上面第8點的疑惑)
- 其中會引入一個IdleHandler問題,什么叫空閑線程Handler,它就是在你這線程cpu空虛的時候干點臟活,如釋放資源,打印log
內容太多,簡單描述就是,干完以后就休眠MessageQueue - 這篇介紹了額外的內容,關于C++底層監控
補充內容:為什么Android的Handler采用管道而不使用Binder?,Binder底層和Handler底層實現是一樣的,管道操作文件描述符的句柄,使用epoll往其中內存地址空間寫數據。只是Binder比管道更加繁重,有Binder驅動完成跨進程,找到對應端口。而管道只支持線程通信,因為他操作的地址是固定的,一端寫入一端寫出,跨進程是需要拷貝數據到目標進程的。反過來可以,看鏈接描述。
- wine process 你可以理解就是可以運行windows程序的虛擬機進程,當然你也能中windows病毒,如果sudo權限夠高。在 Linux 下面安裝 Wine 會不會使 Linux 中 Windows 病毒?
- watchdog 你可以理解是專門給進程配合的忠實伙伴,能解決和監聽進程死鎖問題。關系和人類與狗一樣,它能發現你最近為什么心情不好。原理在這:WatchDog工作原理
- cron 定時執行任務,類似Android AlarmManager。Linux下的crontab定時執行任務命令詳解
12.Activity4種啟動模式都知道了?那么有2個同是singleInstance并且taskAffinity相同會這樣呢?
沒有任何關系,啟動后打印TaskId還是不同的idx。
<activity
android:name="com.example.aaa.a1"
android:label="@string/app_name"
android:taskAffinity="c.aaaa"
android:launchMode="singleInstance">
</activity>
<activity
android:name="com.example.aaa.a2"
android:label="@string/app_name"
android:taskAffinity="c.aaaa"
android:launchMode="singleInstance">
</activity>
13.bind啟動的service,當調用者finish掉后,會真的調用onUnbind么?
會,親測demo
@Override
Activity :: protected void onCreate(Bundle savedInstanceState) {
Intent intent = new Intent(this, a.class);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
new Handler().post(new Runnable() {
@Override
public void run() {
AppActivity.this.finish();
}
});
@Override
Service :: public boolean onUnbind(Intent intent) {
Toast.makeText(this, "exit", Toast.LENGTH_SHORT).show();
return super.onUnbind(intent);
}
你可能不知道IntentService和Service真正區別。讓一次性簡單記住,IntentService是只能塞進去去完成任務,做完就unbind了,所以你就認為一次性的。Service復雜點,能查詢也能做,IntentService只能做,不能記住狀態去查詢。
14你知道ViewRootImpl何時調用第一次performTraversals()?
出自 我簡短了大部分,用來回答我問題,其他懂的,可以不看。
handleResumeActivity在收到AMS代理遠程對象的Scaule后開始。
performLaunchActivity函數完成了兩件事:
- 1 Activity窗口對象的創建,通過attach函數來完成;
- 2 Activity視圖對象的創建,通過setContentView函數來完成;
這些準備工作完成后,就可以顯示該Activity了,應用程序進程通過調用handleResumeActivity函數來啟動Activity的顯示過程。
看addView()
frameworks\base\core\java\android\app\ ActivityThread.java
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
unscheduleGcIdler();
ActivityClientRecord r;
try {
①r = performResumeActivity(token, clearHide);
} catch (Exception e) {
...
}
if (r != null) {
final Activity a = r.activity;
...
if (r.window == null && !a.mFinished && willBeVisible) {
//獲得為當前Activity創建的窗口PhoneWindow對象
r.window = r.activity.getWindow();
//獲取為窗口創建的視圖DecorView對象
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
//在attach函數中就為當前Activity創建了WindowManager對象
ViewManager wm = a.getWindowManager();
//得到該視圖對象的布局參數
②WindowManager.LayoutParams l = r.window.getAttributes();
//將視圖對象保存到Activity的成員變量mDecor中
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
l.idleScreenAvailable = true;
} else {
l.idleScreenAvailable = false;
}
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
//將創建的視圖對象DecorView添加到Activity的窗口管理器中
③wm.addView(decor, l);
}
} else if (!willBeVisible) {
...
}
...
if (!r.onlyLocalRequest) {
r.nextIdle = mNewActivities;
mNewActivities = r;
Looper.myQueue().addIdleHandler(new Idler());
}
...
} else {
...
}
}
在前面的performLaunchActivity函數中完成Activity的創建后,會將當前當前創建的Activity在應用程序進程端的描述符ActivityClientRecord以鍵值對的形式保存到ActivityThread的成員變量mActivities中:mActivities.put(r.token, r),r.token就是Activity的身份證,即是IApplicationToken.Proxy代理對象,也用于與AMS通信。上面的函數首先通過performResumeActivity從mActivities變量中取出Activity的應用程序端描述符ActivityClientRecord,然后取出前面為Activity創建的視圖對象DecorView和窗口管理器WindowManager,最后將視圖對象添加到窗口管理器中。
我們知道Activity引用的其實是輕量級的窗口管理器LocalWindowManager
frameworks\base\core\java\android\view\ Window.java
public final void addView(View view, ViewGroup.LayoutParams params) {
WindowManager.LayoutParams wp = (WindowManager.LayoutParams)params;
CharSequence curTitle = wp.getTitle();
//應用程序窗口
if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
if (wp.token == null) {
View decor = peekDecorView();
if (decor != null) {
// LayoutParams 的token設置為W本地Binder對象
wp.token = decor.getWindowToken();
}
}
if (curTitle == null || curTitle.length() == 0) {
//根據窗口類型設置不同的標題
…
if (mAppName != null) {
title += ":" + mAppName;
}
wp.setTitle(title);
}
} else {//系統窗口
if (wp.token == null) {
wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
}
if ((curTitle == null || curTitle.length() == 0)
&& mAppName != null) {
wp.setTitle(mAppName);
}
}
if (wp.packageName == null) {
wp.packageName = mContext.getPackageName();
}
if (mHardwareAccelerated) {
wp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
super.addView(view, params);
}
看setView()
frameworks\base\core\java\android\view\WindowManagerImpl.java
private void addView(View view, ViewGroup.LayoutParams params,
CompatibilityInfoHolder cih, boolean nest) {
...
final WindowManager.LayoutParams wparams= (WindowManager.LayoutParams)params;
ViewRootImpl root;
View panelParentView = null;
synchronized (this) {
...
//從mViews中查找當前添加的View
int index = findViewLocked(view, false);
//如果已經存在,直接返回
if (index >= 0) {
...
return;
}
//尚未添加當前View
if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
final int count = mViews != null ? mViews.length : 0;
for (int i=0; i<count; i++) {
if (mRoots[i].mWindow.asBinder() == wparams.token) {
panelParentView = mViews[i];
}
}
}
//為Activity創建一個ViewRootImpl對象
①root = new ViewRootImpl(view.getContext());
...
//設置視圖組件的布局參數
view.setLayoutParams(wparams);
if (mViews == null) {
index = 1;
mViews = new View[1];
mRoots = new ViewRootImpl[1];
mParams = new WindowManager.LayoutParams[1];
} else {
//動態增加mViews數組長度
index = mViews.length + 1;
Object[] old = mViews;
mViews = new View[index];
System.arraycopy(old, 0, mViews, 0, index-1);
//動態增加mRoots數組長度
old = mRoots;
mRoots = new ViewRootImpl[index];
System.arraycopy(old, 0, mRoots, 0, index-1);
//動態增加mParams數組長度
old = mParams;
mParams = new WindowManager.LayoutParams[index];
System.arraycopy(old, 0, mParams, 0, index-1);
}
index--;
②mViews[index] = view;
mRoots[index] = root;
mParams[index] = wparams;
}
try {
③root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
...
}
}
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
//將DecorView保存到ViewRootImpl的成員變量mView中
mView = view;
mFallbackEventHandler.setView(view);
mWindowAttributes.copyFrom(attrs);
attrs = mWindowAttributes;
mClientWindowLayoutFlags = attrs.flags;
setAccessibilityFocus(null, null);
//DecorView實現了RootViewSurfaceTaker接口
if (view instanceof RootViewSurfaceTaker) {
mSurfaceHolderCallback =
((RootViewSurfaceTaker)view).willYouTakeTheSurface();
if (mSurfaceHolderCallback != null) {
mSurfaceHolder = new TakenSurfaceHolder();
mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
}
}
...
//同時將DecorView保存到mAttachInfo中
mAttachInfo.mRootView = view;
mAttachInfo.mScalingRequired = mTranslator != null;
mAttachInfo.mApplicationScale = mTranslator == null ? 1.0f : mTranslator.applicationScale;
if (panelParentView != null) {
mAttachInfo.mPanelParentWindowToken
= panelParentView.getApplicationWindowToken();
}
...
//在添加窗口前進行UI布局
①requestLayout();
if ((mWindowAttributes.inputFeatures& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
//將窗口添加到WMS服務中,mWindow為W本地Binder對象,通過Binder傳輸到WMS服務端后,變為IWindow代理對象
②res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mAttachInfo.mContentInsets,
mInputChannel);
} catch (RemoteException e) {
...
}
...
//建立窗口消息通道
if (view instanceof RootViewSurfaceTaker) {
mInputQueueCallback =
((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
}
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue(mInputChannel);
mInputQueueCallback.onInputQueueCreated(mInputQueue);
} else {
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper());
}
}
...
}
}
}
public void requestLayout() {
//檢查當前線程是否是UI線程
checkThread();
//標識當前正在請求UI布局
mLayoutRequested = true;
scheduleTraversals();
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
//暫停UI線程消息隊列對同步消息的處理
mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
//向Choreographer注冊一個類型為CALLBACK_TRAVERSAL的回調,用于處理UI繪制
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
//向Choreographer注冊一個類型為CALLBACK_INPUT的回調,用于處理輸入事件
scheduleConsumeBatchedInput();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
try {
performTraversals();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
ViewRootImpl的setView函數向WMS服務添加一個窗口對象過程:
- 1 requestLayout()在應用程序進程中進行窗口UI布局;
- 2 WindowSession.add()向WMS服務注冊一個窗口對象;
- 3 注冊應用程序進程端的消息接收通道;
這就是為什么你在OnReume一開始調用View的高寬拿不到,postRunnale以后能拿到,因為doTraversal()在Post棧頂,等它跑完就能拿到數值了。
補充硬件加速原理
對View補充一些知識
15 Android在應用層有3種信號你知道么?
public static final int SIGNAL_QUIT = 3; // 追蹤日志
public static final int SIGNAL_KILL = 9; // Process::killProcess()應用比較多
public static final int SIGNAL_USR1 = 10; // 用于強制執行GC
16 Intent和PendingIntent?
- Intent是立即使用的,而PendingIntent可以等到事件發生后觸發,PendingIntent可以cancel
- Intent在程序結束后即終止,而PendingIntent在程序結束后依然有效
- PendingIntent自帶Context,而Intent需要在某個Context內運行
- Intent在原task中運行,PendingIntent在新的task中運行
PendingIntent還要注意其中flag,因為他是有內核收集器,像Map一樣
public final class PendingIntent implements Parcelable {
/** @hide */
@IntDef(flag = true, //======================flag值=============================
value = {
FLAG_ONE_SHOT,
FLAG_NO_CREATE,
FLAG_CANCEL_CURRENT,
FLAG_UPDATE_CURRENT,
Intent.FILL_IN_ACTION,
Intent.FILL_IN_DATA,
Intent.FILL_IN_CATEGORIES,
Intent.FILL_IN_COMPONENT,
Intent.FILL_IN_PACKAGE,
Intent.FILL_IN_SOURCE_BOUNDS,
Intent.FILL_IN_SELECTOR,
Intent.FILL_IN_CLIP_DATA
})
public static PendingIntent getActivity(Context context, int requestCode,
Intent intent, @Flags int flags) {
return getActivity(context, requestCode, intent, flags, null);
}
public static PendingIntent getActivity(Context context, int requestCode,
@NonNull Intent intent, @Flags int flags, @Nullable Bundle options) {
String packageName = context.getPackageName();
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
flags, options, UserHandle.myUserId());
return target != null ? new PendingIntent(target) : null;
} catch (RemoteException e) {
}
return null;
}
}
遠程對象,在system server進程中 AMS.getIntentSender。
public IIntentSender getIntentSender(int type,
String packageName, IBinder token, String resultWho,
int requestCode, Intent[] intents, String[] resolvedTypes,
int flags, Bundle options, int userId) {
//重新拷貝一次intent對象內容
if (intents != null) {
for (int i=0; i<intents.length; i++) {
Intent intent = intents[i];
if (intent != null) {
intents[i] = new Intent(intent);
}
}
}
...
synchronized(this) {
int callingUid = Binder.getCallingUid();
int origUserId = userId;
userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
type == ActivityManager.INTENT_SENDER_BROADCAST,
ALLOW_NON_FULL, "getIntentSender", null);
if (origUserId == UserHandle.USER_CURRENT) {
userId = UserHandle.USER_CURRENT;
}
return getIntentSenderLocked(type, packageName, callingUid, userId,
token, resultWho, requestCode, intents, resolvedTypes, flags, options);
}
}
IIntentSender getIntentSenderLocked(int type, String packageName,
int callingUid, int userId, IBinder token, String resultWho,
int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
Bundle options) {
ActivityRecord activity = null;
...
//創建Key對象
PendingIntentRecord.Key key = new PendingIntentRecord.Key(
type, packageName, activity, resultWho,
requestCode, intents, resolvedTypes, flags, options, userId);
WeakReference<PendingIntentRecord> ref;
ref = mIntentSenderRecords.get(key);//=======================關于flag使用========================
PendingIntentRecord rec = ref != null ? ref.get() : null;
if (rec != null) {
if (!cancelCurrent) {
if (updateCurrent) {
if (rec.key.requestIntent != null) {
rec.key.requestIntent.replaceExtras(intents != null ?
intents[intents.length - 1] : null);
}
if (intents != null) {
intents[intents.length-1] = rec.key.requestIntent;
rec.key.allIntents = intents;
rec.key.allResolvedTypes = resolvedTypes;
} else {
rec.key.allIntents = null;
rec.key.allResolvedTypes = null;
}
}
return rec;
}
rec.canceled = true;
mIntentSenderRecords.remove(key);
}
if (noCreate) {
return rec;
}
//創建PendingIntentRecord對象
rec = new PendingIntentRecord(this, key, callingUid);
mIntentSenderRecords.put(key, rec.ref);
...
return rec;
}
17 BroadcastReceiver?
BroadcastReceiver分為兩類:
- 靜態廣播接收者:通過AndroidManifest.xml的標簽來申明的BroadcastReceiver。
- 動態廣播接收者:通過AMS.registerReceiver()方式注冊的BroadcastReceiver,動態注冊更為靈活,可在不需要時通過unregisterReceiver()取消注冊。
前面你都知道,下面這3個你知道么。
從廣播發送方式可分為三類:
- 普通廣播:通過Context.sendBroadcast()發送,可并行處理
- 有序廣播:通過Context.sendOrderedBroadcast()發送,串行處理
- Sticky廣播:通過Context.sendStickyBroadcast()發送
區別。很多誤區在有序廣播,并不是發送一條條有序,而是接受一條條有順序,排序更android:priority有關。
18 java對象和java序列化原理?
序列化的原理
對象模型
其實就是一堆字節碼,linux也是有文件節點掛載起來的,說白了也是一堆字節碼。通信就全靠序列號來標識。
19 說說Android應用的persistent屬性?
Android應用的persistent屬性觀看這個博客需要先看Android系統啟動流程,才能大部分有概念。一般普通應用不要使用,沒有權限限制這貨。
知道這貨能干嘛呢?如果我要你啟動系統相機你怎么玩,不要彈出Intent匹配對話框?
public static void launchSystemCamera(Activity activity, File file, int requestCode) {
try{
//獲取相機包名
Intent infoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
List<ResolveInfo> infos = activity.getPackageManager().queryIntentActivities(infoIntent, 0);
if(infos != null && infos.size() > 0) {
for(ResolveInfo info:infos) {
int flags = info.activityInfo.applicationInfo.flags;
if ((flags & ApplicationInfo.FLAG_SYSTEM) != 0) { //系統相機
String packageName = info.activityInfo.packageName;
String className = info.activityInfo.name;
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
ComponentName cn = new ComponentName(packageName, className);
intent.setComponent(cn);
intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(file));
activity.startActivityForResult(intent,requestCode);
return;
}
}
}
} catch(Exception e) {
e.printStackTrace();
}
}
20 為啥從應用層面來說,沒有殺不死的進程?
Android進程絕殺技--forceStop看完這篇依賴相殺,大家估計都有個概念了。需要了解AMS下的AMS死亡監聽
關于自創Native進程,不知怎么殺...
21 是時候熟悉一個JNI調用系統服務代碼了,Camera?
Android Camera 系統架構源碼分析
總結下:底層大致數據處理時會阻塞,然后自己不處理,姿勢把數據流放給上層,在上層開始Camera的時候你會設置一堆監聽,然后底層會通過binder遠程調用監聽。
DisplayClient用來負責顯示,CamClient則是一個大統一,把Camera的操作都歸集于此。CamClient又把自己的功能分成幾個 Client去負責,其中PreviewClient負責預覽錄制,RecordClient負責錄制。
CameraClient和DisplayClient是兩個功能的操作者,而CamAdapter則是整個Camera的管理者,負責與底層溝通,讀取Buf,并負責分配Buf給各個功能操作者,并包括管理著Camer各種屬性和算法,如3A,是否自動對焦等