二月 252012
 

(2013-04-15 更新)上一篇文章Android TabHost Without TabActivity提到如何以Activity取代過期的TabActivity來操作TabHost,官方文件中建議以Fragment取代TabActivity,但小蛙還沒試出來使用Fragment的方式(同事盛哥那邊有試出來,之後徵詢盛哥同意後再把Fragment的做法分享出來),小蛙在這邊記錄使用Activity + TabHost + 頁籤中切換Activity,並且保存各個頁籤的Back Stack。注意:官方建議使用Fragment,除非是想跟小蛙一樣懶惰到不想動到整體架構,想要進行「最少修改」,還是聽從官方建議使用Fragment比較好喔!

上個星期跟盛哥試了一段時間使用Fragment後還是不得其門而入(兩個人對Fragment都還不太熟悉),卡住的原因是現在有兩個Tab,當Tab1進入到第二個畫面,Tab2進到第三個畫面,但使用者切回Tab1的時候,Tab1的狀態無法被保留(第二畫面),這個影響就是如果使用者透過Tab1已經搜尋到想要的資料後,因為某些原因切到Tab2,這時候想點回Tab1時,資料卻已經消失,這對使用者體驗來說是非常差的。

前天看到盛哥留言已經解決了上述問題,而在看到盛哥解決之前,小蛙也在
Android: TabActivity Nested Activities @ Henrik Larsen Toft
Android : How to have multiple activities under a single tab of TabActivity @ GammaPoint
這兩篇文章中找到曙光,要讓Activity彼此切換,在這邊使用到了ActivityGroup去管理各個Activity切換的動作,並且額外設置了一個ArrayList<View> history當作Back Stack來使用。但小蛙照著做卻還是沒辦法使用,所以修改了一些東西。

做法從上圖可以看得出來(也有可能畫得太爛造成大家看不太懂),首先小蛙在MainActivity中建立了3個Tab,分別是Tab1、Tab2、Tab3,而Tab1中會有兩次切換Activity的動作(既然是兩次為什麼會有3個Activity?等等後面小蛙會說明),以此類推Tab2也相同,Tab3則是很單純的直接顯示一個Activity7。

會使用到同一頁籤中切換Activity的所有Activity都必須透過ActivityGroup來做管理,也就是圖中的Activity1、Activity2、Activity3都是可以透過ActivityGroup1來管理,同理可說明ActivityGroup2,每個ActivityGroup又另外設置了個別的Back Stack來管理當使用者按下Back鍵時的行為(例如:該退出程式還是回到上一個Activity、切換Tab時該Tab原本停留的狀態),至於Activity7因為只有單一頁面所以不需要這麼麻煩。介紹完架構家族之後,進到程式碼的部份。

承上篇文章Android TabHost Without TabActivity,在MainActivity中的TabHost加入頁籤。

mHost.addTab(mHost.newTabSpec(getString(R.string.tab_two_name))
                .setIndicator(getString(R.string.tab_two_name))
                .setContent(new Intent(this, ActivityGroup1.class)));

小蛙在測試了上面兩篇文章的方法後發現,必須要在ActivityGroup1中直接先載入Activity1(也就是ActivityGroup僅用來"操作"這些Activity,並沒有實質的內容呈現,如果讓ActivityGroup在這邊有自己的內容呈現,會造成Back Stack運作錯誤,也有可能是小蛙實作上出了問題,如果照著上面兩篇文章試不出來的網友,不妨參照小蛙的做法),以下是ActivityGroup1的程式碼:

public class ActivityGroup1 extends ActivityGroup{
    /** 設定成 static 讓其他的子 Activity 可以存取 */
    public static ActivityGroup1 group;
    /** Back Stack */
    private ArrayList<View> history;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.history = new ArrayList<View>();
        group = this;

        // ActivityGroup1 只是一個外框,在這個外框中載入其他要用的 Activity
        // 如果沒有這個外框會發生錯誤
        View view = getLocalActivityManager()
                  .startActivity("Activity1",
                                  new Intent(ActivityGroup1.this, Activity1.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP))
                  .getDecorView();
        // 馬上載入真正要執行的 Activity
        replaceView(view);
    }

    /**
     * 在 ActivityGroup 中切換 Activity
     * @param v
     */
    public void replaceView(View v) {
        // 可在這插入換頁動畫
        history.add(v);
        setContentView(v);
    }

    /**
     * 當使用者按下 back 的時候,把之前存起來的 stack 撈回來顯示
     */
    public void back() {
        // 原本的範例是寫 > 0,但會發生錯誤
        if(history.size() > 1) {
            history.remove(history.size()-1);
            View v = history.get(history.size()-1);
            // 可在這插入換頁動畫
            setContentView(v);
        }else {
            // back stack 沒有其他頁面可顯示,直接結束
            finish();
        }
    }
    /**
     * 複寫聆聽按下 back 事件,呼叫 back()
     */
    // 由於我的股票精算師是使用1.6+,因此採用onKeyDown來監聽
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_BACK:
                back();
                break;
        }
        return true;
    }
}

至於在Activity1中的設定如下:

public class Activity1 extends Activity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity1);
        Button button = (Button) findViewById(R.id.button1);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 如果沒有這個外框會發生錯誤
                View view = ActivityGroup1.group.getLocalActivityManager().startActivity("Activity2", new Intent(Activity1.this, Activity2.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)).getDecorView();
                // 載入真正要執行的 Activity
                ActivityGroup1.group.replaceView(view);
            }
        });
}

