編輯:關於Android編程
有這樣的場景:
當我們使用App的時候,呈現出一個Activity,按下返回鍵(不考慮重寫返回鍵事件),常常就回退到上一個打開的Activity或者退出App。
//重寫返回按鍵事件
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
// 這裡重寫返回鍵
return true;
}
return false;
}
幾個應用之間,例如我的App要使用拍照功能,我需要調用系統的相機App,這分明就是兩個不同的應用程序,分別運行在不同的進程,但是當我調用完成相機後,按下返回鍵可以返回我的App
//調用相機
private void openCamera() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
uri = PhotoUtil.createImageFile();
if (takePictureIntent.resolveActivity(mContext.getPackageManager()) != null) {// 相機被卸載時不會崩潰
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAMERA);
}
}
還有例如在我們的App打開浏覽器、微博之類的應用,然後跳轉到浏覽器,使用完成浏覽器的功能,不斷按下返回鍵,可以回到我們的應用。而不是像點擊桌面上浏覽器圖標啟動浏覽器那樣,不斷返回鍵,最後回到的是桌面。 生成重復頁面。任務棧Task,是一種用來放置Activity實例的容器,他是以棧的形式進行盛放,也就是所謂的先進後出,主要有2個基本操作:壓棧和出棧,其所存放的Activity是不支持重新排序的,只能根據壓棧和出棧操作更改Activity的順序。
啟動一個Application的時候,系統會為它默認創建一個對應的Task,用來放置根Activity。默認啟動Activity會放在同一個Task中,新啟動的Activity會被壓入啟動它的那個Activity的棧中,並且顯示它。當用戶按下回退鍵時,這個Activity就會被彈出棧,按下Home鍵回到桌面,再啟動另一個應用,這時候之前那個Task就被移到後台,成為後台任務棧,而剛啟動的那個Task就被調到前台,成為前台任務棧,手機頁面顯示的就是前台任務棧中的棧頂元素。
Activity默認模式,所有的Activity遵循元素進棧出棧的特性,例如進棧序列為A->B->C->D,D呈現在頁面上,按返回鍵出棧順序久違D->C->B->A.
在
棧頂復用模式,如果要開啟的activity在任務棧的頂部已經存在,就不會創建新的實例,而是調用 onNewIntent() 方法。避免棧頂的activity被重復的創建。
在開始處,我們提到的2個Bug,可以用這種模式解決
通知欄彈出Notification,點擊Notification跳轉到指定Activity,但是如果我現在頁面就停留在那個指定的Activity,會再次打開我當前的Activity,這樣返回的時候回退的頁面和當前頁面一樣,感官上就會很奇怪。
btnNotification.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
NoticationUtil.sendNotication(mContext);
}
});
public class NoticationUtil {
@SuppressLint("NewApi")
public static void sendNotication(Context context) {
// 在Android進行通知處理,首先需要重系統哪裡獲得通知管理器NotificationManager,它是一個系統Service。
NotificationManager manager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
new Intent(context, MainActivity.class), 0);
// 通過Notification.Builder來創建通知,注意API Level
// API16之後才支持
Notification notify = new Notification.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setTicker("您有新短消息,請注意查收!").setContentTitle("我是標題")
.setContentText("點我打開主頁").setContentIntent(pendingIntent)
.setNumber(1).build();
notify.flags |= Notification.FLAG_AUTO_CANCEL; // FLAG_AUTO_CANCEL表明當通知被用戶點擊時,通知將被清除。
manager.notify(1, notify);
}
}
修改為:
登錄成功跳轉到主頁,按下兩次登錄按鈕,生成了兩個主頁。一些有啟動延遲的頁面(往往是動畫,網絡造成)也會有這樣的情況。
btnLogin.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 延遲1000秒,模擬網絡超時
v.getHandler().postDelayed(new Runnable() {
@Override
public void run() {
// 登錄成功,跳轉到主頁
LoginSuccessActivity.actionStart(mContext);
}
}, 3000);
}
});
XML清單配置
把他修改為singleTop
還有一種場景 從activity A啟動了個service進行耗時操作,或者某種監聽,這個時候你home鍵了,service收集到信息,要返回activityA了,就用singleTop啟動,實際不會創建新的activityA,只是resume了。不過使用standard又會創造2個A的實例。
XML配置 MainActivitiy,Test2Activity為standard模式,Test1Activity為singleTask模式。
入棧情況:
MainActivity—>Test1Activity—>Test2Activity—>MainActivity,如果此時啟動Test1Activity,會清空Test1頂部元素 棧內情況變為MainActivity—>Test1Activity;
2. 主要就是在清單文件中配置android:taskAffinity="新的包名"
,因為android:taskAffinity
這個字段默認指定的包名為本應用的包名,表示在本應用包名的任務棧內創建應用。如果設置了這個字段,而且還和本應用包名不同,就會在新的任務棧創建任務。例如,修改剛才的代碼Test1Activity的配置清單:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;">
指定android:taskAffinity
包名為com.test.newlaunch
06-03 14:47:46.556: D/displayTask(22127): id:--69
06-03 14:47:46.556: D/displayTask(22127): numActivities:--1
06-03 14:47:46.556: D/displayTask(22127): topActivity:--com.example.testlaunch.aty.MainActivity
06-03 14:47:46.556: D/displayTask(22127): baseActivity:--com.example.testlaunch.aty.MainActivity
06-03 14:47:48.428: D/displayTask(22127): id:--69
06-03 14:47:48.428: D/displayTask(22127): numActivities:--2
06-03 14:47:48.428: D/displayTask(22127): topActivity:--com.example.testlaunch.aty.Test2Activity
06-03 14:47:48.428: D/displayTask(22127): baseActivity:--com.example.testlaunch.aty.MainActivity
06-03 14:47:50.080: D/displayTask(22127): id:--69
06-03 14:47:50.080: D/displayTask(22127): numActivities:--3
06-03 14:47:50.080: D/displayTask(22127): topActivity:--com.example.testlaunch.aty.MainActivity
06-03 14:47:50.080: D/displayTask(22127): baseActivity:--com.example.testlaunch.aty.MainActivity
06-03 14:47:55.164: D/displayTask(22127): id:--71
06-03 14:47:55.164: D/displayTask(22127): numActivities:--1
06-03 14:47:55.164: D/displayTask(22127): topActivity:--com.example.testlaunch.aty.Test1Activity
06-03 14:47:55.164: D/displayTask(22127): baseActivity:--com.example.testlaunch.aty.Test1Activity
06-03 14:47:56.688: D/displayTask(22127): id:--71
06-03 14:47:56.688: D/displayTask(22127): numActivities:--2
06-03 14:47:56.688: D/displayTask(22127): topActivity:--com.example.testlaunch.aty.Test2Activity
06-03 14:47:56.688: D/displayTask(22127): baseActivity:--com.example.testlaunch.aty.Test1Activity
06-03 14:47:58.140: D/displayTask(22127): id:--71
06-03 14:47:58.140: D/displayTask(22127): numActivities:--3
06-03 14:47:58.140: D/displayTask(22127): topActivity:--com.example.testlaunch.aty.MainActivity
06-03 14:47:58.140: D/displayTask(22127): baseActivity:--com.example.testlaunch.aty.Test1Activity
最開始的棧id為69,然後在06-03 14:47:55.164: D/displayTask(22127): topActivity:--com.example.testlaunch.aty.Test1Activity
Test1Activity啟動的時候又新建了一個棧id為71.同時在查看後台程序,看到出現了2個後台任務都是我們的應用—TestLanuch。
singleTask
模式,保證他只有一個唯一實例,節約內存同時按下返回鍵後的感官也更順暢。但是需要注意,提供給人調用的頁面最好是棧底元素。因為,如果自己的客戶端處於運行狀態,按下Home鍵後台掛起。此時如果使用如果其他應用(比如說QQ)調起自己的客戶端某個頁面,不做任何處理的情況下,按下回退或者當前 Activity.finish(),頁面都會停留在自己的客戶端(因為自己的Application回 退棧不為空),這明顯不符合邏輯的。
在其他應用 “我是QQ”中打開指定頁面Test1Activity
btnSkip.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction(".aty.Test1Activity");
try {
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
});
a. 模擬操作TestLanuch
b. 使用我是QQ打開TestLanuch的Test1Activity,然後按返回鍵退棧
要解決這個問題有兩種方式:
singleTask
清除這個activity任務棧上面所有的activity特性我們提供的分享頁面始終是我們棧底的元素,只要他一啟動就會清空任務棧內其他Activity,保證只有他一個實例。
例如在本應用真就設置:
這樣在Test1Activity啟動的時候,如果com.test.newlaunch
沒啟動就新建一個任務棧,如果com.test.newlaunch
啟動了就直接加入它的任務棧。
單一實例模式,整個手機操作系統裡面只有一個實例存在。不同的應用去打開這個activity 共享公用的同一個activity。他會運行在自己單獨,獨立的任務棧裡面,並且任務棧裡面只有他一個實例存在。應用場景:呼叫來電界面。這種模式的使用情況比較罕見,在Launcher中可能使用。或者你確定你需要使Activity只有一個實例。
可以得出以下結論:
1. 以singleInstance模式啟動的Activity具有全局唯一性,即整個系統中只會存在一個這樣的實例。
2. 以singleInstance模式啟動的Activity在整個系統中是單例的,如果在啟動這樣的Activiyt時,已經存在了一個實例,那麼會把它所在的任務調度到前台,重用這個實例。
3. 以singleInstance模式啟動的Activity具有獨占性,即它會獨自占用一個任務,被他開啟的任何activity都會運行在其他任務中。
4. 被singleInstance模式的Activity開啟的其他activity,能夠在新的任務中啟動,但不一定開啟新的任務,也可能在已有的一個任務中開啟。
換句話說,其實SingleInstance就是我們剛才分析的SingleTask中,分享Activity為棧底元素的情況。
在電商類app的購物車頁面,經常會有這樣的需求:長按“+”按鈕或者“-”按鈕時,購物車中的商品數量連續的增加或減少。本例的
方式一:自定義對話框 public class ProgersssDialog extends Dialog { private ImageView img;
根據Android官方提供給我們的Sample例子實實在在的分析Bitmap使用時候的注意點。在分析Bitmap的使用之前先簡單的了解下BitmapFactory 類,B
Android網絡編程之傳遞數據給服務器(二) 請尊重他人的勞動成果,轉載請注明出處:Android網絡編程之傳遞數據給服務器(二) 我曾在《Andr