BaseProject快速构建自己的APP

不飞则已,一飞冲天;不鸣则已,一鸣惊人。这篇文章主要讲述BaseProject快速构建自己的APP相关的知识,希望能为你提供帮助。
关于BaseProjectBaseProject是一个快速构建app工程的开源项目,目的是为了更加方便的初始化一个工程,省去编写或者导入BaseActivity,BaseFragment,网络请求,工具类等基础又实用的代码。让你更加专注去实现自己产品需求,业务逻辑,而不是浪费时间在重复的工作上!
https://github.com/flyzend/BaseProject
如何依赖BaseProject

BaseProject快速构建自己的APP

文章图片

1. 在project.gradle 文件中添加 maven { url “https://jitpack.io” } 如下所示
allprojects { repositories { jcenter() maven { url "https://jitpack.io" } } }```2. 在app.gradle 文件中添加依赖,如下所示 ``` dependencies { compile ‘com.github.flyzend:BaseProject:V1.0.1‘ }

BaseProject帮你完成了下面的工作BaseApplication**自己的工程定义一个Application并继承BaseApplication
并且在androidManifest.xml中对Application节点改成你自己的Application如:**
android:name=”.MyApplication”
PreferenceUtils 以及FileDownloader 初始化操作
PreferenceUtils 是SharePreference管理类,封装SharePreference的put ,get ,remove,clear操作。
/** * 存入某个key对应的value值 * * @param key * @param value */ public void put(String key, Object value) { Editor edit = mSharedPreferences.edit(); if (value instanceof String) { edit.putString(key, (String) value); } else if (value instanceof Integer) { edit.putInt(key, (Integer) value); } else if (value instanceof Boolean) { edit.putBoolean(key, (Boolean) value); } else if (value instanceof Float) { edit.putFloat(key, (Float) value); } else if (value instanceof Long) { edit.putLong(key, (Long) value); } edit.apply(); }/** * 得到某个key对应的值 * * @param key * @param defValue * @return */ public Object get(String key, Object defValue) { if (defValue instanceof String) { return mSharedPreferences.getString(key, (String) defValue); } else if (defValue instanceof Integer) { return mSharedPreferences.getInt(key, (Integer) defValue); } else if (defValue instanceof Boolean) { return mSharedPreferences.getBoolean(key, (Boolean) defValue); } else if (defValue instanceof Float) { return mSharedPreferences.getFloat(key, (Float) defValue); } else if (defValue instanceof Long) { return mSharedPreferences.getLong(key, (Long) defValue); } return null; }

你可以在代码中直接使用PreferenceUtils来存储配置项
比如常见配置项:用户是否登录
PreferenceUtils.getInstance().put("is_login",true); //设置登录配置项PreferenceUtils.getInstance().get("is_login",false); //获取登录配置项,false为默认值

或者你可以更优雅的在自己的工程中编写一个设置辅助类:SettingUtils.java,并且写一个存储用户是否登录的的配置。你可以根据需求来写自己需要的配置项。
public class SettingUtils { private static SettingUtils instance; private PreferenceUtils preferenceUtils; private static final String IS_LOGIN = "is_login"; //用户是否登录public void setIsLogin(boolean isLogin){ preferenceUtils.put(IS_LOGIN,isLogin); }public boolean getIsLogin(){ return (Boolean) preferenceUtils.get(IS_LOGIN,false); }/** * 创建一个新的实例 SettingsUtils. */ private SettingUtils() { preferenceUtils = PreferenceUtils.getInstance(); }public static synchronized SettingUtils getInstance(){ if (instance == null) { instance = new SettingUtils(); } return instance; }public void clearSettings() { preferenceUtils.clear(); } }

这样你代码中不用输入令人讨厌的key,即可方便存储配置:
SettingUtils.getInstance().setIsLogin(true); //设置登录配置项SettingUtils.getInstance().getIsLogin(); //获取登录配置项,false为默认值

而关于FileDownloader,它是一个非常方便的下载工具类,使用方法 github传送门
FileDownloader提供了FileDownloadListener作为下载状态的监听,但是我们并非关心每一个状态,大多数时候我们只关心进度和完成时刻监听。
BaseProject 提供给你一个SimpleFileDownloadListener,默认需要复写completed方法,表示下载完成的回调。你也可以手动复写updateProgress(int percent)方法,percent就是下载的百分比进度。
FileDownloader.getImpl() //下载地址 .create("https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png") //保存路径 .setPath(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "baidu.png") .setListener(new SimpleFileDownloadListener() { @Override protected void completed(BaseDownloadTask task) { Bitmap bitmap = BitmapFactory.decodeFile(task.getTargetFilePath()); image.setImageBitmap(bitmap); } }) .start();

BaseActivity所有Activity类的基类,当你的Activity继承了它以后,将会拥有以下的技能:
1. 更方便的Toast
在需要弹出Toast的地方可直接调用showToast(String msg); 或者showLongToast(String msg); 来弹出Toast,并且已经做到防止反复弹出Toast
public void showToast(final String msg) { if (mToast == null) { mToast = Toast.makeText(mContext, msg, Toast.LENGTH_SHORT); } else { mToast.setText(msg); mToast.setDuration(Toast.LENGTH_SHORT); } mToast.show(); }

2. 一行代码弹出系统加载对话框(ProgressDialog)
在耗时操作时弹出对话框,你只需要这样做showLoading(); 默认提示语”正在努力加载中…”,你也可以传入你想弹出的提示语。
在结束对话框的地方调用dismissLoading(); 即可
3. 极致精简的Log输出
在你需要用到Log的地方,你只需要这么做:e(“This is an error log”);
同理v,i,d不同级别Log输出也是一样。省去烦人的TAG。
而TAG已经在BaseActivity中定义为当前调用的Activity名字
protected final String TAG = getClass().getSimpleName(); ..... protected void e(String logBody) {LogUtil.e(TAG, logBody); } protected void v(String logBody) {LogUtil.v(TAG, logBody); } protected void i(String logBody) {LogUtil.i(TAG, logBody); } protected void d(String logBody) {LogUtil.d(TAG, logBody); }

4. 简单的Activity跳转
对于基础的Activity跳转进行简单的封装,让跳转更加的简单。
需要返回结果的跳转,requestCode不为-1才能得到返回结果
//jumpToActivityActiviy跳转 jumpToActivity(FragmentActivity.class); //传参数跳转 Bundle bundle = new Bundle(); bundle.putString("name","123"); jumpToActivity(FragmentActivity.class,bundle); //需要返回结果的跳转(startActivityForResult),requestCode不为-1才能得到返回结果 jumpToActivity(FragmentActivity.class,1001); //需要返回结果的跳转,同时携带参数 jumpToActivity(FragmentActivity.class,bundle,1001);

5. 省心的Fragment切换
BaseActivity已经为你提供了Fragment管理的方法。让你在Fragment之间能够随意自如的切换,你只用参考下面的方式就可以get到此技能!
效果图:
BaseProject快速构建自己的APP

文章图片

先看看布局:
< ?xml version="1.0" encoding="utf-8"?> < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> < android.support.design.widget.TabLayout android:id="@+id/tab" android:layout_width="match_parent" android:layout_height="wrap_content"/> < FrameLayout android:layout_weight="1" android:id="@+id/fragmentLayout" android:layout_width="match_parent" android:layout_height="0dp"/> < /LinearLayout>

就是一个TabLayout 和一个FrameLayout,TabLayout是切换的标签,FrameLayout则是一个占位的布局,实际的Fragment会替换它。
下面就是Fragment切换的使用方式:
private List< Fragment> mFragments = new ArrayList< > (); //存储Fragment的列表 ... protected void initViews() { mTabLayout = findAviewById(R.id.tab); mTabLayout.setTabMode(TabLayout.MODE_FIXED); mTabLayout.addTab(mTabLayout.newTab().setText("one")); mTabLayout.addTab(mTabLayout.newTab().setText("two")); mTabLayout.addTab(mTabLayout.newTab().setText("three")); mTabLayout.addTab(mTabLayout.newTab().setText("four")); mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { switchPages(tab.getPosition()); }@Override public void onTabUnselected(TabLayout.Tab tab) {}@Override public void onTabReselected(TabLayout.Tab tab) {} }); }protected void initData() { mFragments.add(new OneFragment()); mFragments.add(new TwoFragment()); mFragments.add(new ThreeFragment()); mFragments.add(new FourFragment()); setFragmentContainer(R.id.fragmentLayout); //fragment所展示的布局id addFragments(mFragments); //添加Fragment列表 switchFragment(0); //默认显示第一个Fragment }

核心方法就是三个,setFragmentContainer,addFragments,switchFragment。
setFragmentContainer方法设置所占位的FrameLayout布局id。
addFragments添加Fragment列表,列表保存了所有的Fragment,当然你也可以调用addFragment(Fragment fragment)方法去单独的添加fragment
switchFragment方法则是在你需要的时候随心所欲去切换Fragment吧!
6.显示系统样式对话框
protected void showDialog(String title, String msg, DialogInterface.OnClickListener listener){ new BaseDialog(mContext).showDialog(title,msg,listener); }

此方法可以快速显示一个系统样式对话框,三个参数分别为标题,内容以及确定按钮的点击事件。
BaseFragmentBaseFragment当中的方法和BaseActivity差不多,不同的是去掉了Fragment管理相关的方法,其他的用法几乎相同,此处不再赘述!
RxJava2 & Retrofit2 异步与网络访问操作BaseProject 已经为你集成了RxJava2 与 Retrofit2,能够优雅的进行异步与网络访问操作。
关于RxJava的使用方式网上有很多资料,这里主要就介绍下BaseProject的网络请求方式。
关于Retrofit使用,包括官方资料都是一个API对应去定义一个接口,使用起来并不方便。BaseProject通过统一的请求方式,更加简单的进行网络请求的操作。
GET请求对于不需要参数的get请求,你可以这样做:
ApiService.build(this).get(url).subscribe(new BaseSubscriber() { @Override public void doOnNext(String result) { mTextView.setText("get请求结果:"+result); WeatherBean bean = Util.parseGson(result, WeatherBean.class); if (bean != null){ //do whatever you want } } });

**this 是继承BaseActivity 或者BaseFragment 的对象,url是请求地址,BaseSubscriber是BaseProject封装的网络请求的订阅者,你可以理解为网络请求结果的回调。
Util.parseGson是封装的一个json解析的工具类。通过它我们可以快速将json字符串解析成我们的javabean对象,然后就可以去愉快的使用bean啦!**
如果需要参数,也非常简单,构造一个Map对象传参即可
Map< String,String> map = new HashMap< > (); map.put("key","520520test"); map.put("city","南京"); map.put("province","江苏"); ApiService.build(this).get(url,map).subscribe(new BaseSubscriber() { @Override public void doOnNext(String result) { mTextView.setText("get请求结果:"+result); WeatherBean bean = Util.parseGson(result, WeatherBean.class); if (bean != null){ //do whatever you want } } });

Post请求以及postJson数据只用修改请求方法get 为post或者postJson 。
//post ApiService.build(this).post(url,map).subscribe(new BaseSubscriber() { @Override public void doOnNext(String result) { mTextView.setText("post请求结果:"+result); } }); //postJson ApiService.build(this).postJson(url,map).subscribe(new BaseSubscriber() { @Override public void doOnNext(String result) { mTextView.setText("postJson请求结果:"+result); } });

BaseSubscriber已经默认为你提供了网络加载的对话框,默认提示语为“正在努力加载中…”,如果你想自定义提示语可以通过构造方法传入
ApiService.build(this).post(url,map).subscribe(new BaseSubscriber("你的加载提示语") {...}

如果你不想要加载对话框,可以在构造方法直接传入false
ApiService.build(this).post(url,map).subscribe(new BaseSubscriber(false) {...}

What’s more?BasePagerAdapter,通用Viewpager的Adapter
public class ViewpagerActivity extends BaseActivity { private ViewPager mViewPager; private List< View> mViews; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_viewpager); initViews(); initData(); }@Override protected void initViews() { mViewPager = findAviewById(R.id.viewpager); mViews = new ArrayList< > (); }@Override protected void initData() { Flowable.just("view1","view2","view3","view4").subscribe(new Consumer< String> () { @Override public void accept(String s) throws Exception { TextView textView = new TextView(mContext); textView.setGravity(Gravity.CENTER); textView.setText(s); mViews.add(textView); } }); mViewPager.setAdapter(new BasePagerAdapter< > (mViews)); } }

你只需要将你需要滑动的view都添加到一个List中,再传入BasePageAdapter的构造方法即可。
DimImageView 图片点击变灰一般点击效果可以通过设置background的选择器,两张背景图点击和常规的即可实现。那么如果图片来自网络呢?接收两张图片然后设置点击样式?很明显这种多图方式既麻烦又占资源
BaseProject为你带来点击图片变灰的图片控件DimImageView,使用上只需要将ImageView替换成DimImageView即可。
实际上是通过给原图添加滤镜来实现的效果。
@Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { setFilter(); } else if (event.getAction() == MotionEvent.ACTION_UP) { removeFilter(); } return super.onTouchEvent(event); }/** * 设置滤镜 */ public void setFilter() { //先获取设置的src图片 Drawable drawable = getDrawable(); //当src图片为Null,获取背景图片 if (drawable == null) { drawable = getBackground(); } if (drawable != null) { //设置滤镜 drawable.setColorFilter(Color.parseColor("#FFD1D1D1"), PorterDuff.Mode.MULTIPLY); } }/** * 清除滤镜 */ public void removeFilter() { //先获取设置的src图片 Drawable drawable = getDrawable(); //当src图片为Null,获取背景图片 if (drawable == null) { drawable = getBackground(); } if (drawable != null) { //清除滤镜 drawable.clearColorFilter(); } }

效果图:
BaseProject快速构建自己的APP

文章图片

BannerLayout 简单实用的轮播图BannerLayout 是github上的开源控件,使用起来非常容易。
SwipeRecyclerView将SwipeLayout 和RecyclerView结合在一起,同时使用BaseRecyclerViewAdapterHelper作为RecyclerView的Adapter,即可快速拥有一个下拉刷新,上拉更多,多ITEM多布局,滑动删除等功能的列表。
BaseRecyclerViewAdapterHelper,是三方提供的非常好用的Adapter,其强大的程度令人叹为观止,使用上之后爱不释手所以我在这里安利一波,并且将它加入到了BaseProject中。
SwipeRecyclerView 默认为你加载了垂直的线性布局管理器,如果你只用普通的列表那么可以不用去写布局管理器。
以下是假设你已经了解BaseRecyclerViewAdapterHelper的使用方法。我们直接进入SwipeRecyclerView的使用。
【BaseProject快速构建自己的APP】效果图:
BaseProject快速构建自己的APP

文章图片

新建一个Adapter
public class SwipeRecyAdapter extends BaseQuickAdapter< String,BaseViewHolder> { public SwipeRecyAdapter(List< String> data) { super(R.layout.swipe_recy_item, data); }@Override protected void convert(BaseViewHolder baseViewHolder, String s) { baseViewHolder.setText(R.id.text,s); } }

Adapter 非常简单,Item的布局也只有一个TextView用于显示传进来的字符串。
新建一个Activity
public class SwipeRecyActivity extends BaseActivity implements BaseQuickAdapter.RequestLoadMoreListener,SwipeRefreshLayout.OnRefreshListener{ private SwipeRecyclerView mSwipeRecyclerView; private SwipeRecyAdapter mSwipeRecyAdapter; private final int PAGE_SIZE = 10; private int PAGE = 1; private List< String> datas = new ArrayList< > (); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_swipe_recy); initViews(); initData(); }@Override protected void initViews() { mSwipeRecyclerView = findAviewById(R.id.swipeRecyclerView); //设置下拉刷新监听 mSwipeRecyclerView.setOnRefreshListener(this); //第一次进入需要加载数据,设置刷新为true mSwipeRecyclerView.setRefreshing(true); }@Override protected void initData() { //模拟网络耗时操作,2秒后执行接下来操作 Flowable.timer(2, TimeUnit.SECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer< Long> () { @Override public void accept(Long aLong) throws Exception { //获取数据 datas = DataServer.getData(PAGE,PAGE_SIZE); mSwipeRecyAdapter = new SwipeRecyAdapter(datas); //设置加载更多的监听 mSwipeRecyAdapter.setOnLoadMoreListener(SwipeRecyActivity.this); //设置刷新为false 此刻已经刷新完成 mSwipeRecyclerView.setRefreshing(false); //设置adapter mSwipeRecyclerView.setBaseQuickAdapter(mSwipeRecyAdapter); } }); }//下拉刷新回调 @Override public void onRefresh() { PAGE = 1; Flowable.timer(2, TimeUnit.SECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer< Long> () { @Override public void accept(Long aLong) throws Exception { datas = DataServer.getData(PAGE,PAGE_SIZE); mSwipeRecyAdapter.setNewData(datas); mSwipeRecyclerView.setRefreshing(false); } }); }//加载更多回调 @Override public void onLoadMoreRequested() { Flowable.timer(2, TimeUnit.SECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer< Long> () { @Override public void accept(Long aLong) throws Exception { PAGE++; datas = DataServer.getData(PAGE,PAGE_SIZE); mSwipeRecyAdapter.addData(datas); mSwipeRecyAdapter.loadMoreComplete(); } }); } }

以上是SwipeRecyclerView的简单用法。更多复杂用法,主要在adapter上面,你可以去BaseRecyclerViewAdapterHelper Get到更多高级玩法,相信它足以满足大家大部分的需求!
捐助开发者你的支持是我完善BaseProject的最大动力!觉得不错点个赞吧,看到这里就去start一下呗!BaseProject传送门
BaseProject快速构建自己的APP

文章图片

BaseProject快速构建自己的APP

文章图片

关于我本人王灿,Android开发芸芸众生当中的一个新手,正在学习的路上不断爬坑!
不论文章还是代码,当然肯定有很多不够好的地方,希望各位大神不吝赐教,我一定虚心学习,可以评论或者在github上提issue,欢迎关注转发!转发请带上原文链接!谢谢
QQ:306217025
github:https://github.com/flyzend
简书:http://www.jianshu.com/users/0d03dcfbfc36/timeline































    推荐阅读