基本上到這邊就已經可以正常運作囉!有什麼問題可以留言在這邊,小蛙會盡可能的協助解決。

2013-01-30 有網友反應 MediaFire 的檔案無法下載,更新下載路徑。範例檔下載

2012-10-22 範例檔下載

相關文章

Android Vuforia with jPCT-AE (5) – 多重模型載入,以 obj 為例

要進到這系列最後一篇文章了,這篇文章拖了很久,一直沒有時間整理,結果到最後 ... 程式碼留下來了,記憶卻有些模糊了,這邊小蛙配著程式碼盡可能的把還記得的東西寫下來。
2016-07-06 11:24:19
hans

18

Android Vuforia with jPCT-AE (4) – 載入 3DS 測試

延續 jPCT-AE Loader 載入模型的部份,這篇要記錄載入 3ds 檔案格式的方法,基本上跟前面幾個 obj, md2 的方法差不多,只有一些小小的變化而已。
2016-07-06 10:24:33
hans

18

Android Vuforia with jPCT-AE (3) – 載入 md2 測試

前兩篇介紹如何直接透過 jPCT-AE 直接繪圖以及載入 .obj 檔案,這邊繼續介紹 jPCT-AE 載入 md2 的方法,載入動作大致上類似,唯一不同的只有 texture 設定部份。
2016-07-06 09:24:43
hans

18

Android Vuforia with jPCT-AE (2) – 載入 obj 測試

上一篇 Android Vuforia with jPCT-AE (1) –
2016-07-06 08:24:55
hans

18

Android Vuforia with jPCT-AE (1) – 基本範例

說來慚愧,從 Google Adsense 被 ban 之後,就好久沒有發文了,站上 Vuforia 的文章也已經是好久以前的事情了 (遠目),最近有專案要用到 Vuforia,爬以前的文回來看,蛙哩咧 ... 現在已經更新到 Vu
2016-07-06 07:57:58
hans

18

Qualcomm Vuforia 教學 (5) – 替換茶壺 – Android JNI 版本

前面的文章提到為什麼要用 Android NDK 來開發,既然已經有了 Android 版本替換茶壺的文章,這邊記錄 Android NDK 版本的替換茶壺。
2014-12-09 17:54:17
hans

18

Qualcomm Vuforia 教學 (4) – 使用 Android NDK 版本並開啟多重偵測

接續前幾篇教學,我們已經建置好 Vuforia 開發及執行環境
2014-12-09 17:10:57
hans

18

Qualcomm Vuforia 教學 (3) – 替換茶壺 – Android 版本

接續上一篇 
2014-12-09 15:38:17
hans

18

Android 2.3 @JavascriptInterface Issue

JavascriptInterface 這個問題相信 Google 一下就可以找到很多文章,雖然如此小蛙還是試了好久才成功,這篇文章記錄一下當時小蛙不成功的盲點在哪裡。上一篇文章「
2014-03-28 20:25:25
hans

18

Android 與 WebView 中的 Javascript 相互溝通

最近的一個 app 需要讓 Android 可以呼叫 WebView 中的 Javascript,並且按下 WebView 中的按鈕時,也可以呼叫 Android 內部的方法,這篇文章記錄一下大概的做法,免得下次遇到又忘記 ...
2014-03-28 20:25:19
hans

18




  44 則留言 to “Android TabHost中切換Activity”

  1. 您好:
    我想請問我今天有tab1 , tab2,

    tab1接 activitygroup -> 子activity1 -> 子activity2,

    tab2接 一個activity,

    我今天該如何在tab1裡的子activity2畫面中,點選tab2後,再點回tab1就可以出現子activity1的畫面呢?

    目前是還是會停留在子activity2,謝謝~

  2. 您好:
    最近正好用到這方面技巧,但看了你的ActivityGroup1,發現MonitorGroup group那裡會出錯,
    載了您的範例檔內沒有ActivityGroup1這隻class檔,是否可以分享一下這隻原始檔與MonitorGroup。
    謝謝您~

    • Dear james:

      感謝您發現這個錯誤 …
      MonitorGroup group 設定成 static 目的讓其他 activity 存取,
      所以就是範例檔裡的 Activity1,
      範例檔應該可以跑才對,可以直接使用範例檔下去改,
      Sorry … ><

      • 感謝您的回覆。

        後來我有試出來了,謝謝。不過我沒有使用您上面寫的MonitorGroup class,因為我找不到此class。

        所以後來我把 MonitorGroup 改成

        public static ActivityGroup group;

        這樣就可以囉~ 提供其他網友參考。

        p.s 這兩天有發現有一些關於這個子activity的問題,我再研究看看,這兩天再跟版主請教討論~謝謝~

  3. 這篇真棒
    最近用fragment用到超煩碰到一堆問題跑來找這篇就解決了
    順便在這邊po一下最近碰到的一個問題的解決方法
    當你的activity裡面有listview的時候發現back會失效(會直接結束程式)
    因為keydown事件被listview吃掉了
    解決方法
    http://phenix.blogbus.com/logs/158999678.html

 回覆

你可以使用以下語法 HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="">

(required)

(required)

   
© 2012 蛙齋 Suffusion theme by Sayontan Sinha