2015年12月14日 星期一

Android 開發心得整理

Android 開發心得整理

Application

  • 只要有該 App 的任何元件(Activity、Service、BroadcastReceiver)執行,Application 就會存在。

Service

  • 簡單一點的話就用 IntentService

  • 同一個 Intent 的 Service 不會同時間執行(尚未測試不同 Intent 的 Service),若執行了兩個相同的
    Service 在 S1 還沒執行完時不會執行 S2,S2 會在S1 執行完後立刻執行,並且 S1 不會執行 onDestroy 而 Service2 會。

  • 使用 AlarmManager 註冊 Service 預計執行 Service,在時間到達前可以重新註冊(update)達成延後或提 前執行或取消註冊。當有兩個相同的 Service 到達執行時間時,僅有 S1 會執行,S2 處於 ready 狀態,ready 狀態的 Service 無法更新、取消註冊。

  • 已經向 AlarmManager 註冊的 Service 就算重新開機,一樣會執行,可以理解為是向 OS 註冊。

  • 當 Service 執行到一半,以 Android task 關閉方式 Kill 該 Service 所屬 App,Service 會被腰斬(沒有執行完),若使用 startForeground 則不會被腰斬,但不會執行 onDestroy。

EventBus

  • 注意 onEvent 的 Thread 問題

  • 想保留該 event 的話可以使用 postSticky

Realm

  • 在 Thread1 撈出來的 RealmObject 無法在 Thread2 存取(讀取也不行!)。

  • 只有在 Main Thread(UI Thread) 撈出來的物件會自動更新。

  • 在非 Main Thread 撈資料前,先使用 refresh,確保資料是最新的狀態。

其他 Lib

Written with StackEdit.

2015年12月10日 星期四

Android 在 gradle 中加入 RecyclerView dependency 的錯誤

Android 在 gradle 中加入 RecyclerView dependency 的錯誤

今天要來寫 Android 的 RecyclerView,我在 app.gradle 中的 dependencies 中加入了

compile 'com.android.support:recyclerview-v7:23.1.0'

也就順便把 appcompate-v7 改成一樣的版本

compile 'com.android.support:appcompat-v7:23.1.0'

結果出現了這兩個錯誤

Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material.Widget.Button.Inverse'.
Error retrieving parent for item: No resource found that matches the given name 'android:Widget.Material.Button.Colored'.

而這兩個東西是在這個檔案裡的

{專案目錄}\app\build\intermediates\exploded-aar\com.android.support\appcompat-v7\23.1.0\res\values-v23\values-v23.xml

想想應該是還有哪裡的版本也要改,估狗一下馬上找到原來是 compileSdlVersion 也要設定一樣的版本,再把它改成 23 後就可以正常使用了。

整個 app.gradle 大概是長這樣

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23

    .
    .
    .
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:23.1.0'
    compile 'com.android.support:recyclerview-v7:23.1.0'

    .
    .
    .
}

Written with StackEdit.

2015年12月7日 星期一

在 Android 中判斷該 Service 有無被註冊喚醒的方法

在 Android 中判斷該 Service 有無被註冊喚醒的方法

我的程式有些批次的事情要做,大概是每五分鐘要去檢查有沒有任務要做,有的話就做,沒的話就等下一個五分鐘,我的任務是有可能會失敗的(例如傳送資料),需要在下一次 Service 內再去嘗試執行,而且要在背景執行。講到這裡聰明的你可能會想到要用 Service 搭配 AlarmManager 來做,就給他設定每隔五分鐘呼叫一次,我也是這樣想的,但遇到一個問題,這樣做非常非常非常非常耗電,就算沒任務也要把 Service 叫起來這可不行。

所以我把程式改為在 ServiceonDestroy 時去判斷還有沒有任務沒完成的,如果有就設定五分鐘後再次執行,若沒有就不設定了,有新任務加入時再去把 Service 叫起來。

這次的重點就在這!

  • 假設上一次的 Service 結束時已經沒有任務要做了,就不會有下一次的自動執行,這時候有新的任務加入,我把 Service 叫起來然後執行,OK!沒問題。
     
  • 假設上一次的 Service 結束時還有任務要做,所以五分鐘後會自動執行,在執行之前有新的任務加入,這時候我該叫起 Service 嗎?叫起的話就破壞了我每五分鐘執行一次的規律生活了。

這樣說起來就是我需要知道目前這個 Service 有沒有被註冊自動執行囉?

拜請 Google 大神的結果是,沒辦法知道 AlarmManager 目前註冊了哪些 PendingIntent,所以我無法透過 AlarmManager 知道這個 Service 有沒有可以自起爬起來工作。

好吧從另一個目標下手,PendingIntent

他的 getService 第四個參數若設定為 PendingIntent.FLAG_NO_CREATE ,可以用來查詢這個 Intent 有沒有存在 PendingIntent,若存在會回傳該 PendingIntent ,反之會回傳 null

if (null == PendingIntent.getService(context, requestCode, intent, PendingIntent.FLAG_NO_CREATE)) {
    // register service
}

然後在 Service 執行時立馬把這個 PendingIntent 刪掉。

@Override
public void onCreate() {
    PendingIntent pi = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_NO_CREATE);
    if (pi != null)
        pi.cancel();
}

如此便完成我的需求

「當該 Service 已經註冊下次喚醒時間時,不再重覆註冊或直接喚醒以避免破壞其規律的生理時鐘」

Written with StackEdit.