編輯:Android編程入門
轉載請注明出處:http://hovertree.com/
先介紹下Android對Activity的管理,Android采用Task來管理多個Activity,當我們啟動一個應用時,Android就會為之創建一個Task,然後啟動這個應用的入口Activity(即<intent-filter.../>中配置為 MAIN和LAUNCHER的Activity)。
因為Android並沒有為Task提供API,因此我們無法真正去訪問Task,只能調用Activity的getTaskId()方法來獲取它所在的Task的ID。事實上我們可以把Task理解成Activity棧,Task以棧的形式來管理Activity:先啟動的Activity被放在Task棧底,後啟動的Activity被放在Task棧頂。
那麼Activity的加載模式,就負責管理實例化、加載Activity的方式、並可以控制Activity與Task之間的關系。
Activity有4中啟動模式,分別為:standard,singleTop,singleTask,singleInstance。如果要使用這四種啟動模式,必須在manifest文件中<activity>標簽中的launchMode屬性配置,如:
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="standard"
>
</activity>
standard
標准啟動模式,也是Android的默認啟動模式。在這種模式下啟動的activity可以被多次實例化,即在一個任務中可以存在多個activity實例,每個實例都會處理一個Intent對象。如果Activity A的啟動模式為standard,並且A已經啟動,在A中再次啟動Activity A,即調用startActivity(new Intent(this,A.class)),會在A的上面再次啟動一個A的實例,即當前的棧中的狀態為A-->A。
singleTop
如果一個以singleTop模式啟動的activity的實例已經存在於任務棧的棧頂,那麼再次啟動這個activity時,不會創建新的實例,而是重用位於棧頂的那個實例,並且會調用該實例的onNewIntent()方法將Intent對象傳遞到這個實例中。舉例來說,如果A的啟動模式為singleTop,並且A的一個實例已經存在於棧頂中,那麼再調用startActivity(new Intent(this,A.class))啟動A時,不會再創建A的實例,而是重用原來的實例,並且調用原來實例的onNewIntent()方法。這時任務棧中還是有一個A的實例。
如果以singleTop模式啟動的activity的一個實例已經存在於任務棧中,但是不在棧頂,那麼它的行為和standard模式相同,也會創建多個實例。
singleTask
官方文檔上稱,如果一個activity的啟動模式為singleTask,那麼系統總會在一個新的任務的最底部(root)啟動這個activity,並且被這個activity啟動的其它activity會和該activity同時存在於這個新任務中。如果系統中已經存在一個這樣的activity則會重用這個實例,並且調用它的onNewIntent()方法。即,這樣的一個activity在系統中只會存在一個實例。
但是這種說法並不准確,采用singleTask啟動目標Activity時,可分三種情況:
1、如果將要開啟的目標Activity不存在,系統將會創建目標Activity實例,並將它放入Task棧頂。
2、如果將要啟動的目標Activity已經位於Task棧頂,此時與singleTop模式的行為相同。
3、如果將要啟動的目標Activity已經存在、但沒有位於Task棧頂,系統將會把位於該Activity上面的所有Activity移出Task棧,從而使得目標Activity轉入棧頂。
下面通過實例說明:
兩個Activity,FirstActivity顯示文本框和按鈕,該按鈕用於啟動SecondActivity;SecondActivity顯示文本框和按鈕,該按鈕用於啟動FirstActivity。
public class FirstActivity extends Activity { TextView tv; Button btn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv=(TextView) findViewById(R.id.tv); tv.setText("Activity為:"+this.toString()+",Task ID為:"+this.getTaskId()); btn=(Button) findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent(FirstActivity.this, SecondActivity.class); startActivity(intent); } }); } }
public class SecondActivity extends Activity { TextView tv; Button btn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); tv=(TextView) findViewById(R.id.tv); tv.setText("Activity為:"+this.toString()+",Task ID為:"+this.getTaskId()); btn=(Button) findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent(SecondActivity.this, FirstActivity.class); startActivity(intent); } }); } }
運行該實例,系統默認啟動FirstActivity,點擊該界面按鈕,系統以singgleTask模式打開SecondActivity ,此時Task棧中有兩個Activity(從底向上):FirstActivity-->SecondActivity.
點擊SecondActivity界面按鈕,系統以標准模式再次啟動FirstActivity,此時Task棧中有三個Activity(從底向上):FirstActivity-->SecondActivity-->FirstActivity.
在FirstActivity中再次點擊按鈕,系統以singleTask模式再次打開SecondActivity,系統會將位於SecondActivity上面的所有Activity移出,使得SecondActivity進入棧頂,此時Task棧中只有兩個Activity(從底向上):FirstActivity-->SecondActivity.
效果圖(依次):
singleInstance
總是在新的任務中開啟,並且這個新的任務中有且只有這一個實例,也就是說被該實例啟動的其他activity會自動運行於另一個任務中。當再次啟動該activity的實例時,會重用已存在的任務和實例。並且會調用這個實例的onNewIntent()方法,將Intent實例傳遞到該實例中。和singleTask相同,同一時刻在系統中只會存在一個這樣的Activity實例。
說明:
這種加載模式下,系統保證無論從哪個Task中啟動目標Activity,只會創建一個目標Activity實例,並會使用一個全新的Task棧來裝載該Activity實例。
當用singleInstance啟動目標Activity時,分兩種情況:
1、當將要啟動的目標Activity不存在,系統會先創建一個全新的Task、再創建目標Activity的實例,並將它加入新的Task的棧頂。
2、如果將要啟動的目標Activity已經存在,無論它位於哪個應用程序中,無論它位於哪個Task中,系統將會把該Activity所在的Task轉到前台,從而使用該Activity顯示出來。
采用該模式加載的Activity總是位於Task棧頂,所在Task只包含該Activity.
舉例說明:
點擊FirstActivity中按鈕,啟動SecondActivity。SecondActivity配置成singleInstance加載模式,export屬性配置成true---表明該Activity可被其它應用啟動。
public class FirstActivity extends Activity { TextView tv; Button btn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv=(TextView) findViewById(R.id.tv); tv.setText("Activity為:"+this.toString()+",Task ID為:"+this.getTaskId()); btn=(Button) findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent(FirstActivity.this, SecondActivity.class); startActivity(intent); } }); } }
<activity android:name=".SecondActivity" android:launchMode="singleInstance" android:exported="true" > <intent-filter> <!--知道該Activity能響應Action為指定字符串的Intent --> <action android:name="joanna.yan.action.TEST_ACTION" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
系統啟動新的Task並用新的Task加載新創建的SecondActivity實例,SecondActivity總是位於棧頂。
效果圖:
另一個示例采用隱式Intent再次啟動該SecondActivity。
代碼:
public class OtherActivity extends Activity { TextView tv; Button btn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); tv=(TextView) findViewById(R.id.tv); tv.setText("Activity為:"+this.toString()+",Task ID為:"+this.getTaskId()); btn=(Button) findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent(); intent.setAction("joanna.yan.action.TEST_ACTION"); startActivity(intent); } }); } }
單擊OtherActivity中的按鈕隱式啟動singleInstance模式的SecondActivity,如果前面一個示例還未退出,無論SecondActivity所在Task是否位於前台,系統將再次把SecondActivity所在Task轉入前台,從而將SecondActivity顯示出來。
效果圖:
Android其本質就是在標准的Linux系統上增加了Java虛擬機Dalvik,並在Dalvik虛擬機上搭建了一個JAVA的application framework,
下一篇本文演示用Android Studio寫一個最簡單的輸入法。界面和交互都很簡陋,只為剔肉留骨,彰顯寫一個Android輸入法的要點。1、打開Android Stud
Camera的架構與Android系統的整體架構保持一致,如下圖所示,本文主要從以下四個方面對其進行說明。 Framework:Camera.java Android
項目裡要用到開獎公告,單行顯示向上滾動的TextView,網上隨便找了一個控件發現效果還不錯改裝一下就可以用到項目裡。唯一不妥的地方就是字體大小不太好控制,不是正常的字體