Android开发中BaseActivity在程序设计对于项目的架构重要性不言而喻,一个好的BaseActivity设计可以让项目的Activity代码看起来更加简洁且易编写,同时BaseActivity也是MVC,MVP和MVVM架构体现。
BaseActivity使用场景
1 多个子类有公有的方法,并且逻辑基本相同时。
2 重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。
3 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。
①MVC的BaseActivity 没有加ButterKnife需要可以加上,EventBus也没加,需要的可以加上
public abstract class BaseActivity extends AppCompatActivity implements View.OnClickListener{
//获取TAG的activity名称
protected final String TAG = this.getClass().getSimpleName();
//设置子activity布局
FrameLayout frameLayout;
//title 如果 return null 则隐藏
RelativeLayout rlTitle;
//返回按钮
LinearLayout llBack;
//title文字
TextView tvTitleBase;
//右侧按钮
public Button btnRightBase;
LinearLayout llRightBase;
//获取上下文
public Context mContext;
//progressDialog 可以用自己自定义的Loading
private ProgressDialog progressdialog;
//是否有返回键
public boolean isHaveBack = true;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
//Activity管理
ActivityUtil.getInstance().addActivity(this);
//设置布局前处理一些逻辑
init(savedInstanceState);
//设置布局
if (setLayoutResourceID() != 0) {
setContentView(R.layout.activity_base);
//ButterKnife.bind(this); 如果有需要可以在这里设置
initBaseView();
}
//初始化控件 设置了ButterKnife 初始化控件就不需要了
initView();
//设置数据
initData();
//设置监听
initListener();
}
/**
* 设置布局前处理一些逻辑和设置
*
* @param savedInstanceState bundle
*/
protected void init(Bundle savedInstanceState) {
}
/**
* 基础View设置
*/
private void initBaseView() {
llBack = findViewById(R.id.ll_back_base);
tvTitleBase = findViewById(R.id.tv_title_base);
frameLayout = findViewById(R.id.fl_base_content);
rlTitle = findViewById(R.id.rl_title_base);
btnRightBase = findViewById(R.id.btn_right_base);
llRightBase = findViewById(R.id.ll_right_base);
if (StringUtil.isNotEmpty(initTitle())) {
tvTitleBase.setText(initTitle());
} else {
rlTitle.setVisibility(View.GONE);
}
if (isHaveBack) {
llBack.setVisibility(View.VISIBLE);
llBack.setOnClickListener(view -> finish());
} else {
llBack.setVisibility(View.GONE);
}
btnRightBase.setOnClickListener(view -> rightBtnClickListener());
View baseView = LayoutInflater.from(mContext).inflate(setLayoutResourceID(), frameLayout, false);
frameLayout.addView(baseView);
}
/**
* 设置布局
* return 布局
*/
@LayoutRes
protected abstract int setLayoutResourceID();
/**
* 初始化控件
*/
protected abstract void initView();
/**
* 设置title
*
* @return title
*/
protected abstract String initTitle();
/**
* 设置数据
*/
protected void initData() {
}
/**
* 设置监听
*/
protected void initListener() {
}
@Override
public void onClick(View view) {
}
/**
* 设置右边Button样式
*
* @param resource
*/
public void setRightBtnResource(int resource) {
if (resource != 0) {
llRightBase.setVisibility(View.VISIBLE);
btnRightBase.setBackground(ContextCompat.getDrawable(mContext, resource));
}
}
/**
* 右边Button的点击事件
*/
protected void rightBtnClickListener() {
}
/**
* show shotToast
*
* @param msg 提示内容
*/
public void showToast(String msg) {
if (StringUtil.isEmpty(msg)) {
return;
}
Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
}
/**
* showProgress
*
* @param msg 提示内容
*/
public void showProgress(String msg) {
if (progressdialog == null) {
progressdialog = new ProgressDialog(mContext);
}
progressdialog.setTitle("请等待...");
progressdialog.setMessage(msg);
progressdialog.show();
}
/**
* dismissProgress
*/
protected void dismissProgress() {
if (progressdialog != null) {
progressdialog.dismiss();
}
}
/**
* 普通跳转
*
* @param activity activity
*/
protected void jumpToActivity(Class<?> activity) {
startActivity(new Intent(mContext, activity));
}
/**
* 保证同一按钮在1秒内只会响应一次点击事件
*/
public abstract class OnSingleClickListener implements View.OnClickListener {
//两次点击按钮之间的间隔,目前为1000ms
private static final int MIN_CLICK_DELAY_TIME = 1000;
private long lastClickTime;
public abstract void onSingleClick(View view);
@Override
public void onClick(View view) {
long curClickTime = System.currentTimeMillis();
if ((curClickTime - lastClickTime) >= MIN_CLICK_DELAY_TIME) {
lastClickTime = curClickTime;
onSingleClick(view);
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityUtil.getInstance().removeActivity(this);
}
}
②BaseActivity布局(可以自定义,如果右上角有多个控件也可以自己添加)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/rl_title_base"
style="@style/Panel.Title">
<LinearLayout
android:id="@+id/ll_back_base"
android:layout_width="48dp"
android:layout_height="48dp"
android:gravity="center_vertical"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/account_ic_back"
android:clickable="false"
android:minWidth="0dp"
android:minHeight="0dp" />
</LinearLayout>
<TextView
android:id="@+id/tv_title_base"
style="@style/TextView.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:singleLine="true" />
<LinearLayout
android:id="@+id/ll_right_base"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:background="@drawable/selector_topbar_button"
android:gravity="center_vertical"
android:orientation="vertical"
android:visibility="gone">
<Button
android:id="@+id/btn_right_base"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/scan_icon"
android:clickable="false"
android:minWidth="0dp"
android:minHeight="0dp" />
</LinearLayout>
</RelativeLayout>
<FrameLayout
android:id="@+id/fl_base_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
③附上ActivityUtil(Activity管理类)
public class ActivityUtil{
private static final String TAG = "ActivityUtil";
/**
* 单一实例
*/
private static ActivityUtil sActivityUtil;
/**
* Activity堆栈 Stack:线程安全
*/
public Stack<Activity> mActivityStack = new Stack<>();
/**
* 私有构造器 无法外部创建
*/
private ActivityUtil() {
}
/**
* 获取单一实例 双重锁定
* @return this
*/
public static ActivityUtil getInstance() {
if (sActivityUtil == null) {
synchronized (ActivityUtil.class) {
if (sActivityUtil == null) {
sActivityUtil = new ActivityUtil();
}
}
}
return sActivityUtil;
}
/**
* 添加Activity到堆栈
*/
public void addActivity(Activity activity) {
mActivityStack.add(activity);
}
/**
* 移除堆栈中的Activity
* @param activity Activity
*/
public void removeActivity(Activity activity) {
if (activity != null && mActivityStack.contains(activity)) {
mActivityStack.remove(activity);
}
}
/**
* 获取当前Activity (堆栈中最后一个添加的)
* @return Activity
*/
public Activity getCurrentActivity() {
return mActivityStack.lastElement();
}
/**
* 获取指定类名的Activity
*/
public Activity getActivity(Class<?> cls) {
if (mActivityStack != null)
for (Activity activity : mActivityStack) {
if (activity.getClass().equals(cls)) {
return activity;
}
}
return null;
}
/**
* 结束当前Activity (堆栈中最后一个添加的)
*/
public void finishCurrentActivity() {
Activity activity = mActivityStack.lastElement();
finishActivity(activity);
}
/**
* 结束指定的Activity
* @param activity Activity
*/
public void finishActivity(Activity activity) {
if (activity != null && mActivityStack.contains(activity)) {
mActivityStack.remove(activity);
activity.finish();
}
}
/**
* 结束指定类名的Activity
* @param clazz Activity.class
*/
public void finishActivity(Class<?> clazz) {
for (Activity activity : mActivityStack) {
if (activity.getClass().equals(clazz)) {
finishActivity(activity);
break;
}
}
}
/**
* 结束所有Activity
*/
public void finishAllActivity() {
for (int i = mActivityStack.size() - 1; i >= 0; i--) {
if (mActivityStack.get(i) != null) {
finishActivity(mActivityStack.get(i));
}
}
mActivityStack.clear();
}
/**
* 结束某个Activity之外的所有Activity
*/
public void finishAllActivityExcept(Class<?> clazz) {
for (int i = mActivityStack.size() - 1; i >= 0; i--) {
if (mActivityStack.get(i) != null && !mActivityStack.get(i).getClass().equals(clazz)) {
finishActivity(mActivityStack.get(i));
}
}
}
/**
* 退出应用程序
*/
public void exitApp() {
try {
finishAllActivity();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.exit(0);
}
}
/**
* 判断某个Activity 界面是否在前台
* @param context
* @param className 某个界面名称
* @return
*/
public static boolean isForeground(Context context, String className) {
if (context == null || TextUtils.isEmpty(className)) {
return false;
}
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> list = am.getRunningTasks(1);
if (list != null && list.size() > 0) {
ComponentName cpn = list.get(0).topActivity;
if (className.equals(cpn.getClassName())) {
return true;
}
}
return false;
}
}
④基础用法 可以自己扩展方法
public class TestActivity extends BaseActivity {
Button button;
Button button2;
//设置布局
@Override
protected int setLayoutResourceID() {
return R.layout.activity_test;
}
//在设置布局之前做一些操作设置或者接收数据
@Override
protected void init(Bundle savedInstanceState) {
super.init(savedInstanceState);
//是否有返回按钮 默认有
//isHaveBack=false;
}
//初始化控件 如果用了ButterKnife 初始化控件就不需要了
@Override
protected void initView() {
button = findViewById(R.id.button_test);
button2 = findViewById(R.id.button_test2);
}
//给控件设置数据
@Override
protected void initData() {
super.initData();
//做网络请求前
showProgress("xxxx");
//网络请求结束
dismissProgress();
//toast short
showToast("xxx");
//普通跳转
//jumpToActivity(xxx.activity);
}
@Override
protected void initListener() {
super.initListener();
//设置1s内单次点击事件
button.setOnClickListener(new OnSingleClickListener() {
@Override
public void onSingleClick(View view) {
}
});
//普通点击事件
button2.setOnClickListener(this);
}
@Override
public void onClick(View view) {
super.onClick(view);
switch (view.getId()) {
case R.id.button_test2:
break;
default:
break;
}
}
//设置 title 如果没有title 可以 return null 就没有title了
@Override
protected String initTitle() {
return "测试title";
}
}
后续会推出基于MVP的BaseMVPActivity的封装,如果有自己需要的方法也可以自己抽出来放在BaseActivity中,本文主要是提供一个思路,具体实现根据个人需要。