运用MVP模式写(okhttp)解析json,数据传输到RecyclerView中;
一、三个层Model,view,Presenter
二、导入okhttp,okio,RecyclerView依赖;
加入网络权限<uses-permission android:name="android.permission.INTERNET"/>
三、封装Adapter实现效果;
model:接口 IShowRecyclerViewModel
public interface IShowRecyclerViewModel {
void showData(int type,Callback callback);
}
model:类 ShowRecyclerViewModel
public class ShowRecyclerViewModel implements IShowRecyclerViewModel {
@Override
public void showData(int type,Callback callback) {
OkHttpUtils.getInstance().doGet("http://www.yulin520.com/a2a/impressApi/news/mergeList?sign=C7548DE604BCB8A17592EFB9006F9265&pageSize=20&gender=2&ts=1871746850&page="+type+"",callback);
}
}
View :接口 IShowRecyclerViewView
public interface ShowRecyclerViewView {
void showRecyclerView(List<Max.DataBean> list);
int getID();
}
Presenter: 类 ShowRecyclerViewPresenter
Max.class是bean包下的json类
public class ShowRecyclerViewpresenter {
IShowRecyclerViewModel model;
ShowRecyclerViewView view;
List<Max.DataBean> list;
Context context;
public ShowRecyclerViewpresenter(Context context, ShowRecyclerViewView view){
this.context=context;
this.view=view;
model=new ShowRecyclerViewModel();
}
public void showRecyclerView(){
int type=view.getID();
model.showData(type, new OnUiCallback() {
@Override
public void onFailed(Call call, IOException e) {
}
@Override
public void onSuccess(String result) throws IOException {
Gson gson=new Gson();
Max max = gson.fromJson(result, Max.class);
list=max.getData();
Toast.makeText(context,list.toString(),Toast.LENGTH_SHORT).show();
view.showRecyclerView(list);
}
});
}
}
Okhttp的封装类:
OkHttpUtils类(get请求):
public class OkHttpUtils {
private Handler handler=new Handler();
public Handler getHandler(){
return handler;
}
private static OkHttpUtils okHttpUtils=new OkHttpUtils();
private OkHttpUtils(){};
public static OkHttpUtils getInstance(){
return okHttpUtils;
}
private OkHttpClient client;
private void initOkHttpClient(){
if(client==null){
client=new OkHttpClient().newBuilder().build();
}
}
public void doGet(String url, Callback callback){
initOkHttpClient();
Request request=new Request.Builder().url(url).build();
Call call=client.newCall(request);
call.enqueue(callback);
}
}
Okhttp的封装类:
OnUiCallback类(get请求):
public abstract class OnUiCallback implements Callback {
private Handler handler=OkHttpUtils.getInstance().getHandler();
public abstract void onFailed(Call call,IOException e);
public abstract void onSuccess(String result)throws IOException;
@Override
public void onFailure(final Call call, final IOException e) {
handler.post(new Runnable() {
@Override
public void run() {
onFailure(call,e);
}
});
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
final String result=response.body().string();
handler.post(new Runnable() {
@Override
public void run() {
try {
onSuccess(result);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
MainActivity:
public class MainActivity extends AppCompatActivity implements ShowRecyclerViewView{
private RecyclerView mRv;
int type=1;
ShowRecyclerViewpresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
presenter=new ShowRecyclerViewpresenter(this,this);
presenter.showRecyclerView();
}
private void initView() {
mRv = (RecyclerView) findViewById(R.id.rv);
LinearLayoutManager layoutManager=new LinearLayoutManager(this);
mRv.setLayoutManager(layoutManager);
mRv.addItemDecoration(new DividerItemDecoration(MainActivity.this,DividerItemDecoration.VERTICAL));
}
@Override
public void showRecyclerView(List<Max.DataBean> list) {
MyAdapter myadapter=new MyAdapter(MainActivity.this,list);
mRv.setAdapter(myadapter);
}
@Override
public int getID() {
return type;
}
}
Adapter:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>{
Context context;
List<Max.DataBean> list;
public MyAdapter ( Context context, List<Max.DataBean> list){
this.context=context;
this.list=list;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view=View.inflate(context,R.layout.items,null);
MyViewHolder holder=new MyViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
ImageLoader.getInstance().displayImage(list.get(position).getImg(),holder.ivhead);
holder.tvage.setText(list.get(position).getUserAge()+"岁");
holder.tvh.setText(list.get(position).getOccupation());
holder.tvmessage.setText(list.get(position).getIntroduction());
}
@Override
public int getItemCount() {
return list==null?0:list.size();
}
class MyViewHolder extends RecyclerView.ViewHolder{
TextView tvmessage;
TextView tvage;
TextView tvh;
ImageView ivhead;
public MyViewHolder(View itemView) {
super(itemView);
tvage=itemView.findViewById(R.id.tvage);
tvh=itemView.findViewById(R.id.tvh);
tvmessage=itemView.findViewById(R.id.tvmessage);
ivhead=itemView.findViewById(R.id.ivhead);
}
}
}
最后我们用ImageLoader来加载网络获取的数据:
定义MyApp类:
在清单文件中别忘了加上
android:name=".MyApp"
public class MyApp extends Application {
ImageLoader imageLoader;
@Override
public void onCreate() {
super.onCreate();
File file = this.getCacheDir();
DisplayImageOptions options = new DisplayImageOptions.Builder()
.showImageOnLoading(R.mipmap.ic_launcher) // 加载未完成时显示的自定义图片
.showImageForEmptyUri(R.mipmap.ic_launcher) // 链接为空时的占位图
.showImageOnFail(R.mipmap.ic_launcher_round) // 加载失败时显示自定义图片
.resetViewBeforeLoading(false) // 在加载前是否重置 view ,默认为false
.delayBeforeLoading(1000) //设置在开始加载前的延迟时间,单位为毫秒
.cacheInMemory(true) // 是否启用内存缓存,默认为false
.cacheOnDisk(true) // 是否启用磁盘缓存,默认为false
.imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // 图片的缩放类型
.bitmapConfig(Bitmap.Config.ARGB_8888) // 图片的色彩格式
.handler(new Handler()) // handler 对象,消息处理
.build();
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
this)
// max width, max height,即保存的每个缓存文件的最大长宽
.memoryCacheExtraOptions(480, 800)
// 线程池内加载的数量
.threadPoolSize(3)
// 线程优先级
.threadPriority(Thread.NORM_PRIORITY - 2)
.defaultDisplayImageOptions(options)
// You can pass your own memory cache implementation你可以通过自己的内存缓存实现
// .memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024))
// .memoryCacheSize(2 * 1024 * 1024)
//硬盘缓存50MB
.diskCacheSize(50 * 1024 * 1024)
//将保存的时候的URI名称用MD5
.diskCacheFileNameGenerator(new Md5FileNameGenerator())
// 加密
.diskCacheFileNameGenerator(new HashCodeFileNameGenerator())//将保存的时候的URI名称用HASHCODE加密
.tasksProcessingOrder(QueueProcessingType.LIFO)
.diskCacheFileCount(100) //缓存的File数量
.diskCache(new UnlimitedDiscCache(file))// 自定义缓存路径
// .defaultDisplayImageOptions(DisplayImageOptions.createSimple())
// .imageDownloader(new BaseImageDownloader(context, 5 * 1000,
// 30 * 1000)) // connectTimeout (5 s), readTimeout (30 s)超时时间
.writeDebugLogs() // Remove for release app
.build();
ImageLoader.getInstance().init(config);
}
}
下面分享一个RecyclerView多条目加载的AdapterDemo(MVC):
加载一个头布局
private void initrvData() {
myadapter=new MyRVAdapter();
mXrv.setAdapter(myadapter);
TextView title = new TextView(MainActivity.this);
myadapter.addHeader(title);
}
class MyRVAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
public static final int TYPE_HEADER = 0;
public static final int TYPE_BO = 1;
List<View> list = new ArrayList<>();
public void addHeader(View view) {
list.add(view);
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_HEADER) {
View view = View.inflate(MainActivity.this, R.layout.xrvhead, null);
MyHeaderHolder headerHolder = new MyHeaderHolder(view);
return headerHolder;
} else {
View view = View.inflate(MainActivity.this, R.layout.xrvitem, null);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof MyHeaderHolder) {
((MyHeaderHolder) holder).h_title.setText(m.getBillboard().getName());
((MyHeaderHolder) holder).h_name.setText(m.getBillboard().getUpdate_date());
((MyHeaderHolder) holder).h_info.setText(m.getBillboard().getComment());
ImageLoader.getInstance().displayImage(m.getBillboard().getPic_s210(), ((MyHeaderHolder) holder).h_iv);
}
if (holder instanceof MyViewHolder) {
((MyViewHolder) holder).title.setText(listrv.get(position).getTitle());
((MyViewHolder) holder).author.setText(listrv.get(position).getAuthor());
((MyViewHolder) holder).name.setText(listrv.get(position).getAlbum_title());
ImageLoader.getInstance().displayImage(listrv.get(position).getPic_big(), ((MyViewHolder) holder).iv);
}
}
@Override
public int getItemCount() {
return listrv == null ? 0 : listrv.size();
}
@Override
public int getItemViewType(int position) {
if (position < list.size()) {
return TYPE_HEADER;
} else {
return TYPE_BO;
}
}
class MyHeaderHolder extends RecyclerView.ViewHolder {
TextView h_title, h_name, h_info, h_author;
ImageView h_iv;
RelativeLayout rl;
public MyHeaderHolder(View itemView) {
super(itemView);
h_iv = itemView.findViewById(R.id.header_iv);
h_title = itemView.findViewById(R.id.header_title);
h_author = itemView.findViewById(R.id.header_author);
h_name = itemView.findViewById(R.id.header_name);
h_info = itemView.findViewById(R.id.header_info);
rl = itemView.findViewById(R.id.rl);
}
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView title, name, author;
ImageView iv;
public MyViewHolder(View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
name = itemView.findViewById(R.id.name);
iv = itemView.findViewById(R.id.iv);
author = itemView.findViewById(R.id.author);
}
}
}
定义全局异常捕获处理器;
演示空指针异常时使用全局异常捕获处理器提示错误信息;
将错误日志成功保存到sd卡;
封装class CrashHandler.class 和CrashApplication.class
package com.example.login_recyclerview20171023;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Environment;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class CrashHandler implements Thread.UncaughtExceptionHandler {
public static final String TAG="CrashHandler";
//系统默认的UncaughtException处理类
private Thread.UncaughtExceptionHandler mDefaultHandler;
//系统默认的UncaughtException处理类
private static CrashHandler INSTANCE=new CrashHandler();
//程序的Context对象
private Context mContext;
//用来存储设备信息和异常信息
private Map<String, String> infos = new HashMap<String, String>();
//用于格式化日期,作为日志文件名的一部分
private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
/** 保证只有一个CrashHandler实例 */
private CrashHandler() {
}
/** 获取CrashHandler实例 ,单例模式 */
public static CrashHandler getInstance() {
return INSTANCE;
}
/**
* 初始化
*
* @param context
*/
public void init(Context context) {
mContext = context;
//获取系统默认的UncaughtException处理器
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
//设置该CrashHandler为程序的默认处理器
Thread.setDefaultUncaughtExceptionHandler(this);
}
/**
* 当UncaughtException发生时会转入该函数来处理
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
//如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, ex);
} else {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
Log.e(TAG, "error : ", e);
}
//退出程序
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);
}
}
/**
* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
*
* @param ex
* @return true:如果处理了该异常信息;否则返回false.
*/
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
//使用Toast来显示异常信息
new Thread() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出.", Toast.LENGTH_LONG).show();
Looper.loop();
}
}.start();
//收集设备参数信息
collectDeviceInfo(mContext);
//保存日志文件
saveCrashInfo2File(ex);
return true;
}
private void collectDeviceInfo(Context ctx) {
try {
PackageManager pm = ctx.getPackageManager();
PackageInfo pi = null;
pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
if (pi != null) {
String versionName = pi.versionName == null ? "null" : pi.versionName;
String versionCode = pi.versionCode + "";
infos.put("versionName", versionName);
infos.put("versionCode", versionCode);
}
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "an error occured when collect package info", e);
}
Field[] fields = Build.class.getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true);
infos.put(field.getName(), field.get(null).toString());
Log.d(TAG, field.getName() + " : " + field.get(null));
} catch (Exception e) {
Log.e(TAG, "an error occured when collect crash info", e);
}
}
}
/**
* 保存错误信息到文件中
*
* @param ex
* @return 返回文件名称,便于将文件传送到服务器
*/
private String saveCrashInfo2File(Throwable ex) {
StringBuffer sb = new StringBuffer();
for (Map.Entry<String, String> entry : infos.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
sb.append(key + "=" + value + "\n");
}
Writer writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
ex.printStackTrace(printWriter);
Throwable cause = ex.getCause();
while (cause != null) {
cause.printStackTrace(printWriter);
cause = cause.getCause();
}
printWriter.close();
String result = writer.toString();
sb.append(result);
try {
long timestamp = System.currentTimeMillis();
String time = formatter.format(new Date());
String fileName = "crash-" + time + "-" + timestamp + ".log";
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
String path = "/sdcard/crash/";
File dir = new File(path);
if (!dir.exists()) {
dir.mkdirs();
}
FileOutputStream fos = new FileOutputStream(path + fileName);
fos.write(sb.toString().getBytes());
fos.close();
}
return fileName;
} catch (Exception e) {
Log.e(TAG, "an error occured while writing file...", e);
}
return null;
}
/**
* 网络是否可用
*
* @param context
* @return
*/
public static boolean isNetworkAvailable(Context context) {
ConnectivityManager mgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo[] info = mgr.getAllNetworkInfo();
if (info != null) {
for (int i = 0; i < info.length; i++) {
if (info[i].getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
}
return false;
}
}
public class CrashApplication extends Application {
private static Context mContext;
@Override
public void onCreate() {
super.onCreate();
this.mContext = this;
CrashHandler.getInstance().init(this);
}
}
清单文件里配置name******
下面补充一个Xrecyclerview的 实例:
添加依赖:compile 'com.jcodecraeer:xrecyclerview:1.3.2'
与recyclerview类似 不同的是可以实现下拉加载和上拉刷新功能:
MVP的model层:
接口 IShowXrecyclerViewp1 :
public interface IShowXrecyclerViewp1 {
void showData(int type,Callback callback);
}
model类
public class ShowXrecyclerViewp1 implements IShowXrecyclerViewp1 {
@Override
public void showData(int type,Callback callback) {
OkHttpUtils.getInstance().doGet("http://news-at.zhihu.com/api/4/news/before/"+type+"",callback);
}
}
view层:
public interface bannerview {
void getXrecyclerViewData(List<XrecyclerViewp1Bean.StoriesBean> listx);
int getID();
}
presenter层:
public class XrecyclerViewp1Presenter {
Context context;
IShowXrecyclerViewp1 model;
bannerview view;
private List<XrecyclerViewp1Bean.StoriesBean> listx;
public XrecyclerViewp1Presenter(Context context,bannerview view){
this.context=context;
this.view=view;
model=new ShowXrecyclerViewp1();
}
public void showXrecyclerViewData(){
int type=view.getID();
model.showData(type, new OnUiCallback() {
@Override
public void onFailed(Call call, IOException e) {
}
@Override
public void onSuccess(String result) throws IOException {
Gson gson = new Gson();
XrecyclerViewp1Bean x = gson.fromJson(result, XrecyclerViewp1Bean.class);
listx=x.getStories();
view.getXrecyclerViewData(listx);
}
});
}
}
看看它的adapter类:
public class XrecyclerViewp4adapter extends XRecyclerView.Adapter<XrecyclerViewp4adapter.MyViewHolder> {
Context context;
List<RecyclerViewp4Bean.OthersBean> listg;
public XrecyclerViewp4adapter(Context context,List<RecyclerViewp4Bean.OthersBean> listg){
this.context=context;
this.listg=listg;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view=View.inflate(context,R.layout.grideitem,null);
MyViewHolder myViewHolder = new MyViewHolder(view);
return myViewHolder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.tvp4.setText(listg.get(position).getName());
ImageLoader.getInstance().displayImage(listg.get(position).getThumbnail(),holder.ivp4);
}
@Override
public int getItemCount() {
return listg==null?0:listg.size();
}
class MyViewHolder extends XRecyclerView.ViewHolder{
ImageView ivp4;
TextView tvp4;
public MyViewHolder(View itemView) {
super(itemView);
tvp4=itemView.findViewById(R.id.tvg);
ivp4=itemView.findViewById(R.id.ivg);
}
}
}
最后在fragment里面实现---showData()方法是刷新功能:
public class Fragmentzxrb extends Fragment implements bannerview {
View view;
private ViewPager mVprb;
Banner bb;
bannerpresenter presenter;
XrecyclerViewp1Adapter xrecyclerViewp1Adapter;
XrecyclerViewp1Presenter presenterx;
List<String> listm;
XRecyclerView rv;
int type=20131119;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view = View.inflate(getActivity(), R.layout.fragmentzxrb, null);
initView();
presenter=new bannerpresenter(getActivity(),this);
presenterx=new XrecyclerViewp1Presenter(getActivity(),this);
presenter.showbanner();
presenterx.showXrecyclerViewData();
showData();
return view;
}
private void showData() {
rv.setLoadingListener(new XRecyclerView.LoadingListener() {
@Override
public void onRefresh() {
type++;
presenterx.showXrecyclerViewData();
xrecyclerViewp1Adapter.notifyDataSetChanged();
rv.refreshComplete();
}
@Override
public void onLoadMore() {
type++;
presenterx.showXrecyclerViewData();
xrecyclerViewp1Adapter.notifyDataSetChanged();
rv.refreshComplete();
}
});
}
private void initView() {
rv=view.findViewById(R.id.rv);
LinearLayoutManager layoutManager=new LinearLayoutManager(getActivity());
rv.setLayoutManager(layoutManager);
rv.addItemDecoration(new DividerItemDecoration(getActivity(),DividerItemDecoration.VERTICAL));
bb=view.findViewById(R.id.bb);
listm=new ArrayList<>();
}
@Override
public void getbannerData(List<BannerBean.TopStoriesBean> listb) {
for(int i=0;i<listb.size();i++){
listm.add(listb.get(i).getImage());
}
bb.setImageLoader(new ImageLoaderBanner());
bb.setImages(listm);
bb.start();
}
@Override
public void getXrecyclerViewData(List<XrecyclerViewp1Bean.StoriesBean> listx) {
xrecyclerViewp1Adapter = new XrecyclerViewp1Adapter(getActivity(), listx);
rv.setAdapter(xrecyclerViewp1Adapter);
}
@Override
public int getID() {
return type;
}
}