[置顶] RxJava+Retrofit+okhttp+mvp+butterknife实现的简易开源项目
2017-02-12 22:19
477 查看
首先介绍下该项目用到的技术点和亮点(大神请绕道,小弟菜鸡)
1. Rxjava+Retrofit+okhttp搭建的网络框架
2. mvp设计模式
因为这个项目没涉及数据库方面数据 所以modle我直接放到presenter层实现逻辑处理了,本项目设计三个列表,因为实现方式都差不多,所以我就只介绍其中一个
具体代码如下
bean对象:
Presenter接口和实现类代码
View接口代码
3.Activity和 Fragment中实现
MainActivity实现,通过toolbar实现标题栏 实现三fragment切换
注解方式查找控件
妹子对应的Fragment实现,注解初始化我在BaseFragment中实现了,在Fragment中注意在onDestroyView方法中调用ButterKnife.reset(this);
4. ListView和GridView,RecycleView的通用数据适配器工具类封装
ListView通用适配器在我的“你还在用第三方开源下拉刷新控件吗?试试google自带的下拉刷新控件SwipeRefreshLayout”这篇博客中有讲解
RecycleView通用适配器实现
5. Glide实现的图片加载框架
6. 总结
我是读了网上的一个开源项目然后自己封装仿写的这个项目 不过我感觉比它写的好 至少代码可读性要强 哈哈(你个自恋狂)
7. 源代码下载
点击进入GitHub下载
如果觉得好,请随手star,如果不好,欢迎批评指点。Thanks you very much!
或者 下载需要2积分 sorry
8.效果展示
本来是想录制gif图片的,因为一些原因只能截图了
9. 联系方式
qq:1509815887
email:zlc921022@163.com
1. Rxjava+Retrofit+okhttp搭建的网络框架 2. mvp设计模式 3. butterknife注解方式查找控件,减少findViewById冗余代码 4. Glide图片加载框架 5. Recyclerview结合SwipeRefreshLayout实现列表和下拉刷新 6. 封装了ListView和GridView,RecycleView的通用数据适配器工具类
1. Rxjava+Retrofit+okhttp搭建的网络框架
代码我写的浅显易懂,就不一一解释了 主要是CacheHelper,OkHttpClientHelper,RetrofitHelper和HttpUtils这四个类,代码我们主要看RetrofitHelper和HttpUtils这两个 public class RetrofitHelper { private final OkHttpClient mClient; private Retrofit mRetrofit; private RetrofitHelper(){ mClient = OkHttpClientHelper.getInstance().getOkHttpClient(); } private static RetrofitHelper helper; //单例 保证对象唯一 public static RetrofitHelper getInstance(){ if(helper==null){ synchronized (RetrofitHelper.class){ if(helper==null){ helper = new RetrofitHelper(); } } } return helper; } //获取Retrofit对象 public Retrofit getRetrofit(String url){ if(mRetrofit==null) { mRetrofit = new Retrofit.Builder() .baseUrl(url + "/") .addConverterFactory(GsonConverterFactory.create()) //添加Gson支持 .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) //添加RxJava支持 .client(mClient) //关联okhttp .build(); } return mRetrofit; } /** *获取服务对象 Rxjava+Retrofit建立在接口对象的基础上的 *泛型避免强制转换 */ public static<T> T getService(String url,Class<T> classz){ return RetrofitHelper.getInstance() .getRetrofit(url) .create(classz); } } 网络请求工具类 public class HttpUtils { //Post方式请求网络 public static<T> void requestNetByPost(Observable observable, final OnResultListener resultListener){ setSubscriber(observable, new Subscriber<T>() { @Override public void onCompleted() { Log.e("onCompleted","读取完成"); } @Override public void onError(Throwable error) { if(error!=null && resultListener!=null){ resultListener.onError(error,error.getMessage()); }else if(resultListener!=null){ resultListener.onError(new Exception("网络不给力"),""); Toast.makeText(MyApplication.getContext(),"网络不给力",Toast.LENGTH_LONG).show(); return; } String e = error.getMessage(); int code =0; if(!TextUtils.isEmpty(e)){ try { e = e.substring(e.length()-3,e.length()); code = Integer.valueOf(e); }catch (Exception e1){ Toast.makeText(MyApplication.getContext(),"网络不给力",Toast.LENGTH_LONG).show(); } } Log.e("code==:",code+""); if(code>=300&&code<500){ Toast.makeText(MyApplication.getContext(),"您的请求迷路了,请稍后再试",Toast.LENGTH_LONG).show(); }else if(code>=500){ Toast.makeText(MyApplication.getContext(),"服务器异常,请稍后再试",Toast.LENGTH_LONG).show(); }else{ Toast.makeText(MyApplication.getContext(),"网络不给力",Toast.LENGTH_LONG).show(); } } @Override public void onNext(T t) { if(resultListener!=null){ resultListener.onSuccess(t); } } }); } //Get方式请求网络 public static void requestNetByGet(Observable observable,final OnResultListener resultListener){ requestNetByPost(observable,resultListener); } //订阅事件 public static<T> void setSubscriber(Observable<T> observable, Subscriber<T> subscriber){ observable.subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(subscriber); } //网络请求接口回调 public interface OnResultListener<T>{ void onSuccess(T t); void onError(Throwable error, String msg); } }
2. mvp设计模式
因为这个项目没涉及数据库方面数据 所以modle我直接放到presenter层实现逻辑处理了,本项目设计三个列表,因为实现方式都差不多,所以我就只介绍其中一个
具体代码如下
bean对象:
public class MeiziInfo { public List<MeiziBean> results; public static class MeiziBean{ public String objectId; public String url; public String type; public String desc; public String who; public boolean used; public boolean hasFadedIn=false; public int imageWidth; public int imageHeight; } }
Presenter接口和实现类代码
妹子接口 public interface IMeiziPrestener{ void getMeiziInfo(String url,int page); } 妹子接口实现类 public class MeiziPresenterImpl implements IMeiziPrestener{ private IMeiziModel meiziModel; //没什么用 只是为了好看 哈哈 private IMeiziFragment iMeiziFragment; //View接口 后面实现 public MeiziPresenterImpl(IMeiziFragment iMeiziFragment){ meiziModel = new MeiziModelImpl(); this.iMeiziFragment = iMeiziFragment; } //通过调用网络工具类 获取数据 View接口调用方法 在相应activity或者fragment中实现 @Override public void getMeiziInfo(String url,int page) { Observable<MeiziInfo> observable = RetrofitHelper.getService(url, IMeiziService.class).getMeizhiData(page); HttpUtils.requestNetByGet(observable, new HttpUtils.OnResultListener<MeiziInfo>() { @Override public void onSuccess(MeiziInfo meiziInfo) { if(meiziInfo!=null) iMeiziFragment.getMeiziDataList(meiziInfo.results); } @Override public void onError(Throwable error, String msg) { Log.e("妹子info error",msg); } }); } }
View接口代码
public interface IMeiziFragment { void getMeiziDataList(List<MeiziInfo.MeiziBean> meiziInfos); }
3.Activity和 Fragment中实现
MainActivity实现,通过toolbar实现标题栏 实现三fragment切换
注解方式查找控件
public class MainActivity extends BaseActivity { @InjectView(R.id.toolbar) Toolbar toolbar; @InjectView(R.id.nav_view) NavigationView navView; @InjectView(R.id.drawer) DrawerLayout drawer; Fragment currentFragment; SimpleArrayMap<Integer, String> mTitleArryMap = new SimpleArrayMap<>(); private ZhihuFragment zhihuFragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.inject(this); //注解初始化这个是必须的 initData(); setSupportActionBar(toolbar); toolbar.setOnMenuItemClickListener(onMenuItemClick); switchFragment(zhihuFragment = new ZhihuFragment()); currentFragment = zhihuFragment; navView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(MenuItem item) { switchFragment(getFragmentById(item.getItemId())); Log.e("条目内容===",item.toString()); drawer.closeDrawer(GravityCompat.END); return true; } }); } private void initData() { } private Fragment getFragmentById(int id) { Fragment fragment = null; switch (id) { case R.id.zhihuitem: fragment = new ZhihuFragment(); break; case R.id.topnewsitem: fragment=new NewsFragment(); break; case R.id.meiziitem: fragment=new MeiziFragment(); break; } return fragment; } private void switchFragment(Fragment fragment) { if (currentFragment == null || !currentFragment.getClass().getName().equals(fragment.getClass().getName())) getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment) .commit(); currentFragment = fragment; } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } private Toolbar.OnMenuItemClickListener onMenuItemClick = new Toolbar.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem menuItem) { switch (menuItem.getItemId()) { case R.id.menu_open: drawer.openDrawer(GravityCompat.END); break; } return true; }}; }
妹子对应的Fragment实现,注解初始化我在BaseFragment中实现了,在Fragment中注意在onDestroyView方法中调用ButterKnife.reset(this);
public class MeiziFragment extends BaseFragment implements IMeiziFragment,SwipeRefreshLayout.OnRefreshListener { @InjectView(R.id.id_meizi_recycle) RecyclerView mMeiziRecycle; @InjectView(R.id.id_meizi_swipe) SwipeRefreshLayout mMeiziSwipe; private MeiziPresenterImpl meiziPrestener; private MeiziAdapter mMeiziAdapter; //妹子地址 private String url = "http://gank.io"; private int page = 1; private LinearLayoutManager linearLayoutManager; private RecyclerView.OnScrollListener mloadmoreListener; private boolean loading; private List<MeiziInfo.MeiziBean> meiziInfos; @Override public View initView() { mView = View.inflate(mActivity, R.layout.fragment_meizi, null); return mView; } @Override public void initData() { SwipeRefreshUtil.setSiwpeLayout(mMeiziSwipe,mActivity,this); meiziInfos = new ArrayList<>(); meiziPrestener = new MeiziPresenterImpl(this); meiziPrestener.getMeiziInfo("",page); setRecycleView(); } private void setRecycleView() { mMeiziRecycle.addItemDecoration(new GridItemDividerDecoration(getContext(), R.dimen.divider_height, R.color.divider_color)); mMeiziRecycle.setItemAnimator(new DefaultItemAnimator()); mMeiziRecycle.setLayoutManager(linearLayoutManager =new LinearLayoutManager(mActivity, LinearLayoutManager.VERTICAL, false)); } @Override protected void initListener() { super.initListener(); mloadmoreListener = new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if (dy > 0 && linearLayoutManager!=null) //向下滚动 { int visibleItemCount = linearLayoutManager.getChildCount(); int totalItemCount = linearLayoutManager.getItemCount(); int pastVisiblesItems = linearLayoutManager.findFirstVisibleItemPosition(); if (!loading && (visibleItemCount + pastVisiblesItems) >= totalItemCount) { loading = true; page+=1; loadMoreData(); } } } }; } private void loadMoreData() { Log.e("当前页数==",page+""); meiziPrestener.getMeiziInfo("",page); } @Override public void getMeiziDataList(List<MeiziInfo.MeiziBean> meiziInfos) { mMeiziSwipe.setRefreshing(false); if(meiziInfos==null || meiziInfos.size()<=0) return; loading = false; this.meiziInfos.addAll(meiziInfos); Log.e("妹子数据集合==",meiziInfos.size()+""); if(mMeiziAdapter==null) { mMeiziRecycle.setAdapter(mMeiziAdapter = new MeiziAdapter(mActivity, this.meiziInfos)); }else{ mMeiziAdapter.notifyDataSetChanged(); } mMeiziRecycle.addOnScrollListener(mloadmoreListener); } @Override public void onRefresh() { new Handler().postDelayed(new Runnable() { @Override public void run() { meiziInfos.clear(); page = 1; loading = false; meiziPrestener.getMeiziInfo("",page); } },1000); } }
4. ListView和GridView,RecycleView的通用数据适配器工具类封装
ListView通用适配器在我的“你还在用第三方开源下拉刷新控件吗?试试google自带的下拉刷新控件SwipeRefreshLayout”这篇博客中有讲解
RecycleView通用适配器实现
public abstract class CommonRecyclerViewAdapter<T> extends RecyclerView.Adapter<CommonRecyclerViewHolder>{ protected Context mContext; protected List<T> mDatas; protected View mView; private CommonRecyclerViewHolder viewHolder; public CommonRecyclerViewAdapter(Context context, List<T> datas){ this.mContext = context; this.mDatas = datas; } @Override public CommonRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { mView = initView(); viewHolder = new CommonRecyclerViewHolder(mContext,mView); return viewHolder; } @Override public int getItemCount() { return mDatas!=null && mDatas.size()>0 ? mDatas.size() : 0; } @Override public void onBindViewHolder(CommonRecyclerViewHolder holder, int position){ setData(holder,position); } public CommonRecyclerViewHolder getViewHolder() { return viewHolder; } public abstract View initView(); //加载布局 public abstract void setData(CommonRecyclerViewHolder holder, int position); //设置数据 处理逻辑 } CommonRecyclerViewHolder 类实现 public class CommonRecyclerViewHolder extends RecyclerView.ViewHolder{ private final SparseArray<View> mViews; //相当于Map集合 不过效率更高,key只能为Integer private View mConvertView; private int mPosition; private Context mContext; public CommonRecyclerViewHolder(Context context,View itemView) { super(itemView); this.mConvertView = itemView; this.mContext = context; this.mViews = new SparseArray<>(); } /** * 通过控件的Id获取对应的控件,如果没有则加入views * @param viewId * @return */ public <T extends View> T getView(int viewId){ View view = mViews.get(viewId); if(view==null && mConvertView!=null){ view = mConvertView.findViewById(viewId); mViews.put(viewId,view); } return (T) view; } /** * 为TextView设置字符串 * * @param viewId * @param text * @return */ public CommonRecyclerViewHolder setText(int viewId, String text) { TextView view = getView(viewId); view.setText(text); return this; } /** * 为ImageView设置图片 */ public CommonRecyclerViewHolder setImageResource(int viewId,int resId){ ImageView imageView = getView(viewId); imageView.setImageResource(resId); return this; } /** * 为ImageView设置图片 */ public CommonRecyclerViewHolder setImageBitmap(int viewId,Bitmap bitmap){ ImageView imageView = getView(viewId); imageView.setImageBitmap(bitmap); return this; } public void showImage(int viewId,String imageUrl){ ImageView view = getView(viewId); ImageUtil.show(view,imageUrl); } }
5. Glide实现的图片加载框架
public class ImageUtil { /**===========================加载图片方式,可换其他框架加载===========================================================================*/ /** * 以正常模式加载网络图片 */ public static void show(ImageView mImageView, String imageUrl) { Glide.with(MyApplication.getContext()).load(imageUrl) .crossFade(0) .into(mImageView); //crossFade是个淡入淡出效果 } /** * 以拉伸模式加载网络图片 */ public static void show1(ImageView mImageView, String imageUrl) { Glide.with(MyApplication.getContext()).load(imageUrl) .fitCenter() .diskCacheStrategy(DiskCacheStrategy.ALL) .transform(new GlideRoundTransform(MyApplication.getContext(),8)) .crossFade(0) .into(mImageView); //crossFade是个淡入淡出效果 } //加载正方形图片 public static void showSquare(ImageView mImageView, String imageUrl) { Glide.with(MyApplication.getContext()).load(imageUrl) .diskCacheStrategy(DiskCacheStrategy.ALL) .centerCrop() .into(mImageView); } //加载正方形图片(商品) public static void showSquare2(ImageView mImageView, String imageUrl) { Glide.with(MyApplication.getContext()).load(imageUrl) .diskCacheStrategy(DiskCacheStrategy.ALL) .into(mImageView); } /** * 加载圆头像 */ public static void showCircle(final ImageView mImageView, String imageUrl) { Glide.with(MyApplication.getContext()).load(imageUrl) .diskCacheStrategy(DiskCacheStrategy.ALL) .fitCenter() .bitmapTransform(new CropCircleTransformation(MyApplication.getContext())) .crossFade(0) .into(mImageView); } public static void showRoundedImage(ImageView imageView, String imageUrl) { Glide.with(MyApplication.getContext()) //可以传getApplicationContext Activity Fragment .load(imageUrl) //图片地址 .diskCacheStrategy(DiskCacheStrategy.ALL) .transform(new GlideRoundTransform(MyApplication.getContext(),4)) .centerCrop() .into(imageView); } public static void showGoodsImage(ImageView imageView, String imageUrl){ Glide.with(MyApplication.getContext()) //可以传getApplicationContext Activity Fragment .load(imageUrl) //图片地址 .diskCacheStrategy(DiskCacheStrategy.ALL) .transform(new GlideRoundTransform(MyApplication.getContext(),4)) .into(imageView); } public static void showRoundedImage2(ImageView imageView, String imageUrl,int radius) { Glide.with(MyApplication.getContext()) //可以传getApplicationContext Activity Fragment .load(imageUrl) //图片地址 .diskCacheStrategy(DiskCacheStrategy.ALL) .transform(new GlideRoundTransform(MyApplication.getContext(),radius)) .into(imageView); } /** * 加载高斯模糊 */ public static void show2(ImageView mImageView, String imageUrl) { Glide.with(MyApplication.getContext()) .load(imageUrl) .bitmapTransform(new BlurTransformation(MyApplication.getContext(), 25)).crossFade(0) .into(mImageView); } //=========================Glide加载GIF图片配置==============================================================// //加载本地GIF public static void showGIF(ImageView imageView,int img){ Glide.with(MyApplication.getContext()).load(img).asGif() .diskCacheStrategy(DiskCacheStrategy.SOURCE) .into(imageView); } //加载网络GIF public static void showGIF(ImageView imageView,String img){ Glide.with(MyApplication.getContext()).load(img).asGif().diskCacheStrategy(DiskCacheStrategy.SOURCE).into(imageView); } }
6. 总结
我是读了网上的一个开源项目然后自己封装仿写的这个项目 不过我感觉比它写的好 至少代码可读性要强 哈哈(你个自恋狂)
7. 源代码下载
点击进入GitHub下载
如果觉得好,请随手star,如果不好,欢迎批评指点。Thanks you very much!
或者 下载需要2积分 sorry
8.效果展示
本来是想录制gif图片的,因为一些原因只能截图了
9. 联系方式
qq:1509815887
email:zlc921022@163.com
相关文章推荐
- Airbnb的开源项目Lottie简易实现动画
- [置顶] Android移动开发-在Android项目里集成开源框架ZXing实现扫描二维码的功能
- VC++ & MFC实现的优秀的开源项目
- 几个开源项目实体层实现方式比较
- 集成开源系统实现自动化构建、代码质量评估、项目信息统计(1)——Jenkins安装
- 【开源项目】花密(Flower Password)VB版之窗体置顶模块
- 基于开源项目acra实现的定制化Android crash上报库及后台系统
- 几个开源项目实体层实现方式比较
- 关于Java RDP协议实现远程桌面连接的开源项目properjavardp
- 集成开源系统实现自动化构建、代码质量评估、项目信息统计
- 开源项目Html Agility Pack实现快速解析Html
- 移植开源项目obexftp到android平台下实现蓝牙ftp的功能
- 基于.NET 2.0的GIS开源项目SharpMap分析手记(十四):ASP.NET2.0实现无刷新客户端回调的Callback机制及例子代码下载
- 高分求救,微软屏传开源的项目,里面也有屏传的代码,是用C#实现的。
- VC++ & MFC实现的优秀的开源项目
- 集成开源系统实现自动化构建、代码质量评估、项目信息统计
- VC++ &amp;amp; MFC实现的优秀的开源项目
- 利用AJAX开源项目 在网页里播放视频实现方法
- 应用开源项目StringResourceTool2 实现.NET多国语言方案
- IM 开源项目 群组服务 缓存设计实现之 群组属性