从零开始搭建一个主流项目框架(一)—简单的框架
2018-02-23 12:21
686 查看
个人博客:haichenyi.com。感谢关注
开发工具Android Studio3.0,还在用eclipse的同鞋,强烈推荐你跨出这一步,你会发现一个新的世界。android studio都出来这么久了,你还在远古时代做开发,说句不好听的,你完全与时代脱轨,你不适合做开发(纯属个人观点)
本篇就只有三部分,第一部分就是新建一个Application,第二部分就是BaseActivity,第三部分就是BaseFragment
如上代码,我这里就初始化了一个全局application单例对象,还初始化square公司出品的一个内存检测工具,用于检测你项目中内存泄漏情况。便于你优化项目。
如上图所示,这个就是清单文件,在application结点下面,添加name标签,内容就是你创建的application的名字。这里你还需要添加两个内存检测的依赖。
如上图所示,首先把你的项目结构视图切换到Project,打开你的app目录下的build.gradle文件,在dependencies结点下面(只要是添加开源库都是在该结点下面,后面就不说了),添加如下两行代码:
最后的1.5.4是版本号,你可以在github上面搜索leakcanary,找最新的版本
上面是目前BaseActivity代码,注释写的很清楚,你会发现BaseView你并没有,下面我给出BaseView的代码
BaseView就是一个接口,是所有V层的基类,代码很简单,Toast方法,显示隐藏加载的对话框方法,检验token是否过期的方法,finish当前页面的方法。什么?Toast方法你没有,下面我贴出来我的Toast的工具类
上面我贴出了三个类,这里我要说明的是,我又创建了两个package,一个是base,一个是utils,我把BaseActivity,BaseView,MyApplication放在base包下面,Toast的工具类放在utils包下面
再就是添加一些常用的东西了,这里我没有用黄油刀,用过一段时间之后,感觉他的每个控件都是全局的,有点占内存,就放弃了。我下面贴出BaseActivity新增的伪代码:
这里我需要说明的是,新增了一个开源框架,就是设置状态栏背景颜色的systembartint。
再就是设置activity标题内容,左边,右边的内容,左边右边可能是文字,也可能是图片。所以,我在用的时候,都是用的TextView,ImageView,不能设置文字。方法如下:
可以看到上面的方法返回值都是BaseActivity,这样做的目的就只有一个,可以连点,写一个方法之后,可以接着点写下一个方法,不用写一个方法就要加分号,就换一行写下一个方法。
还要加一句,在你的app主题里面添加两个item,也就是你的res目录下面的style:
我这里贴出我目前的style的图片
下面有一个LineHorizontal样式,就是你toolbar下面的那个横线
两者在布局抽象方法里面有一点区别,Activity的传了Boundle参数,Fragment没有传,因为Fragment可以通过getArguments()方法获取到这个对象,而Activity不能获取到。
项目链接
目的
首先先说出,最终的目的是现在主流的MVP+RxJava+Retrofit+OkHttp框架。让大家心里有底开发工具Android Studio3.0,还在用eclipse的同鞋,强烈推荐你跨出这一步,你会发现一个新的世界。android studio都出来这么久了,你还在远古时代做开发,说句不好听的,你完全与时代脱轨,你不适合做开发(纯属个人观点)
本篇就只有三部分,第一部分就是新建一个Application,第二部分就是BaseActivity,第三部分就是BaseFragment
Application
首先你得有application类,去初始化应用只用初始化一次的内容,继承Application,然后在清单文件里面注册。package com.haichenyi.myproject; import android.app.Application; import com.squareup.leakcanary.LeakCanary; /** * Author: 海晨忆 * Date: 2018/2/23 * Desc: */ public class MyApplication extends Application { private static MyApplication instance; public static MyApplication getInstance() { return instance; } private void setInstance(MyApplication instance) { MyApplication.instance = instance; } @Override public void onCreate() { super.onCreate(); setInstance(this); initLeakCanary(); } /** * 初始化内存检测工具 */ private void initLeakCanary() { if (LeakCanary.isInAnalyzerProcess(this)) { return; } LeakCanary.install(this); } }
如上代码,我这里就初始化了一个全局application单例对象,还初始化square公司出品的一个内存检测工具,用于检测你项目中内存泄漏情况。便于你优化项目。
如上图所示,这个就是清单文件,在application结点下面,添加name标签,内容就是你创建的application的名字。这里你还需要添加两个内存检测的依赖。
如上图所示,首先把你的项目结构视图切换到Project,打开你的app目录下的build.gradle文件,在dependencies结点下面(只要是添加开源库都是在该结点下面,后面就不说了),添加如下两行代码:
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4' debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4'
最后的1.5.4是版本号,你可以在github上面搜索leakcanary,找最新的版本
BaseActivity
创建基类BaseActivity,也就是所有Activity的父类。还有一个基类的接口BaseView,BaseActivity继承刚才添加的依赖的SupportActivity类,实现BaseView接口,并且实现点击事件的接口(选择实现,你要是不乐意在基类里面写,你可以在你自己的子类里面重新实现一遍也是可以的)。代码如下:每个方法注释写的很清楚,就不用一一解释了package com.haichenyi.myproject.base; import android.app.AlertDialog; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.support.annotation.Nullable; import android.view.Window; import android.widget.ProgressBar; import com.haichenyi.myproject.utils.ToastUtils; import me.yokeyword.fragmentation.SupportActivity; /** * Author: 海晨忆 * Date: 2018/2/23 * Desc: */ public abstract class BaseActivity extends SupportActivity implements BaseView { private AlertDialog loadingDialog; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); } /** * Toast 提示用户 * @param msg 提示内容String */ @Override public void showTipMsg(String msg) { ToastUtils.showTipMsg(msg); } /** * Toast 提示用户 * @param msg 提示内容res目录下面的String的int值 */ @Override public void showTipMsg(int msg) { ToastUtils.showTipMsg(msg); } /** * 网络请求的时候显示正在加载的对话框 */ @Override public void showLoading() { if (null == loadingDialog) { loadingDialog = new AlertDialog.Builder(this).setView(new ProgressBar(this)).create(); loadingDialog.setCanceledOnTouchOutside(false); Window window = loadingDialog.getWindow(); if (null != window) { window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); } } if (!loadingDialog.isShowing()) { loadingDialog.show(); } } /** * 网络请求完成时隐藏加载对话框 */ @Override public void 4000 hideLoading() { if (null != loadingDialog) { if (loadingDialog.isShowing()) { loadingDialog.dismiss(); } loadingDialog = null; } } @Override public void invalidToken() { //用于检测你当前用户的token是否有效,无效就返回登录界面,具体的业务逻辑你自己实现 //如果需要做到实时检测,推荐用socket长连接,每隔10秒发送一个验证当前登录用户token是否过期的请求 } /** * Finish当前页面,最好实现onBackPressedSupport(),这个方法会有一个退栈操作, * 开源框架实现的,我们不用管 */ @Override public void myFinish() { onBackPressedSupport(); } @Override public void onBackPressedSupport() { super.onBackPressedSupport(); } }
上面是目前BaseActivity代码,注释写的很清楚,你会发现BaseView你并没有,下面我给出BaseView的代码
package com.haichenyi.myproject.base; import android.support.annotation.StringRes; /** * Author: 海晨忆 * Date: 2018/2/23 * Desc: */ public interface BaseView { void showTipMsg(String msg); void showTipMsg(@StringRes int msg); void showLoading(); void hideLoading(); void invalidToken(); void myFinish(); }
BaseView就是一个接口,是所有V层的基类,代码很简单,Toast方法,显示隐藏加载的对话框方法,检验token是否过期的方法,finish当前页面的方法。什么?Toast方法你没有,下面我贴出来我的Toast的工具类
/** * Author: 海晨忆. * Date: 2017/12/21 * Desc: 实时更新的Toast工具类 */ public final class ToastUtils { private static Toast toast; private ToastUtils() { throw new RuntimeException("工具类不允许创建对象"); } @SuppressWarnings("all") private static void init() { if (toast == null) { toast = Toast.makeText(MyApplication.getInstance(), "", Toast.LENGTH_SHORT); } } public static void showTipMsg(String msg) { if (null == toast) { init(); } toast.setText(msg); toast.show(); } public static void showTipMsg(@StringRes int msg) { if (null == toast) { init(); } toast.setText(msg); toast.show(); } }
上面我贴出了三个类,这里我要说明的是,我又创建了两个package,一个是base,一个是utils,我把BaseActivity,BaseView,MyApplication放在base包下面,Toast的工具类放在utils包下面
再就是添加一些常用的东西了,这里我没有用黄油刀,用过一段时间之后,感觉他的每个控件都是全局的,有点占内存,就放弃了。我下面贴出BaseActivity新增的伪代码:
/** * 保存当前activity对象,在OnCreate里面添加,记得在OnDestroy里面移除 * 有什么用呢? * 比方说有一个需求,让你在任意位置弹出对话框,弹对话框又需要一个context对象,这个时候, * 你就只用传当前list的最上层的activity对象就可以了 * 当然还有其他需求 */ public static List<BaseActivity> activities = new ArrayList<>(); private Toolbar toolbar; private TextView tvToolbarTitle; private TextView tvToolbarRight; private TextView tvBack; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); activities.add(this); //强制竖屏(不强制加) setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); int layoutId = getLayoutId(savedInstanceState); View inflate = getLayoutInflater().inflate(R.layout.activity_base, toolbar, false); LinearLayout rootLinearLayout = inflate.findViewById(R.id.ll_layout_base_activity); //没有布局的时候传0 if (0 == layoutId) { setContentView(rootLinearLayout); } else { View rootView = getLayoutInflater().inflate(layoutId, rootLinearLayout, true); setContentView(rootView); } stateBar(); initView(); initData(); setOnClick(R.id.tv_back_base_activity); } /** * 设置点击事件. * * @param ids 被点击View的ID * @return {@link BaseActivity} */ public BaseActivity setOnClick(@IdRes int... ids) { View view; for (int id : ids) { view = findViewById(id); if (null != view) { view.setOnClickListener(this); } } return this; } /** * 设置点击事件. * * @param views 被点击View * @return {@link BaseActivity} */ public BaseActivity setOnClick(View... views) { for (View view : views) { view.setOnClickListener(this); } return this; } /** * 获取当前布局对象 * * @param savedInstanceState 这个是当前activity保存的数据,最常见的就是横竖屏切换的时候, * 数据丢失问题 * @return 当前布局的int值 */ protected abstract int getLayoutId(Bundle savedInstanceState); @Override protected void onDestroy() { activities.remove(this); super.onDestroy(); } protected void initData() { } protected void initView() { toolbar = findViewById(R.id.toolbar_base_activity); tvToolbarTitle = findViewById(R.id.tv_title_base_activity); tvToolbarRight = findViewById(R.id.tv_right_base_activity); } /** * 设置状态栏背景颜色,不能改变状态栏内容的颜色 */ private void stateBar() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); } SystemBarTintManager tintManager = new SystemBarTintManager(this); tintManager.setStatusBarTintEnabled(true); tintManager.setNavigationBarTintEnabled(true); tintManager.setTintColor(Color.parseColor("#000000")); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.tv_back_base_activity: onBackPressedSupport(); break; default: break; } }
这里我需要说明的是,新增了一个开源框架,就是设置状态栏背景颜色的systembartint。
implementation 'com.readystatesoftware.systembartint:systembartint:1.0.3'
再就是设置activity标题内容,左边,右边的内容,左边右边可能是文字,也可能是图片。所以,我在用的时候,都是用的TextView,ImageView,不能设置文字。方法如下:
public BaseActivity setTitles(CharSequence title) { tvToolbarTitle.setText(title); return this; } /** * 初始化toolbar的内容 * @param isShowToolbar 是否显示toolbar * @param isShowBack 是否显示左边的TextView * @param isShowMore 是否显示右边的TextView * @return 当前activity对象,可以连点 */ protected BaseActivity initToolbar(boolean isShowToolbar, boolean isShowBack, boolean isShowMore) { setSupportActionBar(toolbar); ActionBar actionBar = getSupportActionBar(); if (null != actionBar) { if (isShowToolbar) { actionBar.show(); tvBack = findViewById(R.id.tv_back_base_activity); TextView textView = findViewById(R.id.tv_right_base_activity); if (null != tvBack && null != textView) { tvBack.setVisibility(isShowBack ? View.VISIBLE : View.INVISIBLE); textView.setVisibility(isShowMore ? View.VISIBLE : View.INVISIBLE); } } else { actionBar.hide(); } } return this; } public BaseActivity setToolbarBack(int colorId) { toolbar.setBackgroundColor(getResources().getColor(colorId)); return this; } @SuppressWarnings("unused") public BaseActivity setMyTitle(String title) { tvToolbarTitle.setText(title); return this; } public BaseActivity setMyTitle(@StringRes int stringId) { tvToolbarTitle.setText(stringId); return this; } public void setMoreTitle(String moreTitle) { tvToolbarRight.setText(moreTitle); } public BaseActivity setMoreTitle(@StringRes int stringId) { tvToolbarRight.setText(stringId); return this; } /** * 设置左边内容. * * @param leftTitle 内容 * @return {@link BaseActivity} */ public BaseActivity setLeftTitle(String leftTitle) { if (tvBack != null) { tvBack.setBackground(null); tvBack.setText(leftTitle); } return this; } /** * 设置左边内容. * * @param leftTitle 内容 */ public void setLeftTitle(@StringRes int l d62d eftTitle) { if (tvBack != null) { tvBack.setBackground(null); tvBack.setText(leftTitle); } } @SuppressWarnings("unused") protected BaseActivity setMoreBackground(int resId) { tvToolbarRight.setBackgroundResource(resId); return this; }
可以看到上面的方法返回值都是BaseActivity,这样做的目的就只有一个,可以连点,写一个方法之后,可以接着点写下一个方法,不用写一个方法就要加分号,就换一行写下一个方法。
还要加一句,在你的app主题里面添加两个item,也就是你的res目录下面的style:
<item name="windowActionBar">false</item> <item name="windowNoTitle">true</item>
我这里贴出我目前的style的图片
下面有一个LineHorizontal样式,就是你toolbar下面的那个横线
BaseFragment
BaseFragment跟BaseActivity的逻辑是差不多的,我这里就贴出代码package com.haichenyi.myproject.base; import android.os.Bundle; import android.support.annotation.IdRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.haichenyi.myproject.utils.ToastUtils; import me.yokeyword.fragmentation.SupportFragment; /** * Author: 海晨忆 * Date: 2018/2/23 * Desc: */ public abstract class BaseFragment extends SupportFragment implements BaseView, View.OnClickListener { protected boolean isInit; private View rootView; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { int layoutRes = layoutRes(); if (0 != layoutRes) { return inflater.inflate(layoutRes, null); } else { return super.onCreateView(inflater, container, savedInstanceState); } } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); rootView = view; } @Override public void onLazyInitView(@Nullable Bundle savedInstanceState) { super.onLazyInitView(savedInstanceState); isInit = true; init(); } protected <T extends View> T findViewById(@IdRes int id) { return rootView.findViewById(id); } /** * 设置点击事件. * * @param ids 被点击View的ID * @return {@link BaseFragment} */ public BaseFragment setOnClick(@IdRes int... ids) { for (int id : ids) { rootView.findViewById(id).setOnClickListener(this); } return this; } /** * 设置点击事件. * * @param views 被点击View的ID * @return {@link BaseFragment} */ public BaseFragment setOnClick(View... views) { for (View view : views) { view.setOnClickListener(this); } return this; } protected abstract void init(); @Override public void onDestroy() { rootView = null; super.onDestroy(); } protected abstract int layoutRes(); @Override public void showTipMsg(String msg) { ToastUtils.showTipMsg(msg); } @Override public void showTipMsg(int msg) { ToastUtils.showTipMsg(msg); } @Override public void showLoading() { BaseActivity activity = (BaseActivity) getActivity(); /*if (activity instanceof BaseMvpActivity) { activity.showLoading(); }*/ } @Override public void hideLoading() { BaseActivity activity = (BaseActivity) getActivity(); /*if (activity instanceof BaseMvpActivity) { activity.hideLoading(); }*/ } @Override public void invalidToken() { BaseActivity activity = (BaseActivity) getActivity(); /*if (activity instanceof BaseMvpActivity) { activity.invalidToken(); }*/ } @Override public void onClick(View v) { } @Override public void myFinish() { onBackPressedSupport(); } }
两者在布局抽象方法里面有一点区别,Activity的传了Boundle参数,Fragment没有传,因为Fragment可以通过getArguments()方法获取到这个对象,而Activity不能获取到。
总结
到此,一个简单的项目框架就出来了,目前还是框架的第一步,是一个雏形,还不包括MVP,dagger等等,下一篇就加上MVP,我这个人有个好习惯,就是喜欢写注释,我注释写的很清楚,是干什么用的,我也衷心的希望,你能写好注释。项目链接
相关文章推荐
- 从零开始搭建一个主流项目框架(二)—MVP+Dagger2
- 从零开始搭建一个主流项目框架(六)——Socket网络编程
- 从零开始搭建一个主流项目框架(五)—GreenDao的增删改查
- 从零开始搭建一个主流项目框架(三)—RxJava2.0+Retrofit2.0+OkHttp
- 从零开始搭建一个主流项目框架(七)—— 权限申请(Android 6.0)
- 从零开始搭建 一个完善的 MVP模式开发框架(一),MVP模式的简单介绍篇
- 使用idea搭建一个简单的SSM框架:(1)使用idea创建maven项目
- Arms是一个整合了大量主流开源项目的Android Mvp快速搭建框架
- 从零开始搭建一个完善的MVP开发框架(五),通过组件化开发优化项目的结构
- 发布一个开源项目,基于thinkphp框架搭建的一个简单框架
- 从零开始搭建一个项目框架MVVM(OC)
- 一个简单的NetCore项目:1 - 搭建框架,生成数据库
- 【从零开始写一个简单的ImageLoader框架】项目介绍
- 使用Node.js的express框架搭建一个简单项目并且添加了一个路由
- Dubbo入门---搭建一个最简单的Demo框架
- Dubbo入门---搭建一个最简单的Demo框架
- 自己动手搭建一个移动端React+Redux+Webpack3项目框架
- 使用Spring MVC 、Spring、 Mybatis搭建一个简单的项目
- vue vuex vue-router vue-resource 简单的搭建一个 vue 小项目
- SSM做一个简单的网上商城-搭建项目