編輯:關於Android編程
Activity作為四大組件,代碼中每定義一個Activity就需要在AndroidManifest.xml
文件中聲明它。
<code class="language-xml hljs "><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.anddle.activitytest"> <application android:icon="@mipmap/ic_launcher" android:label="@string/app_name"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"> <category android:name="android.intent.category.LAUNCHER"> </category></action></intent-filter> </activity> <activity android:name=".AlertActivity" android:theme="@android:style/Theme.Dialog"> </activity> </application> </manifest></code>
Activity標簽還有一些我們常用到的屬性。
這裡的intent-filter
標簽內指定的內容表示:這個Activity可以作為這個應用程序的入口。
<code class="language-xml hljs "><activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"> <category android:name="android.intent.category.LAUNCHER"> </category></action></intent-filter> </activity></code>
直觀一點,就是說它可以被放在桌面上,供用戶通過點擊直接進入。假如一個應用有三個這樣的Activity,那麼桌面上將有三個圖標,供用戶點擊啟動。
指定Activity的主題。安卓系統為界面元素設計了幾種不同的顯示風格,叫做主題。關於主題的詳細介紹我們將放在以後的章節。
android:theme="@android:style/Theme.Dialog">
指定Activity的啟動方式。啟動方式在下一小節詳細講述。
android:launchMode="standard">
指定Activity是否關注系統配置的變化,
android:configChanges="screenSize|orientation">
響應特定的Action
,遇到這樣的Action
就可以啟動該Activity,
那麼,啟動該Activity的代碼,就可以通過它配置中的Action
,
Intent i = new Intent("android.intent.action.VIEW");
startActivity(i);
除了以上列出的一些屬性外,Activity的很多特性都可以這樣設置。
Activity的啟動模式,就是指當用戶或者系統啟動一個Activity時,將這個Activity如何放到Task中進行管理。
android:launchMode="standard">
Activity有四種啟動方式:standard、singleTop、singleTask、singleInstance。
這是每個Activity默認的啟動模式,如果我們沒有在manifest中指定,那麼Activity啟動就會采用這個模式。這個模式很簡單,原則只有一個:當啟動這種類型的Activity時,只要重新創建,然後放在Task棧的棧頂就好了。
進一步舉個例子:Activity A上,有一個按鈕,點擊後,可以再啟動一個Activity A。這時我們看到的Task堆棧情況就是,Activity A上又創建了一個Activity A。這兩個Activity都是Activity A的實例,是互相獨立的Activity,在內存中有各自的一塊區域。
這個啟動模式的原則是:當啟動這個類型的Activity時,如果這個Activity有實例在當前Task中存在,並且位於這個Task的棧頂,那麼就調用onNewIntent()通知一下,而不用重新創建;
否則,即使這個Task中有這個Activity實例,只要它不在棧頂,就重新創建;
使用場景:一個新聞客戶端會接收新聞推送,在statusbar上顯示已經收到10條推送了。當我們點擊第一條的時候,啟動一個顯示新聞內容的Activity-ContentActivity,當我們點擊statusbar上的第二條新聞時,再次啟動ContentActivity。如果ContentActivity是standard模式,可以想見,在之前的新聞內容上,又回彈出一個Activity,10條推送點擊十次,就會有10個Activity疊在一起。
麻煩的是返回時得按10次,而且會占用很多系統資源。
如果將ContentActivity指定為singleTop,那麼點擊後面9條推送時,ContentActivity只會通過onNewIntent()知道有新的調用請求,不必重新創建9個Activity實例過份消耗資源。
這個啟動模式的原則是:當啟動這個類型的Activity時,先查看這個Activity是否有實例在系統當前的Task中存在。
如果它在位於前台的task中存在,並且位於這個Task的棧頂,那麼就調用onNewIntent()
通知一下,而不用重新創建--這一點與singleTop模式類似;
如果存在,但是不在Task的棧頂,就將這個Activity上面別的Activity全部彈出、銷毀,把這個Activity的實例放到最上面,再用onNewIntent()
通知它一次。
如果它在位於後台的task中存在,就把後台task放到前台來,然後把它上面存在的別的Activity彈出、銷毀。
使用場景:應用的主Activity A,可以啟動Activity B, Activity B又能啟動Activity C,C又能啟動D,設計者希望從D能夠直接返回到主Activity。
對於這種希望在任意層級的Activity下,快速返回到主界面的應用,就可以把主Activity A設置成singleTask模式。
這個啟動模式的原則是:當啟動這個類型的Activity時,如果該Activity之前並不存在,就會重新創建一個Task,並把該Activity放入其中。假如這個Activity要啟動別的Activity-C,那麼就放在之前那個Task之上。
如果該Activity已經存在,就把該Activity所在的task切換到前台來。
總之,一個task中有且只有一個這種類型的Activity。
使用場景:對於那種需要提供給第三方調用的Activity,例如微信的分享、轉發,就可以把這種Activity設置成singgleInstance。這樣在系統范圍內保證只有一個這樣的Activity存在。
為了幫助我們深入學習Activity,這裡介紹通過ADB工具獲取系統中現有Activity信息的方法。
用命令行工具進入adb所在的目錄,
輸入adb shell dumpsys activity activities
,會輸出類似如下的內容:
$ ./adb shell dumpsys activity activities
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
Stack #0:
Task id #178
* TaskRecord{cce8184 #178 I=com.android.launcher3/.Launcher U=0 sz=1}
userId=0 effectiveUid=u0a8 mCallingUid=0 mCallingPackage=null
intent={act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000000 cmp=com.android.launcher3/.Launcher}
realActivity=com.android.launcher3/.Launcher
autoRemoveRecents=false isPersistable=true numFullscreen=1 taskType=1 mTaskToReturnTo=0
rootWasReset=false mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
Activities=[ActivityRecord{b820c49 u0 com.android.launcher3/.Launcher t178}]
askedCompatMode=false inRecents=true isAvailable=true
lastThumbnail=null lastThumbnailFile=/data/system/recent_images/178_task_thumbnail.png
stackId=0
hasBeenVisible=true mResizeable=false firstActiveTime=1451983947131 lastActiveTime=1451983947131 (inactive for 2501s)
* Hist #0: ActivityRecord{b820c49 u0 com.android.launcher3/.Launcher t178}
packageName=com.android.launcher3 processName=com.android.launcher3
launchedFromUid=0 launchedFromPackage=null userId=0
app=ProcessRecord{f7b8d6d 25040:com.android.launcher3/u0a8}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000000 cmp=com.android.launcher3/.Launcher }
frontOfTask=true task=TaskRecord{cce8184 #178 I=com.android.launcher3/.Launcher U=0 sz=1}
taskAffinity=null
realActivity=com.android.launcher3/.Launcher
baseDir=/system/priv-app/Launcher3/Launcher3.apk
dataDir=/data/user/0/com.android.launcher3
stateNotNeeded=true componentSpecified=false mActivityType=1
compat={420dpi} labelRes=0x7f0c0005 icon=0x7f030000 theme=0x7f0e000e
config={1.0 310mcc260mnc zh_CN ldltr sw411dp w411dp h659dp 420dpi nrml port finger qwerty/v/v dpad/v s.6}
stackConfigOverride={1.0 ?mcc?mnc ?locale ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}
taskDescription: iconFilename=null label="null" color=ff212121
launchFailed=false launchCount=1 lastLaunchTime=-41m41s66ms
haveState=false icicle=null
state=RESUMED stopped=false delayedResume=false finishing=false
keysPaused=false inHistory=true visible=true sleeping=false idle=true
fullscreen=true noDisplay=false immersive=false launchMode=2
frozenBeforeDestroy=false forceNewConfig=false
mActivityType=HOME_ACTIVITY_TYPE
waitingVisible=false nowVisible=true lastVisibleTime=-41m39s31ms
Running activities (most recent first):
TaskRecord{cce8184 #178 I=com.android.launcher3/.Launcher U=0 sz=1}
Run #0: ActivityRecord{b820c49 u0 com.android.launcher3/.Launcher t178}
mResumedActivity: ActivityRecord{b820c49 u0 com.android.launcher3/.Launcher t178}
mFocusedActivity: ActivityRecord{b820c49 u0 com.android.launcher3/.Launcher t178}
mFocusedStack=ActivityStack{c009da2 stackId=0, 1 tasks} mLastFocusedStack=ActivityStack{c009da2 stackId=0, 1 tasks}
mSleepTimeout=false
mCurTaskId=178
mUserStackInFront={}
mActivityContainers={0=ActivtyContainer{0}A}
mLockTaskModeState=NONE mLockTaskPackages (userId:packages)=
0:[]
mLockTaskModeTasks[]
它記錄下了當前安卓系統中所有的Task,以及每個Task中包含的Activity信息。
例如這裡記錄了,
系統中有一個Task id
為#178
的Task
; Task
棧中的Activity,從上到下依次是TaskRecord---com.android.launcher3/.Launcher
,一個Activity
; 並且com.android.launcher3/.Launcher
這個Activity
是位於前台的Activity
;
這些信息對程序的調試會有很大的幫助。
用ADB工具啟動已知Activity,
$ ./adb shell am start -n 包名/包名.activity名稱}
這裡的包名就形如:com.android.launcher3,例如
$ ./adb shell am start -n com.android.launcher3/com.android.launcher3.Launcher}
這張圖簡單說明了Zygote的啟動過程下面重點解析這些函數,從app_process.main開始 int main(int argc, char* const
第三課(第三步):支持以手指觸控的任意點為中心開始縮放關鍵部分是在縮放的時候不斷進行邊界檢測,防止放大後縮小後出現白邊: /** * 在縮放的時候進行邊界控制
使用EditText的addTextChangedListener(TextWatcher watcher)方法對EditText實現監聽,TextWatcher是一個接
小米5尊享版和標准版有什麼區別?備受期待的小米手機5於2月24日發布,推出了三個版本,分別是標准版、高配版和尊享版,標准版和高配版僅在內存上有不同,而尊享版