項目地址
一款第三方今日頭條客戶端, MVP + RxJava + Retrofit
架構
標準的MVP
架構
IBasePresenter
層
每個P層都有刷新界面以及顯示網絡錯誤需求
public interface IBasePresenter {
void doRefresh();
void doShowNetError();
}
IBaseView
層
每個V層都有展示狀態頁,設置Presenter
,以及解除RxJava
訂閱防止內存泄漏的接口.
public interface IBaseView<T> {
void onShowLoading();
void onHideLoading();
void onShowNetError();
void setPresenter(T presenter); // P類型由V層泛型決定
<X> AutoDisposeConverter<X> bindAutoDispose();
}
對新聞頁架構分析
新建INewsArticle
接口,其中INewsArticle.View
接口由NewsArticleView
實現,INewsArticle.Presenter
由NewsArticlePresenter
實現.
public interface INewsArticle {
// INewsArticle.View接口繼承自IBaseListView接口,可以看作是對IBaseListView接口方法的補充.
// INewsArticle.View接口中定義了新聞頁的行爲方法
// IBaseListView<Presenter> 該泛型決定了P層類型,也就是該P層類型必須爲INewsArticle.Presenter類型.
interface View extends IBaseListView<Presenter> {
void onLoadData();
void onRefresh();
}
// INewsArticle.Presenter接口繼承自IBasePresenter接口,可以看作是對IBaseListView接口方法的擴充
// INewsArticle.Presenter接口中定義了新聞頁P層的行爲方法
interface Presenter extends IBasePresenter {
void doLoadData(String... category);
void doLoadMoreData();
void doSetAdapter(List<MultiNewsArticleDataBean> dataBeen);
void doShowNoMore();
}
}
對新聞頁分析
NewsArticlePresenter
public class NewsArticlePresenter implements INewsArticle.Presenter {
private INewsArticle.View view;// NewsArticleView層引用, 用來更新UI.
public NewsArticlePresenter(INewsArticle.View view) {
this.view = view;
}
}
NewsArticleView
// <INewsArticle.Presenter>: 該泛型是用來確定創建得P層對象的類型.
public class NewsArticleView extends BaseListFragment<INewsArticle.Presenter> implements INewsArticle.View {
// IBaseView接口中定義得setPresenter()方法,在這裏實現.
@Override
public void setPresenter(INewsArticle.Presenter presenter) {
if (null == presenter) {
// this.presenter: 在BaseFragment中定義了一個變量presenter,專門用來接收P層對象..
this.presenter = new NewsArticlePresenter(this);
}
}
}
MVP
架構總結
// 頂層接口定義一些共有的方法
interface IBaseP {
}
interface IBaseV<T> {
// 爲V層創建P層對象
// 泛型T確定了P層對象的類型
T setPresenter(T t);
}
// 次級接口定義自己特有的方法
interface IMy {
// <MyP>: 確定P層對象的類型爲MyP
interface MyV extends IBaseV<MyP> {
void refreshPage();// 更新UI
}
interface MyP extends IBaseP {
void getData();// 獲取數據
}
}
// P層的實現
// <T extends IMy.MyV>: 確定P層持有的V層類型
class MyPresenter<T extends IMy.MyV> implements IMy.MyP {
T mView;
public MyPresenter(T mView) {
this.mView = mView;
}
@Override
public void getData() {
System.out.println("獲取數據");
mView.refreshPage();// 獲取數據之後更新界面
}
}
// 定義BaseActivity,<T>用來確定P層對象的類型.
abstract class BaseActivity<T> implements IBaseV<T> {
T mPresenter;
public BaseActivity() {
// 調用子類實現的setPresenter()方法,創建P層對象,由父類mPresenter變量保存.
mPresenter = setPresenter(mPresenter);
}
}
// V層實現類
// <IMy.MyP>: 確定P層對象類型.
class MyActivity extends BaseActivity<IMy.MyP> implements IMy.MyV {
public MyActivity() {
mPresenter.getData();
}
@Override
public void refreshPage() {
System.out.println("更新界面");
}
// IBaseV.setPresenter()接口方法的具體實現.
@Override
public IMy.MyP setPresenter(IMy.MyP myP) {
// <IMy.MyV>: 用來確認P層中V對象的類型.
return new MyPresenter<IMy.MyV>(this);
}
}
public class MVP {
public static void main(String[] args) {
// 模擬Activity啓動之後獲取數據然後刷新界面
new MyActivity();
}
}
網絡
網絡框架使用的是Retorfit+OkHttp+RxJava
Cookie
管理
使用的是一個第三方庫PersistentCookieJar
簡單的設置如下:
ClearableCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(InitApp.AppContext));
OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(cookieJar)
.cache(cache)
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build();
緩存管理
OkHttp
的緩存推薦使用RxCache,這個真的非常好用.
處理RxJava
內存泄漏
項目中沒有使用RxLifecycle
,使用的是AutoDispose
.
例子:
RetrofitFactory.getRetrofit().create(IMobileNewsApi.class)
.getNewsComment(groupId, offset)
.subscribeOn(Schedulers.io())
...
.observeOn(AndroidSchedulers.mainThread())
.as(view.bindAutoDispose()) // bindAutoDispose該方法由View層實現.
.subscribe(list -> {
if (null != list && list.size() > 0) {
doSetAdapter(list);
} else {
doShowNoMore();
}
}, throwable -> {
doShowNetError();
ErrorAction.print(throwable);
});
View
層如何實現的bindAutoDispose()
public abstract class BaseFragment<T extends IBasePresenter> extends Fragment implements IBaseView<T> {
/**
* 綁定生命週期
*/
@Override
public <X> AutoDisposeConverter<X> bindAutoDispose() {
return AutoDispose.autoDisposable(AndroidLifecycleScopeProvider
.from(this, Lifecycle.Event.ON_DESTROY)); // 當Activity被銷燬時候,接觸RxJava間的訂閱.
}
}
高亮提示效果
TapTargetView
使用的是這個庫,項目中是在MainActivity.showTapTarget()
方法中用到.
動態設置APP屬性
項目中SettingUtil
工具類可以設置主題顏色,導航欄上色,視頻橫屏,字體大小等.
manifest
中Activity
配置
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize|uiMode"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar"/>
Android 設備運行時候,設備的配置可能發生改變,如橫豎屏切換,鍵盤等,這樣會導致Activity重啓,銷燬前先調用onSaveInstanceState()保存應用中的一些數據,供Activity恢復時候使用.如果想讓手機的配置改變不重啓Activity的話需要爲當前Activity的android:configChanges
添加某些屬性,這樣當配置改變時不會重啓Activity而是會調用Activity的onConfigurationChanged()
方法.
navigation
:導航欄發生了變化fontScale
: 字體發生了變化uiMode
:用戶模式發生了變化orientation
:屏幕方向發生了變化screenSize
:屏幕大小發生了變化keyboardHidden
: 鍵盤可用性發生了變化