跳到主要內容

發表文章

目前顯示的是 7月, 2014的文章

探討 LayoutInflater 的 inflate method

        在 Android 程式裡要動態新增 View,最直接的方法就是使用 LayoutInflater 提供的 inflate method。比較常用的有以下兩個 method: inflate(int resource, ViewGroup root) inflate(int resource, ViewGroup root, boolean attachToRoot)         第一個參數 resource,就是 layout xml file,如 R.layout.your_file。第二個參數 root,指的是這個 inflate 的 view,要成為哪個 view 的 child view。最後一個參數 attachToRoot 是 inflate 的 view 是否要 attach 到 root view,這會影響到回傳的是哪個 view。假如 attachToRoot 為 true,則最後回傳的 view 為 root view (就是第二個參數的 view);反之就是回傳 inflate 的 view。         第二個參數 ViewGroup root 需要特別說明一下,因為這會影響到如何 inflate 新的 view 出來。android 的 view 是有階層 (hierarchy) 的,因此 parent view 的屬性 (attribute) 會影響到 child view 。假如你是如以下兩種方式使用 inflate method的話: View view1 = LayoutInflater.from(mContext).inflate(R.layout.your_file, null) View view2 = LayoutInflater.from(mContext).inflate(R.layout.your_file, null, false)         因為沒有 root view,系統沒辦法把 inflate view 的屬性正確設定,因此系統會把 inflate view 的屬性設為 null,這會導致 inflate view 的屬性都非你所預期  (稍後會用 LayoutInflater source code 解說)。因此要很注意你 root view 是否要代 nul

AsyncTask 真的有在平行執行嗎?

        我一直以為只要使用了 AsyncTask 的 execute,就相當於開一個 thread 去做事情。後來在網路上看到一篇 文章 才知道原來新版的 Android 有改過。在 API level 11 以上,AsyncTask 預設是循序執行的,因此要能平行執行的話,原本使用 AsyncTask 的方法要重新改寫,如以下所示: AsyncTask task = new YourAsyncTask(); if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { task.execute(); } 參考資料 1. Android AsyncTask behavior changes you should know 2. Android AsyncTask - executeOnExecutor ---

ADT 開新專案不使用 support.v7.appcompat

        ADT 愈來愈煩了…不知道從哪一版開始,我目前版本是 Android SDK Tools 22.6.4,Android SDK Platform-Tools 19.0.2,只要開新專案選 Blank Activity,預設 MainActivity 就會 extends AtionBarActivity 並使用 Fragment 顯示頁面,而且 project list 還會多一個 appcompat_v7,可是我一點都不喜歡 Fragment 阿!!!但是選專案 Activity 時,多了一個 Empty Activity,我選它總可以了吧!         很好,總算是 extends Activity了,但還是一樣會多一個 appcompat_v7 的專案。這看了真的很礙眼,我索性就把它刪了。結果刪掉後,反而新專案怎麼 build 都失敗。看一下錯誤都是在 style.xml         看一下錯誤訊息,是   No resource found that matches the given name 'Theme.AppCompat.Light' 。因為這是在 support v7 appcompat 裡的東西,把它砍了當然就找不到,build 失敗也是正常的,這裡教大家如何能順利 build 這個新專案: 1. 對專案按右鍵 --> Properties --> 左邊 Panel 選 Android --> 右邊 Scroll bar 拉到最下面 -->             Library 的地方把 appcompat_v7 這個 project library 給 remove 掉 --> Apply and OK。 2. 把 style.xml 裡的 parent theme 都改成原有的 theme,例如  android:Theme.Light 3. 重新 build project --> 打完收工!         這是不想用 Fragment 的情形才要這樣做啦,要是你的 app 想要呈現多頁的資訊的話,Fragment + ActionBar/ViewPager 還是不錯的選擇啦! (但是滿難用就是了)

使用 hide/internal Android API

        有時在開發 Android app 時,可能會想使用非公開的 API (就是有註解為 @hide),這時候可以使用 Java 的 Reflection 機制來達成。本文並不討論此機制的原理,有興趣的網友可以自行 GOOGLE 。         在 Android 要使用 Reflection 機制有兩項前提,分別是: 1. 必須要知道要使用的 API 其完整 class name 及 method name,class name 要包含 package             name 2. 使用此 API 所需的 permission ( 加在 AndroidManifest 的)         其實上述這兩點只要看 source code 就可以知道了,而網路上都有 source code 可以看,所以應該不是什麼大問題… 底下是一個簡單的範例: WifiManager wifiMgr = (WifiManager) getSystemService(Context.WIFI_SERVICE); WifiConfiguration wifiConfig = null; try { Class WifiMgrClz = Class.forName(WifiManager.class.getName()); Method getWifiApCOnfiguration = WifiMgrClz.getMethod("getWifiApConfiguration"); wifiConfig = (WifiConfiguration) getWifiApCOnfiguration.invoke(wifiMgr); Class[] paramOfClass = new Class[2]; paramOfClass[0] = WifiConfiguration.class; paramOfClass[1] = Boolean.TYPE; Method setWifiApEnabled = WifiMgrClz.getMethod("setWifiApEnabled", paramOfClass); Object[] paramO

動態更新 ViewPager 的目前顯示頁面

        ViewPager 在 Android 裡是一個很好用的元件,使用者只要左右滑動,就可以顯示多頁的資訊。假如你的資料是從網路取得,如圖片,當使用者滑到還沒載入完成的頁面時,該怎麼辦呢?         雖然 ViewPager 會動態更新頁面,但是當下顯示的頁面是不會更新的。要達到上述的目的,我們要做一些事。ViewPager 主要是由 PagerAdapter 來處理內部的資料的,因此我們要從它下手。         PagerAdapter 有一個 method:getItemPosition。看 API 說明應該是用來判斷目前頁面的內容位置是否有變,但是也可以用它來滿足我們的要求,pseudo code 如下: public int getItemPosition(Object object) {         if ( 你的資料準備好了 )         {                 return POSITION_NONE;         }         else         {                 // 資料還沒準備好,此頁面維持不變                 return POSITION_UNCHANGED;         } }         雖然 overwrite 了 getItemPosition,但是這個 method 並不是我們主動去 invoke 的,PagerAdapter 提供了另一個 method 可以讓我們通知 adapger 有資料要更新了:notifyDataSetChanged。因此當我們確定資料準備好了就使用 notifyDataSetChanged,搭配 getItemPosition,就能動態更新目前的 ViewPager 頁面了。 參考資料: 1. ViewPager 2. PagerAdapter

清空 Handler 的 message queue

寫 Android 多執行緒的程式時,我最常使用的是 Thread-Handler 架構。某天遇到了一個情形:在特定時間點清空 message queue,讓 Handler 都不處理還留著的 event。有一個方法可以做到,就是  removeCallbacksAndMessages 。API 說明如下: public final void  removeCallbacksAndMessages   ( Object  token) Added in  API level 1 Remove any pending posts of callbacks and sent messages whose  obj  is  token . If  token  is null, all callbacks and messages will be removed. 因此,我們只要使用 handler.removeCallbacksAndMessages(null),就可以讓 Handler 不處理還 queue 住的 event。