這兩天開始放寒假,在家待著也是待著,遂決定找星空以前 Android 方向大佬寫的項目學習下,看看別人代碼的結構以及有什麼方法可以降低代碼的耦合度,然後在師兄的項目裡接觸到了 BaseActivity,在這裡記錄一下
為什麼設計基類#
- 方便代碼編寫,減少重複代碼和冗餘邏輯,優化代碼
- 優化程序架構,降低耦合度,方便拓展、修改
- 版面更乾淨,減少了諸如生命週期日誌等重複邏輯的佔用版面
設計的基本思路#
- 生命週期的調試日誌輸出
- 綁定視圖
- 常用 OnClick 方法
- Back 方法,Toast 以及 Activity 等操作
- 常用第三方工具(ButterKnife 等)
- 標題欄是否顯示,是否全屏,初始化數據等
具體基類的封裝#
BaseActivity#
public abstract class BaseActivity<P extends BasePresenter> extends AppCompatActivity
implements BaseView<P> {
@BindView(R.id.toolbar)
Toolbar mToolbar;
Unbinder bind;
/**
* 進度對話框
*/
protected ProgressDialog mProgressDialog;
/**
* 泛型確定Presenter
*/
protected P mPresenter;
@Override
protected final void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 設置為豎屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(bindLayout());
// ButterKnife綁定佈局
bind = ButterKnife.bind(this);
mPresenter = createPresenter();
if (mPresenter != null) {
// 調用Presenter初始化方法
mPresenter.onStart();
}
// 準備數據
prepareData();
// 初始化標題欄
initToolbar();
// 初始化視圖
initView();
// 初始化數據
initData(savedInstanceState);
// 初始化事件監聽
initEvent();
}
/**
* 創建Presenter
*
* @return 泛型Presenter
*/
protected abstract P createPresenter();
/**
* 實現BasePresenter接口的setPresenter方法
*
* @param presenter createPresenter()創建的Presenter
*/
@Override
public void setPresenter(P presenter) {
mPresenter = presenter;
}
/**
* 初始化Toolbar
*/
private void initToolbar() {
setSupportActionBar(mToolbar);
}
/**
* 設置Toolbar標題
*
* @param title 標題
*/
protected void setToolbarTitle(String title) {
if (getSupportActionBar() != null) {
getSupportActionBar().setTitle(title);
}
}
/**
* 設置Toolbar顯示返回按鈕及標題
*
* @param title 標題
*/
protected void setToolbarBackEnable(String title) {
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_arrow_white_24dp);
setToolbarTitle(title);
}
}
/**
* 綁定佈局
*
* @return 佈局文件的資源ID
*/
protected abstract int bindLayout();
/**
* 準備數據(從Intent獲取上個界面傳過來的數據或其他需要初始化的數據)
*/
protected abstract void prepareData();
/**
* 初始化視圖,findViewById等等
*/
protected abstract void initView();
/**
* 初始化數據,從本地或伺服器開始獲取數據
*
* @param savedInstanceState 界面非正常銷毀時保存的數據
*/
protected abstract void initData(Bundle savedInstanceState);
/**
* 初始化事件監聽,setOnClickListener等等
*/
protected abstract void initEvent();
/**
* 實現BaseView的showToast(CharSequence msg)
*
* @param msg 吐司顯示的信息
*/
@Override
public void showToast(CharSequence msg) {
ToastUtils.shortToast(this, msg);
}
/**
* 實現BaseView的showToast(int msgId)
*
* @param msgId 吐司顯示的字符串資源id
*/
@Override
public void showToast(int msgId) {
ToastUtils.shortToast(this, msgId);
}
/**
* 實現BaseView的showLoadingDialog(CharSequence msg)
* 顯示加載對話框
*
* @param msg 對話框的提示內容
*/
@Override
public void showLoadingDialog(CharSequence msg) {
if (mProgressDialog == null) {
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setTitle(R.string.title_dialog_tips);
mProgressDialog.setMessage(msg);
} else {
mProgressDialog.setTitle(R.string.title_dialog_tips);
}
mProgressDialog.show();
}
/**
* 實現BaseView的hideLoadingDialog()
* 隱藏加載對話框
*/
@Override
public void hideLoadingDialog() {
if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
}
}
/**
* Activity銷毀時清理資源
*/
@Override
protected void onDestroy() {
// ButterKnife解除綁定
bind.unbind();
// 銷毀Presenter
if (mPresenter != null) {
mPresenter.onDestroy();
}
super.onDestroy();
}
/**
* 隱藏鍵盤
*/
public void hideKeyboard() {
View view = getCurrentFocus();
if (view != null) {
((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).
hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
@Override
protected void onPause() {
super.onPause();
// (僅有Activity的應用中SDK自動調用,不需要單獨寫)
// 保證 onPageEnd 在onPause之前調用,因為 onPause 中會保存信息。
MobclickAgent.onPageEnd(this.getClass().getSimpleName());
MobclickAgent.onPause(this);
}
@Override
protected void onResume() {
super.onResume();
//統計頁面(僅有Activity的應用中SDK自動調用,不需要單獨寫。)
MobclickAgent.onPageStart(this.getClass().getSimpleName());
//統計時長
MobclickAgent.onResume(this);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
}
return super.onOptionsItemSelected(item);
}
}
BaseFragment#
public abstract class BaseFragment<P extends BasePresenter> extends Fragment
implements BaseView<P> {
@BindView(R.id.toolbar)
Toolbar mToolbar;
private Unbinder mUnbinder;
protected P mPresenter;
protected ProgressDialog mProgressDialog;
private ActionBar mActionbar;
@Nullable
@Override
public final View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mPresenter = createPresenter();
if (mPresenter != null) {
mPresenter.onStart();
}
View root = inflater.inflate(bindLayout(), container, false);
mUnbinder = ButterKnife.bind(this, root);
prepareData(savedInstanceState);
initToolbar();
// 初始化視圖
initView(root);
initData(savedInstanceState);
initEvent();
return root;
}
protected abstract P createPresenter();
@Override
public void setPresenter(P presenter) {
mPresenter = presenter;
}
/**
* 準備數據
*
* @param savedInstanceState
*/
protected abstract void prepareData(Bundle savedInstanceState);
/**
* 綁定fragment的佈局文件
*
* @return
*/
protected abstract int bindLayout();
/**
* 初始化數據
*
* @param savedInstanceState
*/
protected abstract void initData(Bundle savedInstanceState);
/**
* 初始化界面
*
* @param rootView
*/
protected abstract void initView(View rootView);
/**
* 初始化事件監聽器
*/
protected abstract void initEvent();
/**
* 初始化Toolbar
*/
private void initToolbar() {
((AppCompatActivity) getActivity()).setSupportActionBar(mToolbar);
mActionbar = ((AppCompatActivity) getActivity()).getSupportActionBar();
}
/**
* 設置Toolbar標題
*
* @param title 標題
*/
protected void setToolbarTitle(String title) {
if (mActionbar != null) {
mActionbar.setTitle(title);
}
}
/**
* 設置Toolbar顯示返回按鈕及標題
*
* @param title 標題
*/
protected void setToolbarBackEnable(String title) {
if (mActionbar != null) {
mActionbar.setDisplayHomeAsUpEnabled(true);
mActionbar.setHomeAsUpIndicator(R.drawable.ic_arrow_white_24dp);
}
}
@Override
public void showToast(CharSequence msg) {
ToastUtils.shortToast(APP.getAppContext(), msg);
}
@Override
public void showToast(int msgId) {
ToastUtils.shortToast(APP.getAppContext(), msgId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void showLoadingDialog(CharSequence msg) {
if (mProgressDialog == null) {
mProgressDialog = new ProgressDialog(getContext());
mProgressDialog.setMessage(msg);
} else {
mProgressDialog.setTitle(R.string.title_dialog_tips);
}
mProgressDialog.show();
}
@Override
public void hideLoadingDialog() {
if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
}
}
@Override
public void onDetach() {
mUnbinder.unbind();
super.onDetach();
}
@Override
public void onDestroyView() {
if (mPresenter != null) {
mPresenter.onDestroy();
}
super.onDestroyView();
}
@Override
public void onResume() {
super.onResume();
MobclickAgent.onPageStart(this.getClass().getSimpleName());
}
@Override
public void onPause() {
super.onPause();
MobclickAgent.onPageEnd(this.getClass().getSimpleName());
}
}
BasePresenter#
public interface BasePresenter {
void onStart();
void onDestroy();
}
BaseView#
public interface BaseView<P> {
void setPresenter(P presenter);
void showToast(CharSequence msg);
void showToast(int msgId);
void showLoadingDialog(CharSequence msg);
void hideLoadingDialog();
}
Impl 類#
public abstract class BasePresenterImpl implements BasePresenter {
protected CompositeDisposable mSubscriptions;
@Override
public void onStart() {
if (mSubscriptions == null) {
mSubscriptions = new CompositeDisposable();
}
}
@Override
public void onDestroy() {
if (mSubscriptions != null) {
mSubscriptions.dispose();
mSubscriptions.clear();
}
}
}
APP 類#
用於獲取全局的 context
public class APP extends Application {
private static Context appContext;
private static long exitTime = 0;
/**
* 獲取Application的Context
*
* @return 全局Context
*/
public static Context getAppContext() {
return appContext;
}
@Override
public void onCreate() {
super.onCreate();
appContext = getApplicationContext();
}
/**
* 退出APP
*/
public static void exitApp() {
if (System.currentTimeMillis() - exitTime > 2000) {
ToastUtils.shortToast(getAppContext(), appContext.getString(R.string.text_press_again));
exitTime = System.currentTimeMillis();
} else {
android.os.Process.killProcess(android.os.Process.myPid());
}
}
}
具體使用#
Contract 契約類#
契約類用於定義同一個界面的 view 和 presenter 的接口,通過規範的方法命名或註釋,可以清晰的看到整個頁面的邏輯。
public interface myContract {
interface View extends BaseView<Presenter> {
}
interface Presenter extends BasePresenter {
}
}
Presenter#
public class SamplePresenter extends BasePresenterImpl implements myContract.Presenter {
private final myContract.View mView;
public SamplePresenter(myContract.View view) {
mView = view;
this.mView.setPresenter(this);
}
}
Activiy#
public class SampleActivity extends BaseActivity<myContract.Presenter> implements myContract.View {
@BindView(R.id.tv_sample_text)
TextView mTvSample;
@Override
protected myContract.Presenter createPresenter() {
return new SamplePresenter(this);
}
@Override
protected int bindLayout() {
//TODO:添加視圖,記得添加androidmanifest
return R.layout.activity_sample;
}
@Override
protected void prepareData() {
//TODO:準備數據 比如:從數據庫加載數據,或者網絡請求數據等等
}
@Override
protected void initView() {
//TODO:初始化視圖 比如:recycleview的準備,添加adapter等等
mTvSample.setText("這是一個sample");
}
@Override
protected void initData(Bundle savedInstanceState) {
//TODO:初始化數據 比如:將數據加入到view中
}
@Override
protected void initEvent() {
//TODO:初始化事件監聽 比如:增加監聽器,下拉刷新,加載更多等等
}
}