AllenHsu的技術手扎

學海無涯,努力做個永遠年輕的人

關於依賴注入

在談 Dagger2 之前,我想先簡單介紹一下關於 依賴注入 。什麼是依賴注入? Dependency Injection (依賴注入) 簡稱 DI,用來降低程式碼的耦合度所使用。

當我們今天有一個 Class A 用到了 Class B 的物件,一般情況下,需要在 A 的代碼中顯示的 new 一個 B 的物件。這樣子Class A 的建構就依賴於 Class B了,
當我們實現依賴注入之後 A 的代碼只需要定義一個私有的 B 物件,不需要直接
New 來獲得這個物件,而是透過相關的容器控制程式來將 B 物件在外部 new出來並注入到 A 類裡的參考中。

依賴注入有如下實現方式:

  • 基於介面。實現特定介面以供外部容器注入所依值型別的物件。
  • 基於 set 方法。實現特定屬性的public set方法,來讓外部容器呼叫傳入所依值型別的物件。
  • 基於建構函式。實現特定參數的建構函式,在新建物件時傳入所依值型別的物件。
  • 基於註解。基於Java的註解功能,在私有變數前加「@Autowired」等註解,不需要顯式的定義以上三種代碼,便可以讓外部容器傳入對應的物件。該方案相當於定義了public的set方法,但是因為沒有真正的set方法,從而不會為了實現依賴注入導致暴露了不該暴露的介面(因為set方法只想讓容器存取來注入而並不希望其他依賴此類的物件存取)。
Read more »

前言

設計模式 中, 一個最基本的原則 少用繼承,多用合成 。所以我們有了 Strategy Pattern (策略模式) 和 其他有用的設計模式,在這邊主要是想要談如何透過 Swift 來實作策略模式。

Read more »

NSTimer 的 retain cycle 的問題

有時我們常常需要在 Controller 中建立一個定時被呼叫的函數,所以會使用到 NSTimer,NSTimer 很容易產生 retain cycle 的狀況,下列一個是很常見的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class ViewController: UIViewController {

var timer : Timer?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(fire), userInfo: nil, repeats: false)
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

@objc func fire() {
//Do some thing
}

deinit {
timer?.invalidate()
timer = nil;
}
}
Read more »

RecycleView的Bug : java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position

最近在工作上,因為某些原因,需要很快速地刷新RecycleView內的元素,但是很常出現閃退,追了一下log,發現是下列的原因:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 150(offset:150).state:153
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5504)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5440)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5436)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2224)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1551)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1511)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:595)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3583)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3312)
at android.support.v7.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1618)
at android.support.v7.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:4702)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911)
at android.view.Choreographer.doCallbacks(Choreographer.java:686)
at android.view.Choreographer.doFrame(Choreographer.java:619)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:7409)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

Bug 出現原因 :

再進行數據變動時,務必要保證 Adapter 中的數據和移除的數據保持一致,就是當你更新你的集合後,呼叫 notify 方法時, adapter 的更新預期結果和實際集合更新結果不同,就會出現此異常。

例如: 增加了兩條數據,但是 Adapter 的 notify 只增加 5 條數據,這種情況就屬於不一致,簡單來說 Apapter 有個 Size,你的資料結構集合也有 Size,這兩個 Size 在呼叫 notify 方法時必須保持相同。

解決方法 :

覆寫 xxxxLayoutManager(看你使用的是 LinearLayoutManager 或是 GridLayoutManager或其他)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class RecyclerViewLinearLayoutManager extends LinearLayoutManager {
public RecyclerViewLinearLayoutManager(Context context) {
super( context );
}

public RecyclerViewLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super( context, orientation, reverseLayout );
}

public RecyclerViewLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super( context, attrs, defStyleAttr, defStyleRes );
}

@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
try {
//主要在這邊加入 try catch
super.onLayoutChildren( recycler, state );
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
}

}
}

主要是在添加集合的時候,增加了一層 try catch去解決。

參考 :

https://stackoverflow.com/questions/30458640/recyclerview-java-lang-indexoutofboundsexception-inconsistency-detected-inval

http://www.cnblogs.com/fuyaozhishang/p/6991221.html

前言

前面介紹了關於 RxSwift 的資源管理,這次要來介紹關於 RxJava 的部分,在 RxJava 中有一些第三方的資源管理像是 RxLifecycle 這種好用的第三方庫來幫忙在程式碼中,如果沒有及時的回收 Rx 相關的資源,會造成 Activity/Fragment 無法銷毀所導致的 Memory LeakRxLifecycle 的用法就是讓我們的 Observable 跟隨著 Activity/Fragment 的生命週期去取消訂閱,但是這樣就真的完美解決了 RxJava 的記憶體管理問題嗎 ? 我們來看看 RxLifecycle 的作者怎麼說。

Read more »

關於 RxSwift 的記憶體管理機制

在介紹關於 RxSwift 基本入門 中提到了一些 RxSwift 的核心概念 - Observable ,我們描述了事件訊息的種類,分別是 : nexterrorcompleted , 當這個 Observable 收到errorcompleted 事件訊息時,那麼這個 Observable 將不會再接受其他的訂閱事件。 同時在這邊用來分派給此 Observable 的記憶體資源就一起被釋放掉了,我們可以將其視為類似 ARC 的自動記憶體釋放。 如果你想立刻將 Observable 關閉且立刻釋放資源,那麼你需要呼叫 dispose 函數,這邊我們可以理解為類似 MRC 的手動釋放。

如果一個 Observable 在一定的時間內結束,即使不呼叫 dispose 或者使用 DisposeBag 也不會引發 Memory Leak。 如果一個 Observable 因為某些原因

沒有結束,那記憶體將會永遠的不會被釋放,所以就算 根據 Observable 的運作原理,我們也會希望透過某些記憶體回收機制來確保不會產生 Memory Leak 的問題。

下面將詳細介紹幾種 RxSwift 的記憶體管理機制。

Read more »

RxSwift 初心者入門

在之前我們稍微提過 RxSwift 這一個 framework ,也有稍微介紹了什麼是 Reactive Programming ,那這邊就來詳細談談如何學習以及使用 RxSwfit 吧。

使用 RxSwift 的 Playground

首先我們先至 RxSwift Clone 整個 Project,接著我們這邊使用 Rx.Playground 做為入門的教學,按照官網的操作如下

1
2
3
4
5
6
To use playgrounds:

Open Rx.xcworkspace
Build the RxSwift-macOS scheme
Open Rx playground in the Rx.xcworkspace tree view.
Choose View > Debug Area > Show Debug Area
Read more »

為什麼需要規範團隊的 git log

在團隊開發中,我們常常會希望團隊遵循一個 git commit log 的規範,原因是我們希望在未來要查找之前的 log 時,可以透過這樣的方式可以很快的搜尋到想要的結果,也可以在 CI/CD 的流程中,透過規範的 git log 藉而產出一個有意義且能給 QA/PM/其他團隊成員觀看的 CHNAGELOG (版本更新內容)

Read more »

RecyclerView - 比 ListView 更強大易用效率高的滾動元件

雖然 ListView 可以完成我們大部分列表的需求,不過我們需要使用額外的方式來提高 ListView 的效率,然後 ListView 的擴展性也還不夠全面,它無法做到橫向滾動的效果,所以 Android 提供了一個更強大的元件 — RecyclerView

Read more »

ListView - 如何提高執行效能

在 ListView 中,如何有效的提高執行效能是很重要的一點,它有相當多的細節可以優化,這邊會介紹該如何去提高執行的效能。

Read more »
0%