例:
技能要求:
1. 如上图,使用 MVP+xRecyclerView+Retrofit+OkHttp+RxJava
接口:APIKEY=‘71e58b5b2f930eaf1f937407acde08fe’
http://api.tianapi.com/nba/?key=APIKEY&num=10
实现思路
1. 主页面显示一个xRecycleveiw实现分页加载
2. Retrofit访问网络接口获取数据
3. 添加动态代理
4. Rxjava异步处理数据
5. 设置适配器,将数据列表传入适配器
6. 重写适配器的4个方法,并在显示视图的方法中做优化
7. 在构造方法中初始化Fresco并做配置
8. 配置图片的显示方式为圆形显示
9. 在适配器显示视图的方法中通过Fresco来显示图片
10.点击删除条目
添加依赖:dependencies { compile 'io.reactivex:rxjava:1.3.4' compile 'io.reactivex:rxandroid:1.2.1' compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0' compile 'com.squareup.retrofit2:adapter-rxjava:2.3.0' compile 'com.squareup.retrofit2:adapter-rxjava:2.3.0-beta4' compile 'com.squareup.okhttp3:okhttp:3.9.0' //compile project(':xrecyclerview') compile 'com.facebook.fresco:fresco:0.12.0'//fresco compile 'com.jcodecraeer:xrecyclerview:1.3.2'//xrecyclerview }
加权限:
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
http://api.tianapi.com/nba/?key=APIKEY&num=10
public class JavaBean { /** * code : 200 * msg : success * newslist : [{"APIKEY":"1554c051d8e3f9e205a4cd77ae3168eb","title":"[贴图]迷人的职业女性【2016・11・09】","description":"华声美女","picUrl":"http://image.hnol.net/c/2016-11/09/11/201611091148413631-4761447.jpg","url":"http://bbs.voc.com.cn/mm/meinv-7527597-0-1.html"},{"ctime":"2016-11-09 16:00","title":"水灵秀气 陆金佳Jessica 气质养眼私房大秀迷人美腿","description":"美女写真","picUrl":"http://m.xxxiao.com/wp-content/uploads/sites/3/2016/09/m.xxxiao.com_e9b1d07eb4eefb2de98e7e1f267a2aad-682x1024.jpg","url":"http://m.xxxiao.com/78896"},{"ctime":"2016-11-09 16:00","title":"邻家有女叫格格 [贴图] 【2016・11・09】","description":"华声美女","picUrl":"http://image.hnol.net/c/2016-11/09/14/201611091440404841-4761447.jpg","url":"http://bbs.voc.com.cn/mm/meinv-7527869-0-1.html"},{"ctime":"2016-11-09 16:00","title":"演员何花清纯甜美知性诱惑","description":"华声美女","picUrl":"http://image.hnol.net/c/2016-11/07/17/201611071717489781-2484647.jpg","url":"http://bbs.voc.com.cn/mm/meinv-7524871-0-1.html"},{"ctime":"2016-11-09 20:00","title":"傲娇优雅 啊狸ali 清凉夏日女仆","description":"美女写真","picUrl":"http://m.xxxiao.com/wp-content/uploads/sites/3/2016/08/m.xxxiao.com_51b9d936d17a1be700847c24b793b24b-683x1024.jpg","url":"http://m.xxxiao.com/67756"},{"ctime":"2016-11-09 22:00","title":"带眼镜的女孩","description":"华声美女","picUrl":"http://image.hnol.net/c/2016-11/09/21/20161109214852611-619336.jpg","url":"http://bbs.voc.com.cn/mm/meinv-7528672-0-1.html"},{"ctime":"2016-11-09 22:00","title":"爱秀18 (杨若心Young 2016.11.9)","description":"华声美女","picUrl":"http://image.hnol.net/c/2016-11/09/21/20161109210818721-5058976.jpg","url":"http://bbs.voc.com.cn/mm/meinv-7528658-0-1.html"},{"ctime":"2016-11-09 22:00","title":"爱秀17 (余菲菲Faye2016.11.9)","description":"华声美女","picUrl":"http://image.hnol.net/c/2016-11/09/21/201611092120006111-5058976.jpg","url":"http://bbs.voc.com.cn/mm/meinv-7528657-0-1.html"},{"ctime":"2016-11-09 22:00","title":"丽柜 (Model 允儿2016.11.09)","description":"华声美女","picUrl":"http://image.hnol.net/c/2016-11/09/21/2016110921290321-5058976.jpg","url":"http://bbs.voc.com.cn/mm/meinv-7528654-0-1.html"},{"ctime":"2016-11-09 22:00","title":"美女明星蔡蝶","description":"华声美女","picUrl":"http://image.hnol.net/c/2016-11/09/20/201611092015092811-2228137.jpg","url":"http://bbs.voc.com.cn/mm/meinv-7528543-0-1.html"}] */ private int code; private String msg; private List<NewslistBean> newslist; public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public List<NewslistBean> getNewslist() { return newslist; } public void setNewslist(List<NewslistBean> newslist) { this.newslist = newslist; } public static class NewslistBean { /** * ctime : 2016-11-09 14:00 * title : [贴图]迷人的职业女性【2016・11・09】 * description : 华声美女 * picUrl : http://image.hnol.net/c/2016-11/09/11/201611091148413631-4761447.jpg * url : http://bbs.voc.com.cn/mm/meinv-7527597-0-1.html */ private String ctime; private String title; private String description; private String picUrl; private String url; public String getCtime() { return ctime; } public void setCtime(String ctime) { this.ctime = ctime; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getPicUrl() { return picUrl; } public void setPicUrl(String picUrl) { this.picUrl = picUrl; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } } }
MainActivity 主方法类:
public class MainActivity extends AppCompatActivity { private List<JavaBean.NewslistBean> list = new ArrayList<>(); private int num=10; private NewsPresenter presenter; private MyAdapter adapter; private XRecyclerView xRecyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); xRecyclerView = (XRecyclerView) findViewById(R.id.rv); LinearLayoutManager layoutManager = new LinearLayoutManager(this); //显示垂直滚动列表或水,VERTICAL平垂直的 layoutManager.setOrientation(LinearLayoutManager.VERTICAL); xRecyclerView.setLayoutManager(layoutManager); Fresco.initialize(this);//Fresco初始化 getData(num);//数据连接 //设置下拉刷新和加载更多可执行,为true xRecyclerView.setPullRefreshEnabled(true); xRecyclerView.setLoadingMoreEnabled(true); xRecyclerView.setRefreshProgressStyle(ProgressStyle.BallSpinFadeLoader);//下拉刷新 xRecyclerView.setLoadingMoreProgressStyle(ProgressStyle.Pacman);//上拉加载 /** *设定下拉刷新和上拉加载监听 */ xRecyclerView.setLoadingListener(new XRecyclerView.LoadingListener() { //下拉刷新监听 @Override public void onRefresh() { new Handler().postDelayed(new Runnable(){ public void run() { num=10; getData(num); xRecyclerView.refreshComplete(); } }, 2000); } //上拉加载监听 @Override public void onLoadMore() { new Handler().postDelayed(new Runnable(){ public void run() { num+=10; getData(num); xRecyclerView.refreshComplete(); } }, 2000); } }); } /** * 数据连接 * http://api.tianapi.com/nba/?key=APIKEY&num=10 */ public void getData(int count){ presenter = new NewsPresenter(); presenter.getNews("APIKEY", count); presenter.attachView(new NewsView() { @Override public void success(List<JavaBean.NewslistBean> data) { list.clear(); list.addAll(data); Log.i("zzz", "success: " + list.toString()); if (adapter==null){ adapter = new MyAdapter(list, MainActivity.this); xRecyclerView.setAdapter(adapter); }else { adapter.notifyDataSetChanged(); } } @Override public void failed(String e) { } }); } @Override protected void onDestroy() { super.onDestroy(); if (presenter!=null){ presenter.detachView(); } } }
activity_main 主方法类布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <com.jcodecraeer.xrecyclerview.XRecyclerView android:id="@+id/rv" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
NewsPresenter 类:(有做防止内存泄漏的操作)
public class NewsPresenter { private NewsView inv; private Subscription subscribe; public void attachView(NewsView inv){ this.inv = inv; } public void getNews(String key,int num){ Retrofit retrofit = RetrofitUtils.getInstance().getRetrofit(); BlogService service = retrofit.create(BlogService.class); subscribe = service.getUrl(key, num) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<JavaBean>() { @Override public void call(JavaBean javaBean) { List<JavaBean.NewslistBean> list = javaBean.getNewslist(); inv.success(list); } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { inv.failed(throwable.getMessage()); } }); } public void detachView(){ // 当Activity销毁的时候取消订阅时间,防止内存泄漏 if (subscribe != null) { if (subscribe.isUnsubscribed()) { subscribe.unsubscribe(); } } if (inv!=null){ inv = null; } } }
NewsView 接口:
public interface NewsView { void success(List<JavaBean.NewslistBean> data); void failed(String e); }
RetrofitUtils 类:
public class RetrofitUtils { private static volatile RetrofitUtils instance; private Retrofit retrofit; private RetrofitUtils(){ } private RetrofitUtils(String baseUrl){ OkHttpClient client = new OkHttpClient(); retrofit = new Retrofit.Builder() .client(client) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .baseUrl(baseUrl) .build(); } public static RetrofitUtils getInstance(String baseUrl){ if (instance==null){ synchronized (RetrofitUtils.class){ if (null==instance){ instance = new RetrofitUtils(baseUrl); } } } return instance; } http://api.tianapi.com/nba/?key=APIKEY&num=10 public static RetrofitUtils getInstance(){ if (null == instance){ return getInstance("http://api.tianapi.com/"); } return instance; } public Retrofit getRetrofit(){ return retrofit; } }
BlogService 接口:
public interface BlogService { @GET("meinv/") Observable<JavaBean> getUrl(@Query("key") String key, @Query("num") int num); }
MyAdapter 适配器类:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { private List<JavaBean.NewslistBean> datas; private Context context; public MyAdapter(List<JavaBean.NewslistBean> datas, Context context) { this.datas = datas; this.context = context; } //创建新View,被LayoutManager所调用 @Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { View view = View.inflate(context, R.layout.item, null); ViewHolder vh = new ViewHolder(view); return vh; } //将数据与界面进行绑定的操作 @Override public void onBindViewHolder(ViewHolder viewHolder, final int position) { viewHolder.item_img.setImageURI(datas.get(position).getPicUrl()); //获取图片,Fresco viewHolder.mTextView.setText(datas.get(position).getTitle()); viewHolder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { /** * 点击条目删除 */ AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setIcon(R.mipmap.ic_launcher); builder.setTitle("我是对话框"); builder.setMessage("我是对话框的内容"); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Toast.makeText(context, "点击了取消按钮", Toast.LENGTH_SHORT).show(); dialog.dismiss(); } }); builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Toast.makeText(context, "点击了确定的按钮", Toast.LENGTH_SHORT).show(); dialog.dismiss(); //移除数据 datas.remove(position); //条目刷新 notifyDataSetChanged(); } }); AlertDialog dialog = builder.create(); dialog.show(); } }); } //获取数据的数量 @Override public int getItemCount() { return datas.size(); } //自定义的ViewHolder,持有每个Item的的所有界面元素 public static class ViewHolder extends RecyclerView.ViewHolder { public TextView mTextView; private SimpleDraweeView item_img;//获取图片Fresco public ViewHolder(View view) { super(view); mTextView = (TextView) view.findViewById(R.id.text); item_img = view.findViewById(R.id.item_img); } } }
item 适配器布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:fresco="http://schemas.android.com/apk/res-auto"> <LinearLayout android:layout_gravity="center_horizontal" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:text="名称:" android:textSize="30dp" android:textColor="#000000" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/text" android:textSize="25dp" android:textColor="#FF0000" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> <com.facebook.drawee.view.SimpleDraweeView android:layout_gravity="center_horizontal" android:id="@+id/item_img" android:layout_width="match_parent" android:layout_height="400dp" fresco:placeholderImage="@mipmap/ic_launcher"/> </LinearLayout>
MyApp 类:(记得在清单文件中添加name)
public class MyApp extends Application { @Override public void onCreate() { super.onCreate(); //fresco的初始化 Fresco.initialize(this); } }