上一节讲到设计模式的观察者模式,实际上面向对象的设计模式有24种。但是我们不会一一的去讲,我们只挑在实际开发中使用频率高的而且必须要会使用的拿出来讲。如果要继续深入了解更多的同学可以另外去学习。这一节我们开始讲继承。
为什么继承那么重要呢?比如一个Activity,如果你在创建一个具体的XXActivity的时候只是继承了Activity,那么当需求发生变化的时候(比如要添加友盟统计代码),你需要去修改所有的Activity,不仅费时费力而且还很容易出错。再比如现在产品经理跟你说每个界面在加载数据的时候都要添加一个加载中动画。这个时候如果你的项目中如果有几十上百个Activity,那就得疯了。所以应该把都要用到的重复代码放在基类
写一个Activity的基类,比如BaseActivity 继承Activity来把所有界面都需要处理的逻辑抽象画出来或者直接写在基类。下面给出一个例子:
public abstract class BaseActivity extends Activity {
public MyHandler mHandler;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//如果所有的界面都需要状态栏沉浸效果直接写在基类
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Window window = getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//透明状态栏
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
//基类创建一个handler子类就能直接使用
mHandler = new MyHandler(this);
//这里把加载布局和加载数据几个步骤抽象化出来,在子类只需要重写initViews(),initData(),loadData()就行,而不需要知道
具体的执行步骤
int resId = getLayoutRes();
if (resId > 0) {
setContentView(resId);
}
initViews();
initData();
loadData();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
}
protected void onBackAction() {
finish();
}
protected static class MyHandler extends Handler {
private WeakReference<BaseActivity> wr;
public MyHandler(BaseActivity activity) {
wr = new WeakReference<BaseActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
if (wr != null && wr.get() != null) {
wr.get().consumeMessage(msg);
}
}
}
/**
* 加载数据
*/
protected void initData() {
}
/**
* 加载网络数据
*/
protected void loadData() {
}
/**
* 初始化控�?
*/
protected abstract void initViews();
/**
* 加载视图ID
*
* @return
*/
protected abstract int getLayoutRes();
protected boolean consumeMessage(Message msg) {
return false;
}
@Override
protected void onResume() {
super.onResume();
//统一添加友盟统计,子类不需要再写
String pName = setPagerName();
if (!TextUtils.isEmpty(pName)) {
MobclickAgent.onPageStart(pName);
}
MobclickAgent.onResume(this);
//Glide是谷歌推出的图片加载框架,在这里执行这一句,所有的界面在onresum的时候就能加载未加载完成的图片
Glide.with(this).resumeRequests();
}
@Override
protected void onPause() {
super.onPause();
String pName = setPagerName();
if (!TextUtils.isEmpty(pName)) {
MobclickAgent.onPageEnd(pName);
}
MobclickAgent.onPause(this);
Glide.with(this).pauseRequests();
}
@Override
protected void onStop() {
super.onStop();
Glide.with(this).onStop();
}
public abstract String setPagerName();
@Override
protected void onDestroy() {
super.onDestroy();
//在这里统一执行图片的回收和内存的回收,而releaseRes则是子类要实现的回收,这里定好回收步骤,子类就只要实现releaseRes回收自己的类里面该回收的
对象就可以了,而不需要理解其他的
releaseRes();
if (mHandler != null) {
mHandler.removeCallbacksAndMessages(null);
mHandler = null;
}
new Thread(){
@Override
public void run() {
Glide.get(BaseActivity.this).clearDiskCache();
}
}.start();
Glide.get(this).clearMemory();
System.gc();
}
/**
* 资源释放
*/
protected void releaseRes() {
ViewGroup viewGroup = (ViewGroup) findViewById(android.R.id.content);
if (viewGroup != null) {
viewGroup.removeAllViews();
viewGroup = null;
}
}
protected void postRequest() {
}
}
基类已经把所有的公共操作,包括布局加载、数据加载、对象回收,友盟统计,图片加载管理都封装好了,子类可以少写很多代码。
接着往下看,怎样给Activity添加统一样式的头部(红框内的头部)
public abstract class BaseTitleActivity extends BaseActivity {
//自定义头部布局(上图红框中的头部) private ActionBarLayout mActionBarLayout; @Override public void setContentView(int layoutResID) { setContentView(LayoutInflaterUtils.inflateView(this, layoutResID)); } @Override public void setContentView(View view) {
//自定义的头部布局,这里不需要知道这个布局是什么,只要知道时自定义的头部布局就好了 ViewGroup parentLayout = (ViewGroup) LayoutInflaterUtils.inflateView(this, R.layout.layout_title); LinearLayout childLayout = (LinearLayout) parentLayout.findViewById(R.id.layout_title_layout); //把子类的布局添加到头部布局中,实现所有继承该类的子Activity都有统一的头部布局
childLayout.addView(view, new LinearLayout.LayoutParams(-1, -1)); initActionBarView(childLayout); initActionBarData(); addOtherView(parentLayout); super.setContentView(parentLayout); } protected boolean toShowBackIcon(){ return true; } protected void addOtherView(ViewGroup parentLayout) { } private void initActionBarView(View view){ mActionBarLayout = (ActionBarLayout) view.findViewById(R.id.layout_title_layout); mActionBarLayout.setOnBackListener(new OnClickListener() { @Override public void onClick(View v) { onBackAction();//点击头部返回按钮 } }); mActionBarLayout.setOnActionBarMenuAction(new ActionBarLayout.OnActionBarMenuAction() { @Override public void onMenuAction(int menuId) { actionMenuOnClick(menuId);//点击头部的兑换记录菜单 } }); } /** * 配置头部数据 */ protected abstract void initActionBarData(); @Override public void setTitle(int titleId) {//设置头部的标题 mActionBarLayout.setTitle(titleId); if(toShowBackIcon()){ mActionBarLayout.showBackIcon(View.VISIBLE); }else{ mActionBarLayout.showBackIcon(View.GONE); } } @Override public void setTitle(CharSequence title) { mActionBarLayout.setTitle(title); if(toShowBackIcon()){ mActionBarLayout.showBackIcon(View.VISIBLE); }else{ mActionBarLayout.showBackIcon(View.GONE); } } /** * 头部返回键事�? */ protected void onBackAction() { finish(); } protected void addMenuItem(int... resId){//给头部添加菜单按钮 mActionBarLayout.addMenu(resId); } protected View addMenuItem(int resId){ mActionBarLayout.addMenu(resId); return null; } protected void addMenuItem(int viewId, View view){ mActionBarLayout.addMenu(viewId, view); } protected void updateMenuItem(int dstId, int resId) { mActionBarLayout.updateMenuItem(dstId, resId); } protected void removeMenuItem(int... resId) { mActionBarLayout.removeMenuItem(resId); } protected void actionMenuOnClick(int menuId){ } protected void actionSearchClick(String keyWord){ } protected void setActionBarLayoutVisibility(int visibility){ mActionBarLayout.findViewById(R.id.layout_title).setVisibility(visibility); } @Override protected void releaseRes() { if(mActionBarLayout != null){ mActionBarLayout.removeAllViews(); mActionBarLayout = null; } super.releaseRes(); } }
所以只要一个类继承BaseTitleActivity,就可以拥有统一的头部布局,只要在子类中调用setTitle()就可以设置标题,
调用addMenuItem()就可以在头部右侧添加菜单。所以到了具体的Activity类就很简单了
比如这个登录Activity
public class LoginActivity extends BaseTitleActivity implements OnClickListener private TextView mTvForget; private EditText mUserNameEdit; private EditText mPasswordEdit; private TextView mTvLogin; private TextView mTvPhoneLogin; private Button mBtnShowPsw; //只需要在这里设置标题和菜单就ok了 @Override protected void initActionBarData() { setTitle("用户登录"); addMenuItem(R.string.zhuce); } @Override protected void actionMenuOnClick(int menuId) { super.actionMenuOnClick(menuId); ActivityUtils.startRegisterActivity(this, mFromKey, mFromName); } @Override protected void initViews() { mUserNameEdit = (EditText)findViewById(R.id.activity_login_edt_phone); mPasswordEdit = (EditText)findViewById(R.id.activity_login_edt_psw); mTvForget = (TextView)findViewById(R.id.activity_login_tv_forget); mTvLogin = (TextView)findViewById(R.id.activity_login_tv_login); mBtnShowPsw = (Button)findViewById(R.id.activity_login_btn_showpsw); mTvPhoneLogin = (TextView)findViewById(R.id.activity_login_tv_phone_login); } @Override protected int getLayoutRes() { return R.layout.activity_login; } @Override public String setPagerName() { return "登入"; } @Override protected void releaseRes() { super.releaseRes(); UserInfoObserver.getInst().removeUserInfoObserver(this); UserManager.getInst().removeLoginListener(this); mUserNameEdit = null; mPasswordEdit = null; if(mTvForget!=null){ mTvForget.setOnClickListener(null); mTvForget = null; } if(mTvLogin!=null){ mTvLogin.setOnClickListener(null); mTvLogin = null; } if(mTvPhoneLogin!=null){ mTvPhoneLogin.setOnClickListener(null); mTvPhoneLogin = null; } if(mBtnShowPsw!=null){ mBtnShowPsw.setOnClickListener(null); mBtnShowPsw = null; } } }