Magren

Magren

Idealist & Garbage maker 🛸
twitter
jike

Android基類的設計

這兩天開始放寒假,在家待著也是待著,遂決定找星空以前 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:初始化事件監聽 比如:增加監聽器,下拉刷新,加載更多等等
    }
}
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。