功能 / 分析Activity基类(旧版)
版本 / v4.1.7
在分析主页面(MainActivity)之前,我们需要知道Activity基类(BaseActivity)都封装了哪些功能,对外提供了哪些共通的方法。
此处使用了设计模式中的模板方法。我们先来看看它的定义是什么。定义一个功能的框架或者说骨架,一部分功能是确定的,一部分功能是不确定的,先把确定的部分确定下来,把不确定的部分延迟到子类中实现的设计模式称之为模板方法。
其优点是通过继承基类,从而具备共通的属性和行为,减少重复的工作。缺点是提高了耦合度,同时由于有些功能在部分画面中使用不到,画面渲染的时间也会加长,牺牲部分的性能,所以需要权衡哪些功能通过继承的方式(基类的形式)提供,哪些功能通过组合的方式(工具类的形式)提供。
关联代码文件:
通过阅读源码,我们可以知道BaseActivity主要封装了以下功能。
相关文件:
说明:
public abstract class BaseActivity extends AppCompatActivity implements
DialogControl, View.OnClickListener, BaseViewInterface {
protected LayoutInflater mInflater;
protected ActionBar mActionBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 讲解:在清单文件中已经设置全局主题样式了(App_Theme_Light),
// 因为此处优先级高,所以清单文件中Activity作用域下的主题将会被覆盖
// 此处应删除
setTheme(R.style.App_Theme_Light);
onBeforeSetContentLayout();
if (getLayoutId() != 0) {
setContentView(getLayoutId());
}
mActionBar = getSupportActionBar();
mInflater = getLayoutInflater();
......
// 讲解:可以使用JetPack的成员组件Databinding绑定组件,ButterKnife应废弃
// 通过注解绑定控件
ButterKnife.bind(this);
init(savedInstanceState);
initView();
// 讲解:此处初始化数据并不合理,要优先加载页面,数据加载后置。
initData();
......
}
protected void onBeforeSetContentLayout() {
}
protected void init(Bundle savedInstanceState) {
}
protected int getLayoutId() {
return 0;
}
}
protected ActionBar mActionBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
......
mActionBar = getSupportActionBar();
if (hasActionBar()) {
initActionBar(mActionBar);
}
......
}
// 讲解:是否含有ActionBar,可以通过设置主题样式便可以实现。
protected boolean hasActionBar() {
return getSupportActionBar() != null;
}
// 讲解:代码中mActionBar可以使用参数actionBar代替
protected void initActionBar(ActionBar actionBar) {
if (actionBar == null)
return;
if (hasBackButton()) {
mActionBar.setDisplayHomeAsUpEnabled(true);
mActionBar.setHomeButtonEnabled(true);
} else {
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE);
actionBar.setDisplayUseLogoEnabled(false);
int titleRes = getActionBarTitle();
if (titleRes != 0) {
actionBar.setTitle(titleRes);
}
}
}
// 讲解:通过资源Id设置标题
public void setActionBarTitle(int resId) {
if (resId != 0) {
setActionBarTitle(getString(resId));
}
}
// 讲解:通过文本设置标题
public void setActionBarTitle(String title) {
if (TextUtils.isEmpty(title)) {
title = getString(R.string.app_name);
}
if (hasActionBar() && mActionBar != null) {
mActionBar.setTitle(title);
}
}
// 讲解1:在子类中重写该方法即可
protected boolean hasBackButton() {
return false;
}
protected void initActionBar(ActionBar actionBar) {
if (actionBar == null)
return;
// 讲解2:当设置有返回按钮的时候,在ActionBar显示返回按钮
if (hasBackButton()) {
mActionBar.setDisplayHomeAsUpEnabled(true);
mActionBar.setHomeButtonEnabled(true);
} else {
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE);
actionBar.setDisplayUseLogoEnabled(false);
int titleRes = getActionBarTitle();
if (titleRes != 0) {
actionBar.setTitle(titleRes);
}
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// 讲解3:点击ActionBar上的返回按钮时,返回上一级页面
case android.R.id.home:
onBackPressed();
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
此处应先定义接口,然后根据需要提供实现。同时只能观测到用户什么时候打开页面,什么时候关闭页面。用户点击什么按钮等事件没有观测到,收集的数据比较有限,不能给运维提供强有力的支持,需要改进。
private final String packageName4Umeng = this.getClass().getName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
......
// 讲解初始化代理
MobclickAgent.setDebugMode(false);
MobclickAgent.openActivityDurationTrack(false);
MobclickAgent.setScenarioType(this, MobclickAgent.EScenarioType.E_UM_NORMAL);
}
@Override
protected void onPause() {
super.onPause();
MobclickAgent.onPageEnd(this.packageName4Umeng);
// 讲解:此处设置错误,应为MobclickAgent.onPause(this)
MobclickAgent.onResume(this);
......
}
@Override
protected void onResume() {
super.onResume();
MobclickAgent.onPageStart(this.packageName4Umeng);
MobclickAgent.onResume(this);
}
路径:app/src/main/AndroidManifest.xml
<manifest>
<application>
<meta-data
android:name="UMENG_APPKEY"
android:value="53cb520c56240bbd7d076ce5" />
<meta-data
android:name="UMENG_CHANNEL"
android:value="${UMENG_CHANNEL}" />
application>
manifest>
系统在逐步迭代后,使用了至少四种提示框,SimplexToast应向上抽取成全局工具类,
以组合的方式在需要的位置调用。此处的代码应删除比较合理。
public void showToast(int msgResid, int icon, int gravity) {
showToast(getString(msgResid), icon, gravity);
}
public void showToast(String message, int icon, int gravity) {
CommonToast toast = new CommonToast(this);
toast.setMessage(message);
toast.setMessageIc(icon);
toast.setLayoutGravity(gravity);
toast.show();
}
相关文件:
成员变量说明:
private boolean _isVisible;
private ProgressDialog _waitDialog;
@Override
public ProgressDialog showWaitDialog() {
return showWaitDialog(R.string.loading);
}
@Override
public ProgressDialog showWaitDialog(int resid) {
return showWaitDialog(getString(resid));
}
@Override
public ProgressDialog showWaitDialog(String message) {
if (_isVisible) {
if (_waitDialog == null) {
_waitDialog = DialogHelper.getProgressDialog(this, message);
}
if (_waitDialog != null) {
_waitDialog.setMessage(message);
_waitDialog.show();
}
return _waitDialog;
}
return null;
}
@Override
public void hideWaitDialog() {
if (_isVisible && _waitDialog != null) {
try {
_waitDialog.dismiss();
_waitDialog = null;
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
路径:app/src/main/res/values/strings.xml
<resources>
<string name="loading">加载中…string>
resources>
分析完以后才发现,原来是旧版Activity基类,已经被废弃了,但是代码文件仍然被保留没有被删除,也没有添加已过时注解,建议改进。
通过旧版Activity基类源码的分析,笔者有以下的观点供大家参考: