啟動Activity的流程(Launcher中點選圖示啟動)
啟動Activity一般有多種方式,常見的有三種:
-
在Launcher桌面點選app圖示
-
呼叫startActivity啟動一個Activity
-
命令am start啟動
這三種方式在服務端的處理方式基本相同,客戶端的請求方式也差別不大,理解其中之一就可以類推到其他方式。本文結合案例分析在Launcher桌面點選app圖示啟動應用的方式,再簡要給出其他兩種方式的區別。
案例
應用名稱為TestLaunchApp,包含A和B兩個Activity,A為入口類,點選按鈕跳轉到B
A.java1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | packagecom.example.startapptest; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; publicclassAextendsActivity{ privatefinalstaticStringTAG="StartAppTest"; @Override protectedvoidonCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); Log.i(TAG,"A"+"--------------onCreate()"); setContentView(R.layout.a_layout); } @Override protectedvoidonResume(){ // TODO Auto-generated method stub Log.i(TAG,"A"+"--------------onResume()"); super.onResume(); } @Override protectedvoidonPause(){ // TODO Auto-generated method stub Log.i(TAG,"A"+"--------------onPause()"); super.onPause(); } publicvoidfuncA(View view){ startActivity(newIntent("com.feeyan.www.b_activity")); } @Override publicvoidonBackPressed(){ // TODO Auto-generated method stub finish(); super.onBackPressed(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | packagecom.example.startapptest; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; publicclassBextendsActivity{ privatefinalstaticStringTAG="StartAppTest"; @Override protectedvoidonCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); Log.i(TAG,"B"+"--------------onCreate()"); setContentView(R.layout.b_layout); } @Override protectedvoidonResume(){ Log.i(TAG,"B"+"--------------onResume()"); super.onResume(); } @Override protectedvoidonPause(){ // TODO Auto-generated method stub Log.i(TAG,"B"+"--------------onPause()"); super.onPause(); } publicvoidfuncB(View view){ startActivity(newIntent("com.feeyan.www.a_activity")); finish(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <?xml version="1.0"encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin"> <Button android:id="@+id/button_a_id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="50dp" android:onClick="funcA" android:text="@string/button_a_text" android:textSize="20sp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_marginTop="154dp" android:text="@string/page_a_text" android:textSize="30sp"/> </RelativeLayout> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <?xml version="1.0"encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin"> <Button android:id="@+id/button_b_id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="50dp" android:onClick="funcB" android:text="@string/button_b_text" android:textSize="20sp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/button_b_id" android:layout_centerHorizontal="true" android:layout_marginBottom="140dp" android:text="@string/page_b_text" android:textSize="30sp"/> </RelativeLayout> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | <?xml version="1.0"encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.startapptest" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="17" android:targetSdkVersion="21"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <activity android:name=".A" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> <intent-filter> <action android:name="com.feeyan.www.a_activity"> </action> <category android:name="android.intent.category.DEFAULT"> </category> </intent-filter> </activity> <activity android:name=".B" android:label="@string/app_name"> <intent-filter> <action android:name="com.feeyan.www.b_activity"> </action> <category android:name="android.intent.category.DEFAULT"> </category> </intent-filter> </activity> </application> </manifest> |
當點選A中的按鈕時,跳轉到B,先暫停A,A從前臺轉入到後臺,開始執行B的onCreate、onResume方法,B被調入到棧頂,B現在可見,日誌為:
1 2 3 4 5 | I/StartAppTest(26256):A--------------onCreate() I/StartAppTest(26256):A--------------onResume() I/StartAppTest(26256):A--------------onPause() I/StartAppTest(26256):B--------------onCreate() I/StartAppTest(26256):B--------------onResume() |
啟動一個Activity的標誌是開始執行生命週期onCreate方法,轉入到後臺的標誌是onPause方法,正在執行、可見的標誌是onResume方法,本文將從原始碼著手,分析啟動activity的過程。
1. 在Launcher桌面點選app圖示啟動入口Activity
本文基於android5.1.1原始碼,在Launcher主頁面當點選圖表時,呼叫過程為:
onClick—->……—->startActivitySafely—->startActivity(v, intent, tag)—->startActivity(intent, optsBundle);
原始碼:packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
intent設定了FLAG_ACTIVITY_NEW_TASK標誌,表示開啟一個新任務,在新任務中啟動activity,本案例沒有特殊的動畫設定,optsBundle為null。
framework層客戶端
過程1 frameworks\base\core\java\android\app\Activity.java
startActivity所屬的物件是this,表示當前啟動類Launcher物件,下一步執行到Activity的startActivity方法,過程為:
startActivity(Intent intent, @Nullable Bundle options)
—-> startActivityForResult(intent, -1)
—-> startActivityForResult(intent, requestCode, null)
注:由於原始碼較長,本文不貼上全部原始碼,只給出方法名稱、部分程式碼以及原始碼路徑
action為字串“com.feeyan.www.b_activity”,requestCode等於-1,如果>=0, B被啟動後會返回到A中,且A中的onActivityResult()方法會被呼叫。即便是呼叫startActivity,還是會調到 startActivityForResult,只不過此時requestCode是-1了。
mParent:如果不為空,表示當前Activity有子類,本案例沒有子類,為空,程序執行到:
1 2 3 4 | Instrumentation.ActivityResult ar= mInstrumentation.execStartActivity( this,mMainThread.getApplicationThread(),mToken,this, intent,requestCode,options); |
要搞懂原始碼,最關鍵的就是弄清楚引數的具體含義,原始碼中引數有時候多達十幾個,如果不清楚引數的來龍去脈,無從分析。
this:當前程序還是在Launcher所在的程序,this就是Launcher類的一個物件。
mMainThread.getApplicationThread():返回一個ApplicationThread物件型別,也是一個IBinder物件型別,,mMainThread是ActivityThread的一個物件,代表當前Launcher主執行緒物件
mToken:也是一個IBinder物件型別
requestCode仍為-1,options為null
過程2 frameworks\base\core\java\android\app\Instrumentation.java
1 2 3 4 5 | publicActivityResult execStartActivity( Context who,IBinder contextThread,IBinder token,Activity target, Intent intent,intrequestCode,Bundle options){ ...... } |
this物件傳給execStartActivity,該函式的第一個形參who是Context型別,第4個形參target是Activity型別,其實際型別都是Launcher物件,只是名字起的不一樣,這就是一種共識,代表著某種含義,讀者看到名字就能猜得著其用意。
1 | IApplicationThread whoThread=(IApplicationThread)contextThread; |
contextThread既是IBinder物件,也是IApplicationThread物件,此處向上轉型為IApplicationThread物件,
1 2 3 4 5 | intresult=ActivityManagerNative.getDefault() .startActivity(whoThread,who.getBasePackageName(),intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token,target!=null?target.mEmbeddedID:null, requestCode,0,null,options); |
ActivityManagerNative實現了IActivityManager介面,呼叫getDefault方法最終返回ActivityManagerService的代理類ActivityManagerProxy的一個物件,於是,startActivity便轉入到ActivityManagerProxy物件中開始執行。
過程3 frameworks\base\core\java\android\app\ActivityManagerNative.java
1 2 3 4 5 | publicintstartActivity(IApplicationThread caller,StringcallingPackage,Intent intent, StringresolvedType,IBinder resultTo,StringresultWho,intrequestCode, intstartFlags,ProfilerInfo profilerInfo,Bundle options)throwsRemoteException{ ...... } |
分析引數時,結合實際引數來看,否則單獨看形參不能確定具體含義。
caller:前面傳過來的值,代表ApplicationThread物件
callingPackage:由who.getBasePackageName()的值傳遞而來,who是Context物件,getBasePackageName()的實現在ContextImple中,返回當前啟動類的包名,就是Launcher的包名
resolvedType:解析當前傳送的Intent的MIME資料型別,本案例沒有為intent設定type、data屬性,因此,intent.resolveTypeIfNeeded(who.getContentResolver())返回null
resultTo:Ibinder物件,具體含義後面繼續看
resultWho:由target != null ? target.mEmbeddedID : null得來,target是activity物件即啟動類Launcher物件,不為空,該語句返回mEmbeddedID,一個id號,這個值必須要從Launcher這個apk啟動中獲得,在Launcher啟動後,代表Launcher啟動類的物件是一個ActivityClientRecord物件,該物件所屬的類路徑為:
frameworks\base\core\java\android\app\ActivityThread.java
該物件的scheduleLaunchActivity方法中,有一句:
ActivityClientRecord r = new ActivityClientRecord();
在ActivityClientRecord的構造方法中會把embeddedID初始化為null,因此mEmbeddedID為空
startFlags:整型值,已經初始化為0,具體作用後面分析
profilerInfo:為null,具體作用後面分析
這些引數都會被打包到持久化類Parcel的物件data中,把data作為transact的引數進行跨程序傳遞:
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
該方法通過binder通訊機制會傳遞到ActivityManagerNative的onTransact方法,在onTransact方法中,根據傳送命令START_ACTIVITY_TRANSACTION找到case處理語句,把data中的資料取出來賦給相應的變數,繼續呼叫:
1 2 | intresult=startActivity(app,callingPackage,intent,resolvedType, resultTo,resultWho,requestCode,startFlags,profilerInfo,options); |
startActivity最終會呼叫到服務端ActivityManagerService中。此時,程序也從啟動類Launcher所在的程序切換到了服務端程序。從ActivityManagerNative.getDefault().startActivity一直到ActivityManagerService的startActivity方法,主要由binder通訊實現,該過程相當複雜,但binder通訊不屬於本文重點,而且binder機制貫穿於整個Android系統、核心、驅動部分,本文如再遇到binder通訊機制,直接給出最終被呼叫的類及方法。
在進入到服務端之前,看看客戶端到底做了哪些工作?
主要是獲得了一些必要的引數:IApplicationThread物件、啟動類包名、Intent的MIME資料型別、IApplicationToken.Stub型別物件resultTo等,除了這些,沒有其他特殊的操作了,其實最關鍵的操作還是在服務端進行的,這就是為何本文一開始提到無論哪種啟動方式,客戶端都是大同小異。
framework層服務端
過程4 frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
startActivity—->startActivityAsUser—->mStackSupervisor.startActivityMayWait
1 2 3 | mStackSupervisor.startActivityMayWait(caller,-1,callingPackage,intent, resolvedType,null,null,resultTo,resultWho,requestCode,startFlags, profilerInfo,null,null,options,userId,null,null); |
這幾步沒有太多的操作,獲得了一個使用者id,用來作一些檢測
過程5 frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
1 2 3 4 5 6 7 8 | finalintstartActivityMayWait(IApplicationThread caller,intcallingUid, StringcallingPackage,Intent intent,StringresolvedType, IVoiceInteractionSession voiceSession,IVoiceInteractor voiceInteractor, IBinder resultTo,StringresultWho,intrequestCode,intstartFlags, ProfilerInfo profilerInfo,WaitResult outResult,Configuration config, Bundle options,intuserId,IActivityContainer iContainer,TaskRecord inTask){ ...... } |
先看多了哪些引數:
voiceSession:IVoiceInteractionSession物件型別,被初始化null。IVoiceInteractionSession本是一個aidl遠端介面,定義了任務棧啟動taskStarted、任務棧結束taskFinished等方法
voiceInteractor:IVoiceInteractor物件型別,被初始化為null。IVoiceInteractor也是一個aidl遠端介面
outResult:WaitResult物件型別,被初始化為null。WaitResult是IActivityManager的內部類,實現了Parcelable介面,主要用來儲存啟動Activity後返回的結果資訊
config:Configuration物件型別,被初始化為null。Configuration描述了所有裝置相關的配置資訊,比如,本地語言、螢幕大小、螢幕方向、輸入法模式,可以通過Resources的getConfiguration獲得改物件
iContainer:IActivityContainer物件型別,被初始化為null。IActivityContainer也是一個aidl遠端介面
inTask:TaskRecord物件型別,被初始化為null。TaskRecord很重要,會經常用到此類,描述一個任務棧,每個任務棧可以包含多個Activity物件,每個TaskRecord物件都有一個當前棧ActivityStack的引用,每個棧可以對應多個TaskRecord物件
除了這些多餘的引數,其他引數都是從客戶端傳遞而來。
1 | booleancomponentSpecified=intent.getComponent()!=null; |
getComponent方法返回一個ComponentName物件,該物件表示通過intent要啟動的元件類,本案例就對應A這個Activity,ComponentName物件一般用包名和類名標識一個元件,因此,componentSpecified為true
1 | intent=newIntent(intent); |
根據客戶端傳遞過來的Intent物件重新構建一個Intent物件,這樣做是不要破壞客戶端傳遞來的Intent物件
1 2 3 4 5 6 7 | ActivityInfo aInfo=resolveActivity(intent,resolvedType,startFlags, profilerInfo,userId); ActivityInfo resolveActivity(Intent intent,StringresolvedType,intstartFlags, ProfilerInfo profilerInfo,intuserId){ ...... } |
resolveActivity方法開始解析Intent物件,返回intent對應的目標Activity類的ActivityInfo物件,ActivityInfo類專門用來描述AndroidManifest.xml中Activity、Receiver元件資訊的,本案例返回的就是A這個類對應的資訊,ActivityInfo的成員變數name就是類名稱,packageName就是包名稱,對應本案例分別為com.example.startapptest.A和com.example.startapptest
1 2 3 4 5 6 7 8 | if(callingUid>=0){ callingPid=-1; }elseif(caller==null){ callingPid=realCallingPid; callingUid=realCallingUid; }else{ callingPid=callingUid=-1; } |
callingUid傳過來時為-1,call又不為空,程序執行else字句callingPid = callingUid = -1;
1 2 3 4 5 6 7 8 | ActivityContainer container=(ActivityContainer)iContainer; finalActivityStack stack; if(container==null||container.mStack.isOnHomeDisplay()){ stack=getFocusedStack(); }else{ stack=container.mStack; } |
iContainer為空,那麼container也為空,呼叫getFocusedStack獲得當前正在前臺的棧,也就是Launcher所在的棧。
1 2 3 4 | if(aInfo!=null&& (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE)!=0){ ...... } |
aInfo雖然不為空,但aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE卻為0,因為沒有設定這種屬性,因此跳過該if語句,開始執行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | intres=startActivityLocked(caller,intent,resolvedType,aInfo, voiceSession,voiceInteractor,resultTo,resultWho, requestCode,callingPid,callingUid,callingPackage, realCallingPid,realCallingUid,startFlags,options, componentSpecified,null,container,inTask); finalintstartActivityLocked(IApplicationThread caller, Intent intent,StringresolvedType,ActivityInfo aInfo, IVoiceInteractionSession voiceSession,IVoiceInteractor voiceInteractor, IBinder resultTo,StringresultWho,intrequestCode, intcallingPid,intcallingUid,StringcallingPackage, intrealCallingPid,intrealCallingUid,intstartFlags,Bundle options, booleancomponentSpecified,ActivityRecord[]outActivity,ActivityContainer container, TaskRecord inTask){ ...... } |
callingPid:int型變數,看字面意思與pid相關,具體含義後面再看
callingUid:int型變數,看字面意思與uid相關,具體含義後面再看
realCallingPid:啟動類所在程序的pid,本案例是Launcher
realCallingUid:啟動類所在程序的uid,本案例是Launcher
componentSpecified:為true,表明intent對應的目標Activity類存在
outActivity:ActivityRecord陣列名稱,初始化為null,ActivityRecord是一個動態生成的物件,代表Activity在歷史棧中的記錄,ActivityRecord包含了Activity所有資訊。
1 2 3 4 5 6 7 8 9 10 11 12 13 | ProcessRecord callerApp=null; if(caller!=null){ callerApp=mService.getRecordForAppLocked(caller); if(callerApp!=null){ callingPid=callerApp.pid; callingUid=callerApp.info.uid; }else{ Slog.w(TAG,"Unable to find app for caller "+caller +" (pid="+callingPid+") when starting: " +intent.toString()); err=ActivityManager.START_PERMISSION_DENIED; } } |
相關推薦
啟動Activity的流程(Launcher中點選圖示啟動)
啟動Activity一般有多種方式,常見的有三種: 在Launcher桌面點選app圖示 呼叫startActivity啟動一個Activity 命令am start啟動 這三種方式在服務端的處理方式基本相同,客戶端的請求方式也差別
Activity啟動流程【從Launcher點選圖示】和【在Activity中呼叫startActivity()】
從Launch程序啟動Application及Activity Android系統是基於Linux的,所以它的所有應用也是基於Linux的Init程序創建出來的, 首先Init程序啟動Zygote(受精卵)程序,然後再fork出其他程序(包括SystemServer),最後開
android 從點選圖示到啟動Activity的流程
一、前期準備 1.一些概念的介紹 ActivityManagerServices,簡稱AMS,服務端物件,負責系統中所有Activity的生命週期 ActivityThread,App的真正入口。當開啟App之後,會呼叫main()開始執行,開啟訊息迴圈佇列,這就是傳說
解決:Android App 在執行時候按下 home 鍵,讓App 在後臺執行,點選圖示再次進入時防止應用重新啟動
一:app 退出時,讓 app 在後臺執行,類似於 home 鍵的功能,最小化 重寫 onkeydown 和 onBackPressed 方法,主要是 movetoBack 方法。 注意在 MainA
AMS之開機啟動Launcher、開機廣告後啟動Launcher、Launcher啟動activity
activity的啟動關閉最終都是由AMS控制的。從刷了rom到第一開機引導、launcher啟動、點選啟動特定app,這之間ams控制開機引導activity、launcher、app啟動有什麼不同嗎?還是same流程?下面讓我們一探究竟。文章分三部分:第一部總體概述、第二
android關於每次點選圖示進入應用後都會重新建立啟動頁的問題
android關於每次點選圖示進入應用後都會重新建立啟動頁的問題 原創 2017年07月26日 11:49:21 標籤: android / 啟動模式 932
Android Launcher分析和修改9——Launcher啟動APP流程
本來想分析AppsCustomizePagedView類,不過今天突然接到一個臨時任務。客戶反饋說機器介面的圖示很難點選啟動程式,經常點選了沒有反應,Boss說要優先解決這問題。沒辦法,只能看看是怎麼回事。今天分析一下Launcher啟動APP的過程。從使用者點選到程式啟動的流程,下面針對WorkSpac
app切換到後臺,點選圖示快速啟動
專案中發現切換到後臺,點選圖示,載入比較慢。 在網上找到解決方法。 第一步: 找到入口activity,設定其為standard。 第二步: 在你的app的AndroidManifest.xml檔案的
Android 點選圖示使APP由後臺切換至前臺重新啟動歡迎頁的問題
問題:當我們的APP切到後臺執行時,點選桌面的應用圖示使APP重新回到前臺,此時APP會重新啟動歡迎頁。 但是我們並不需要這種操作,我們需要直接把APP切至前臺。 解決:我們只需要在歡迎頁的onCr
launcher 啟動應用流程簡述
在Launcher程序中,首先呼叫startActivity(),然後呼叫startActivityForResult(),然後呼叫到Instrumention的execStartActivity(),
Android應用返回桌面後,每次點選圖示,啟動介面都會出現
現象描述 通過QQ或者微信下載App並安裝 點選Home鍵返回Launch介面 點選安裝好的軟體圖示 發現軟體再次出現啟動介面 原因分析 解決辦法 新建一個程式入口Activity /** * 這個類的職責是: * 解決從QQ等第三方平臺安裝後
呼叫startActivityForResult啟動activity,返回當前頁不響應的問題(附帶activity攜帶引數流程)
最近在專案遇到這樣一個問題,原始的activity不是為我寫,後面我要改成返回activity攜帶引數。我改好了之後 發現不能呼叫onActivityResult。除錯也沒有問題,activity結束
如何找到Android app啟動activity和頁面元素信息
dump ref adg 按鈕 配置環境變量 好的 too 啟動app ace 在實施app自動化的時候,我們需要知道app 的啟動activity和頁面元素信息,以此啟動app和定位頁面元素,那麽如何在沒有源碼的情況下找打他們呢?當然是有好的工具啦,有Android sd
手把手教你_怎麽找android應用的包名和啟動activity
color don dsm too key 包名 ani 一個 col 自己主動化測試中常常遇到這個問題,關於這個題目,方法眾多,咱的目的是找個比較簡單靠譜的: 方法一: 先進入cmd窗體,adb shell 後: cd /data/d
Linux系統啟動了流程
linux開機開機自檢(BIOS)MBR引導(光盤、磁盤)GRUB菜單(選擇內核,一般只有一個內核)加載內核運行init進程,選擇運行級別(Linux的第一個運行程序)讀取/etc/inittab配置文件執行/etc/rc.d/rc.sysinit腳本(系統的初始化腳本,設置主機名和IP地址)執行/etc/r
啟動activity的標準的action常量及對應的字符串
nbsp alt .cn img 字符串 9.png 字符 技術分享 cti 啟動activity的標準的action常量及對應的字符串
activity的生命周期和啟動模式
發生 完成 nbsp 本質 top 但是 可見 自動 res 1.常見生命周期說明 2.兩個常見問題 問題一答案:本質上就是onstart和onstop方法是是否可見進行調用,而onresume和onpause是看是否為前臺互動而調用。 問題二答案:先
Android 跨進程啟動Activity黑屏(白屏)的三種解決方案
orien 但是 解決 icon draw lun 簡單 android基礎 分享 原文鏈接:http://www.cnblogs.com/feidu/p/8057012.html 當Android跨進程啟動Activity時,過程界面很黑屏(白屏)短暫時間(幾百毫秒?)。
Weblogic安裝啟動流程及免密後臺啟動
con sof util ack change tab roo 正在 default Weblogic安裝啟動流程一、安裝步驟: 1.啟動安裝程序:$ <YOUR_JAVA_HOME>/bin/java -jar -Xmx1200m wls1211_generi
CentOS5、6、7啟動具體流程
CentOS5 啟動 具體流程 CentOS5、6系統的啟動流程基於Intel X86架構平臺的系統啟動流程:1.POST:Power-On Self Testing,加電自檢;CMOS:在這裏面有一個EPROM,可擦寫可編程的只讀存儲器;在這裏面保存了一小段程序叫做BIOS程序,全稱為Basic