我们想要开发一款APP,首要工作肯定是先把包结构建好,框架搭建起来,然后把基类封装,需要用到的第三方库导入项目等等一系列工作。今天我们就来说下如何完成这一套流程。
(注:每个人都有自己的代码风格,所以不存在哪种好,哪种不好,适合自己就可以了。)
通过本篇文章你可以Get到以下技能点:
1、新建项目的包结构如何搭建;
2、新建项目的常用基类的封装。
正文
包结构的搭建
提到分包大家肯定都有自己的方式,最常见的就是把activity放到一起、把fragment放到一起等等的。当然我也是这样分包的(嘿嘿)。下面就是我的分包图:
这里我是用了MVP模式,所以分包里面有一个mvp,如果看管老爷们不需要mvp就是简单点,那就把mvp换成去掉,把model、activity、fragment放到外面就可以了。
这里constants是放常量类,widget放的是自定义view的东西。别的包里面看包名就可以看出来里面要放什么东西,所以这里也不用过多解释了。各位看管老爷们看一下就行了。
常用基类的封装
下面才是本文的重点,常用基类的封装。我们按照顺序来,先从Application开始,废话不多说先上代码:
/**
* @author: X_Meteor
* @description: 自定义的BaseApplication
* @version: V_1.0.0
* @date: 2017/4/21 16:34
* @email: lx802315@163.com
*/
public class BaseApplication extends Application {
/**
* 维护一个全局的context对象
*/
public Context context;
/**
* 用于存放当前用户(如果有的话)
*/
// private static UserInfo currentUser;
//单例模式
private static BaseApplication myApplication = null;
public static BaseApplication getInstance() {
return myApplication;
}
/**
* 获取当前的用户对象
*
* @param currentUser
*/
// public UserInfo getCurrentUser() {
// UserInfo user = currentUser;
// if (user != null) {
// return user;
// }
// return null;
// }
/**
* 设置当前的用户对象
*
*/
// public void setCurrentUser(UserInfo currentUser) {
// this.currentUser = currentUser;
// }
/**
* 定义一个标记
*/
private static String TAG;
@Override
public void onCreate() {
super.onCreate();
//把TAG定义为当前类的类名
TAG = this.getClass().getSimpleName();
//由于Application类本身已经单例,所以直接按以下处理即可。
myApplication = this;
context = getApplicationContext();
//全局异常处理
if(Constants.isCollectException){
CrashHandlerUtils crashHandler = CrashHandlerUtils.getInstance();
crashHandler.init(getApplicationContext());
}
}
}
可以看到,在BaseApplication中,我们主要做了三件事:
- 获取当前系统使用用户(有用户模块的话)
- 定义了一个用于打印log的TAG,以当前类的类名为值
- 定义了一个全局错误异常类,在程序出现异常的时候可以捕获异常。(异常处理类后面会贴出)
下面再来BaseActivity:
/**
* @author: Meteor
* @description: 所有Activity的基类
* @version: V 1.0
* @date: 2016/12/28 0028 15:33
* @company:
* @email: lx802315@163.com
*/
public abstract class BaseActivity extends AppCompatActivity {
//声明一个构建着对象,用于创建警告对话框
private AlertDialog.Builder builder;
//用于创建一个进度条对话框
private ProgressDialog dialog;
//用于打印log
private final String TAG = "BaseActivity";
//声明一个活动管理栈
private static Stack<Activity> activities = new Stack<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//添加活动到活动栈中
activities.add(this);
//固定屏幕方向
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
//设置在activity启动的时候输入法默认不开启
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
initRootView();
ButterKnife.bind(this);
initView();
initData();
initListener();
//打印当前类名
String msg = this.getClass().getName();
LogUtils.print(msg);
}
/**
* 初始化根布局文件
*/
public abstract void initRootView();
/**
* 初始化控件
*/
public abstract void initView();
/**
* 初始化数据
*/
public abstract void initData();
/**
* 初始化接口
*/
public abstract void initListener();
/**
* 实现沉浸式通知栏,使通知栏和APP的标题颜色一样
*/
protected void immersiveNotification() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//导航栏透明
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//底部虚拟按钮透明
// getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
}
/**
* 显示一个警告对话框,无按钮,需要自己设置
*
* @param title 标题
* @param msg 内容
* @param flag 是否可以取消
* @return
*/
protected AlertDialog.Builder showAlertDialog(String title, String msg, boolean flag) {
if (builder == null) {
//创建一个构建者对象
builder = new AlertDialog.Builder(this);
builder.setTitle(title).setMessage(msg).setCancelable(flag);
}
return builder;
}
/**
* 功能:取消警告对话框
*/
protected void dismissAlertDialog(android.app.AlertDialog alertDialog) {
if (alertDialog != null) {
//取消警告对话框
alertDialog.dismiss();
}
}
/**
* 功能 :显示一个进度条对话框
*/
protected void showProcessDialog(String title, String msg, boolean falg) {
if (dialog == null) {
dialog = new ProgressDialog(this);
}
dialog.setTitle(title);
dialog.setMessage(msg);
dialog.setCancelable(falg);
dialog.show();
}
/**
* 功能 :取消一个进度条对话框
*/
protected void dismissProcessDialog() {
if (dialog != null) {
dialog.dismiss();
}
}
/**
* 判断用户是否登陆过
*
* @return true 为登陆成功 false 为没有登陆过
*/
protected boolean isLogin() {
//这里面做你自己的逻辑处理
return true;
}
/**
* 退出所有活动并且退出当前应用
*/
public static void exitApplication() {
for (Activity activity : activities) {
if (activity != null) {
activity.finish();
}
}
System.exit(0);
android.os.Process.killProcess(android.os.Process.myPid());
}
}
可以看到,在BaseActivity中我们做了很多处理:
- 定义了一个AlertDialog,警告对话框
- 定义了一个ProgressDialog,进度对话框
- 实现了一个判断用户是否登录的方法
- 维护了一个活动栈,并且开放了一个退出所有活动的方法
- 定义了抽象四个方法:initRootVeiw();initView;initData();initListener。
(注:这里的initRootView是为了使用butterknife专门定义的,我们需要在集成的子类中把setContentView放入其中)
具体可以看代码:BaseActivity的onCreate()
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//添加活动到活动栈中
activities.add(this);
//固定屏幕方向
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
//设置在activity启动的时候输入法默认不开启
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
initRootView();
//加入ButterKnife注解框架
ButterKnife.bind(this);
initView();
initData();
initListener();
//打印当前类名
String msg = this.getClass().getName();
LogUtils.print(msg);
}
继承的子类,MainActivity:
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void initRootView() {
setContentView(R.layout.activity_main);
}
@Override
public void initView() {
}
@Override
public void initData() {
}
@Override
public void initListener() {
}
}
下面再来BaseFragment:
/**
* @author: Meteor
* @description: 所有Fragment的基类
* @version:
* @date: 2016/12/28 0028 16:16
* @company:
* @email: lx802315@163.com
*/
public abstract class BaseFragment extends Fragment {
//定义一个用于重复View的回收池
private View contentView = null;
/**
* Fragment当前状态是否可见
*/
protected boolean isVisible;
private AlertDialog.Builder builder;
private AlertDialog alertDialog;
private ProgressDialog dialog;
//用于Butterknife 的绑定
Unbinder unbinder;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
if (contentView == null) {//判断回收池是否为空
contentView = initLayout(inflater, container, false);
unbinder = ButterKnife.bind(this, contentView);
}
if (contentView != null) {
unbinder = ButterKnife.bind(this, contentView);
return contentView;
}
return super.onCreateView(inflater, container, savedInstanceState);
}
/**
* 初始化Fragment的布局,当要创建试图时候调用
*
* @param inflater 布局填充器
* @param container ViewGroup
* @param b 标记
* @return view 返回视图
*/
protected abstract View initLayout(LayoutInflater inflater, ViewGroup container, boolean b);
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//初始化数据
initData(savedInstanceState);
}
/**
* 初始化数据,当ViewCreate被创建时调用此方法
* @param savedInstanceState
*/
protected abstract void initData(Bundle savedInstanceState);
@Override
public final void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (getUserVisibleHint()) {
isVisible = true;
onVisible();
} else {
isVisible = false;
onInvisible();
}
}
/**
* 可见
*/
protected void onVisible() {
lazyLoad();
}
/**
* 不可见
*/
protected void onInvisible() {
}
/**
* 延迟加载
* 子类必须重写此方法
*/
protected abstract void lazyLoad();
@Override
public final void onDestroyView() {
//移除当前视图,防止重复加载相同视图使得程序闪退
((ViewGroup) contentView.getParent()).removeView(contentView);
super.onDestroyView();
unbinder.unbind();
}
/**
* 判断用户是否登陆过
*
* @return true 为登陆成功 false 为没有登陆过
*/
protected boolean isLogin() {
return false;
}
/**
* 功能 :显示一个警告对话框
*/
protected void showAlertDialog(String title,String text){
if (builder==null){
//创建一个构建者对象
builder = new AlertDialog.Builder(getContext());
builder.setTitle(title).setMessage(text).setCancelable(false);
builder.setPositiveButton("设置", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//跳转到系统网络设置
Intent intent = new Intent(Settings.ACTION_WIRELESS_SETTINGS);
startActivity(intent);
}
}).setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//退出虚拟机
System.exit(0);
}
});
}
alertDialog = builder.show();
}
/**
* 功能:取消警告对话框
*/
protected void dismissAlertDialog(){
if (alertDialog!=null){
//取消警告对话框
alertDialog.dismiss();
}
}
/**
* 功能 :显示一个进度条对话框
*/
protected void showProcessDialog(String title,String msg,boolean falg){
if(dialog==null){
dialog = new ProgressDialog(getContext());
}
dialog.setTitle(title);
dialog.setMessage(msg);
dialog.setCancelable(falg);
dialog.show();
}
/**
* 功能 :取消一个进度条对话框
*/
protected void dismissProcessDialog(){
if(dialog!=null){
dialog.dismiss();
}
}
public interface BackHandledInterface {
public abstract void setSelectedFragment(BaseFragment selectedFragment);
}
}
这里除了跟BaseActivity 的相似的显示对话框外,主要多个懒加载方法,关于懒加载的知识,看官老爷们可以自行百度这里不过多解释。
子类继承使用如下:
/**
* @author: X_Meteor
* @description: 类描述
* @version: V_1.0.0
* @date: 2017/4/22 16:37
* @email: lx802315@163.com
*/
public class homeFragment extends BaseFragment {
@Override
protected View initLayout(LayoutInflater inflater, ViewGroup container, boolean b) {
View rootView = inflater.inflate(R.layout.activity_main, null);
return rootView;
}
@Override
protected void initData(Bundle savedInstanceState) {
}
@Override
protected void lazyLoad() {
}
}
到这里最常用的基类就封装完毕了,当然还是那句话,没有最好的只有最合适的自己的。项目已经上传 地址如下:
Demo
今天的内容就到此结束了,后面我会写一下rxjava2 + retrofit2 的网络请求框架的简单封装。欢迎大家共同探讨学习。