記錄下對專案進行重構的過程
最近因為研究了Retrofit+RxJava+MVP,感覺這種組合相當好,再看看自己之前寫的程式碼,可維護性真的太差了。
由於公司專案使用的是WebService+xml,所以我寫了個Demo讓WebService+xml也能使用Retrofit+Rx+MVP,花費了比較多的時間,主要是對xml解析那塊,需要使用simplexml來解析,但情況又不完全符合。但後來想想,如果把專案真的完全改成這種模式,那付出的代價太大了。
由於專案是已經上線的,對專案進行重構,必須要保證能夠對之前的版本相容。
後來我仔細思考,Retrofit也屬於網路框架,我們專案中也為WebService封裝了自己的網路請求框架,所以,如果把Retrofit強行移植到專案中,並不一定能提高效率,反而增加重構的工作量。
打算對專案進行重構,從以下幾個步驟進行。
· 1 全面壓縮apk大小
宣告一下,這應該不算是重構的內容,但也是我在這個目標中給自己規定的一定要完成的任務。
在網上找了許多教程,主要是參考這幾個網站
使用lint檢查刪除冗餘程式碼和資源
ctrl+shift+alt+I 輸入unused會彈出很多提示,
我主要是用unused assignment和unused resource。
使用unused resource的時候要謹慎, 防止誤刪有用的資源,因為有時候第三方包需要使用的資源,這裡是檢查不到的,比如極光推送,需要一個名字為jpush_notification_icon.png的檔案,這些細節注意下即可。
其次就是刪掉so包,只保留一個armeabi,關於這一步,如果有問題,也可參考我的另一篇
做完這些操作,我的apk成功減小了6M
· 2 對Realm資料庫進行合併
剛開始使用Realm資料庫的時候,對它並不是特別瞭解,建了許多個數據庫,當時其實也知道這樣不太好,但想著能實現功能就沒管那麼多了。
但後來專案上線以後,經理總是要求功能改這改那,有時候就不得不對資料庫結構進行修改,Realm資料庫結構發生變化時是需要使用Migration的,需要自己定義升級操作。但是我當時建的資料庫太多,導致升級時遷移困難。
所以我就想到了將Realm資料庫來一個大合併,全都合併到一個數據庫中去。
但這也不是一件簡單的事,首先也是最重要的就是要保證對以前版本的相容性。之前我使用的Realm資料庫是0.89.1的,在合併資料庫的過程中遇到了許多錯誤,後來嘗試升級了1.0的版本,就成功將資料庫合併了。
現在只剩下一個數據庫,每次更改資料庫結構,我只需要編寫一個Migration就可以萬事大吉了。不用擔心其他各種各種問題。
· 3 使用ButterKnife8.1.0 替代之前的7.0.1的版本
ButterKnife算是有名的元件注入框架了,之前一直使用7.0.1的版本,但後來在網上看到資料,7.0.1是在執行時注入的,有點兒影響效率,新出的8.1.0的版本是在編譯時注入的,不會對執行造成任何影響,我就果斷升級8.1.0啦。
不過8.1.0有部分語法和之前不太一樣了,所以程式碼裡面都要改,我沒有找到一鍵把工程中所有的Bind全都替換成BindView的方法,而且這樣應該也不安全,容易出現未知錯誤。所以只好一個檔案一個檔案替換了。
· 4 建立新的BaseActivity(多個)
之前專案中也寫了一BaseActivity,但完成的功能是在太少了。
編寫新的BaseActivity,BaseFragment等等也是為了適應即將逐步嵌入的MVP框架和RxJava。
這個就不多說了,主要就是把公共的View提取到BaseActivity中,還有提供一些公共的方法。在BaseActivity中完成頁面打點,ButterKnife的繫結之類的操作。有了一系列的BaseView之後,可以大大簡化Acitivity中的操作。
我認為這個是非常必要的,BaseView也需要在專案編寫過程中不斷增加公共內容,不斷地完善。
BaseActivity中可以結合IBase,BasePresenter完成view的attach、dettach,弱引用關聯,unSubscribe等。這是非常必要的,使用MVP框架,如果不這樣做,非常容易引起記憶體洩漏。
貼上我的BaseActivity在這方面的處理,只貼核心程式碼。
public abstract class BaseActivityNoLayout<V,T extends BasePresenter<V>> extends AppCompatActivity implements IBase {
protected T mPresenter;
protected boolean nowRequest;
@Override
public void setContentView(@LayoutRes int layoutResID) {
super.setContentView(layoutResID);
ButterKnife.bind(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
if(mPresenter != null)
mPresenter.dettachView();
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = createPresenter();
}
protected abstract T createPresenter();
@Override
public void showToast(String s) {
Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
}
@Override
public boolean hasNet() {
return NetUtil.hasNet(getMApplicationContext());
}
}
還有BasePresenter進行弱引用關聯,即使你忘記dettach,等網路請求結束後,系統也會完成回收功能。
/**
* Created by fancy on 2016/6/22.
*/
public abstract class BasePresenter<T> {
String TAG = "BasePresenter";
//view介面型別的弱引用
protected Reference<T> mViewRef;
public void attachView(T view) {
Log.d(TAG, "attachView: "+mViewRef);
mViewRef = new WeakReference<T>(view);
Log.d(TAG, "attachView: "+mViewRef);
}
protected T getView() {
return mViewRef.get();
}
public boolean isViewAttached() {
return mViewRef != null && mViewRef.get() != null;
}
public void dettachView() {
if (mViewRef != null) {
mViewRef.clear();
mViewRef = null;
}
}
}
· 5 將MVP和Rx逐步嵌入專案
在我的專案中原本是使用非同步任務執行網路請求的,這就導致了網路請求需要排隊執行,非常地影響效率,網速比較慢的時候就更加坑爹了,慢到想死。
所以想使用RxJava來替代非同步任務,不過一口是吃不成胖子的,如果想一次性全都改了,容易出錯。
之前我新建了專案打算重定專案介面,包都分好了,但很快發現這樣不現實,第一專案已經上線,還在不斷維護,有時要開發新功能,很難保證同步,而且時不時又要回到原來的專案中去,來回切換不僅心累還耗時間。
後來我決定使用逐步替換的方式。
從使用者最先接觸到的功能,最重要的功能改起,一步一步使用MVP和Rx代替。當我成功替換一個功能之後,很快我就看到了效果,請求到結果的時間大大減少了,一條線變成了多條線能不快多了嗎,現在這一步還沒有完全完成,還只替換了絕大部分。
使用這種模式還有一個非常大的好處就是程式解耦,降低程式耦合性,方便程式維護,真想感嘆一句,MVP和總是要求改改改的經理更配哦~
有了RxJava之前我想到的網路請求優化方案都能so的一下實現了。
最後,對文章中提到的內容有任何疑問,歡迎加群討論:283272067