实现思路:
1. 主页面显示一个xRecycleveiw实现分页加载
2. Retrofit访问网络接口获取数据
3. xRecycleview 实现多条目展示上面效果
4. MVP分层;P调M ;V实现P
5. 自定义搜索框
6. 在构造方法中初始化Fresco并做配置
7. 配置图片的显示方式为圆形显示
8. 在适配器显示视图的方法中通过Fresco来显示图片
接口:APIKEY=‘71e58b5b2f930eaf1f937407acde08fe’
http://api.tianapi.com/nba/?key=APIKEY&num=10
1.依赖
//《Butterknife依赖(黄油刀)》 compile 'com.jakewharton:butterknife:8.8.1' annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' //《XRecyclerview依赖》 compile 'com.jcodecraeer:xrecyclerview:1.3.2' //《Okhttp网络请求依赖》 compile 'com.squareup.okhttp3:okhttp:3.10.0' //《Retrofit网络请求依赖》 implementation 'com.squareup.retrofit2:retrofit:2.4.0' compile 'com.squareup.retrofit2:converter-gson:2.4.0' //《Fresco图片框架依赖》 compile 'com.facebook.fresco:fresco:0.14.1' //《RXjava2的适配器》 compile 'com.squareup.retrofit2:adapter-rxjava2:2.4.0' //《Rxjava2》 compile 'io.reactivex.rxjava2:rxjava:2.1.7' compile 'io.reactivex.rxjava2:rxandroid:2.0.1' //《Gson解析依赖》 compile 'com.google.code.gson:gson:2.2.4'
2.权限
<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"/>
3.网络获取接口的数据Bean
package com.example.rikao0419.entity; import java.util.List; public class MyNewsListBean { 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 { 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; } } }
4.接口
package com.example.rikao0419.utils; //创建方法 保存接口 public class StringUrl { public static final String BASE_URL="http://api.tianapi.com/"; }
5.拼接接口
package com.example.rikao0419.service; import com.example.rikao0419.entity.MyNewsListBean; import io.reactivex.Observable; import retrofit2.http.GET; import retrofit2.http.Query; public interface ApiService { //拼接数据接口 //请求次数多用:Flowable(背压) 请求次数少用:Observable(无背压) @GET("nba/") Observable<MyNewsListBean> getData(@Query("key")String key, @Query("num")String num); }
6.RetrofitUtils的封装
package com.example.rikao0419.utils; import com.example.rikao0419.service.ApiService; import retrofit2.Retrofit; import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; import retrofit2.converter.gson.GsonConverterFactory; //Retrofit 网络请求框架 public class RetrofitUtils { //1创建一个单列模式 private static volatile RetrofitUtils instance; private final Retrofit retrofit; //2创建一个私有的无参构造 private RetrofitUtils(){ //3创建Retrofit retrofit = new Retrofit.Builder() .baseUrl(StringUrl.BASE_URL)//接口 .addConverterFactory(GsonConverterFactory.create())//默认Gson解析 .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//使用RxJava2的适配器 .build(); } //4.创建一个静态方法,得到instance 判断是否为空 public static RetrofitUtils getInstance(){ if(instance==null){ //添加同步锁 synchronized (RetrofitUtils.class){ if(null==instance){ instance = new RetrofitUtils(); } } } //5返回创建的instance return instance; } //6创建方法 方便调用 public ApiService getservice(){ return retrofit.create(ApiService.class); } }
7.M层接口
package com.example.rikao0419.model; public interface DataModel { //定义请求数据的方法 void getModelData(String key,String num); }
8.M层实现类
package com.example.rikao0419.model; import com.example.rikao0419.entity.MyNewsListBean; import com.example.rikao0419.presenter.MyDataPresenter; import com.example.rikao0419.utils.RetrofitUtils; import io.reactivex.Observable; public class MyDataModel implements DataModel{ MyDataPresenter presenter; //创建构造方法,将p层传入M层 public MyDataModel(MyDataPresenter presenter){ this.presenter=presenter; } //重写请求数据的方法 @Override public void getModelData(String key, String num) { //RetrofitUtils工具类 调用getservice,得到ApiService,再调用其数据方法 Observable<MyNewsListBean> data = RetrofitUtils.getInstance().getservice().getData(key, num); //调用P层方法,将数据传给P层 presenter.getPresenterData(data); } }
9.P层的接口
package com.example.rikao0419.presenter; import com.example.rikao0419.entity.MyNewsListBean; import io.reactivex.Observable; public interface DataPresenter { //定义请求数据的方法 void getPresenterData( Observable<MyNewsListBean> data); }
10.P层的实现类
package com.example.rikao0419.presenter; import com.example.rikao0419.entity.MyNewsListBean; import com.example.rikao0419.model.MyDataModel; import com.example.rikao0419.view.DataView; import java.util.List; import io.reactivex.Observable; import io.reactivex.Observer; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; public class MyDataPresenter implements DataPresenter{ //创建构造器 将M层传入P层 DataView dataView; private final MyDataModel model; public MyDataPresenter(DataView dataView){ this.dataView=dataView; //实例化M层 将P层传给M层 model = new MyDataModel(this); } //重写请求数据的方法 @Override public void getPresenterData( Observable<MyNewsListBean> data) { //改变线程 RXjava异步 data.subscribeOn(Schedulers.io())//Io子线程 网络请求 .observeOn(AndroidSchedulers.mainThread())//主线程 更新控件 //subscribe:赋观察者的方法 Observer:观察者 .subscribe(new Observer<MyNewsListBean>() { //onSubscribe:订阅者 @Override public void onSubscribe(Disposable d) {} //下一个 @Override public void onNext(MyNewsListBean myNewsListBean) { //返回集合 判断若集合不等于空 if(myNewsListBean!=null) { List<MyNewsListBean.NewslistBean> newslist = myNewsListBean.getNewslist(); //调用V层方法,将数据传给V层 dataView.Success(newslist); } } //异常 @Override public void onError(Throwable e) { //调用V层方法,将异常数据传给V层 dataView.Error(e); } //成功 @Override public void onComplete() {} }); } //创建一个方法 用于接收V层传来的KEY、NUM public void getKeyorNum(String key,String num){ //调用M层方法 将key和num传给M层 model.getModelData(key, num); } //将V层置空 防止内存泄露 public void DreyView(){ if(dataView!=null){ dataView=null; } } }
11.V层接口
package com.example.rikao0419.view; import com.example.rikao0419.entity.MyNewsListBean; import java.util.List; public interface DataView { //成功与失败的方法 void Success(List<MyNewsListBean.NewslistBean> newslist); void Error(Throwable t); }
12.V层接口的实现类
package com.example.rikao0419.view; import android.os.Bundle; import android.os.Handler; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import com.example.rikao0419.R; import com.example.rikao0419.adapter.MyAdapter; import com.example.rikao0419.entity.MyNewsListBean; import com.example.rikao0419.presenter.MyDataPresenter; import com.jcodecraeer.xrecyclerview.ProgressStyle; import com.jcodecraeer.xrecyclerview.XRecyclerView; import java.util.ArrayList; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; public class MainActivity extends AppCompatActivity implements DataView { @BindView(R.id.main_xrcv) XRecyclerView main_XRcv; private MyDataPresenter presenter; private MyAdapter myAdapter; int num =10;//调用每次请求的条数 //创建集合 用于存放请求的数据 private List<MyNewsListBean.NewslistBean> list = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); //设置布局 main_XRcv.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false)); //实例化P层 ,将V层和key和num传给P层 presenter = new MyDataPresenter(this); presenter.getKeyorNum("71e58b5b2f930eaf1f937407acde08fe","10"); //设置上拉加载下拉刷新 main_XRcv.setLoadingMoreEnabled(true); main_XRcv.setPullRefreshEnabled(true); //设置上拉下拉的样式 main_XRcv.setRefreshProgressStyle(ProgressStyle.BallSpinFadeLoader); main_XRcv.setLoadingMoreProgressStyle(ProgressStyle.Pacman); //设置XRecyclerView的监听器 main_XRcv.setLoadingListener(new XRecyclerView.LoadingListener() { //下拉刷新 @Override public void onRefresh() { new Handler().postDelayed(new Runnable() { @Override public void run() { //重新调用P层方法,请求数据 presenter.getKeyorNum("71e58b5b2f930eaf1f937407acde08fe",num+""); //设置一秒后停止刷新 main_XRcv.refreshComplete(); } },1000); } //上拉加载 @Override public void onLoadMore() { new Handler().postDelayed(new Runnable() { @Override public void run() { //每次请求多增加10条数据 num+=10; //重新调用P层方法,请求数据 presenter.getKeyorNum("71e58b5b2f930eaf1f937407acde08fe",num+""); //设置一秒后停止刷新 main_XRcv.refreshComplete(); } },1000); } }); } //成功 因其在主线程,可直接更新UI 进入适配器 @Override public void Success(List<MyNewsListBean.NewslistBean> newslist) { //清空集合 list.clear(); //将数据重新全部添加入集合 list.addAll(newslist); //进入适配器 getAdapter(); } //设置适配器 void getAdapter(){ //判断适配器是否存在 if(myAdapter == null){ //不存在则创建适配器 myAdapter = new MyAdapter(this,list); //并设置适配器 main_XRcv.setAdapter(myAdapter); }else{ //若存在,则只刷新 myAdapter.notifyDataSetChanged(); } } //失败 @Override public void Error(Throwable t) {} }
13.适配器
package com.example.rikao0419.adapter; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.example.rikao0419.R; import com.example.rikao0419.entity.MyNewsListBean; import com.facebook.drawee.view.SimpleDraweeView; import java.util.List; public class MyAdapter extends RecyclerView.Adapter { Context context; List<MyNewsListBean.NewslistBean> list; private View view; private int itemViewType; public MyAdapter(Context context, List<MyNewsListBean.NewslistBean> list) { this.context=context; this.list=list; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { //获取条目类型 itemViewType = getItemViewType(viewType); //进行判断引入布局 if(itemViewType ==0){ view = View.inflate(context, R.layout.item_01, null); }else{ view = View.inflate(context, R.layout.item_02, null); } //创建myViewHolder 将布局view 传下去 MyViewHolder myViewHolder = new MyViewHolder(view); return myViewHolder; } @Override public int getItemViewType(int position) { //获取条目的下标,进行判断 if(position%2==0){ return 0; }else{ return 1; } } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { MyViewHolder myViewHolder = (MyViewHolder) holder; //根据下标得到条目类型 int itemViewType = getItemViewType(position); //进行判断 进行赋值 if(itemViewType ==0){ myViewHolder.rcv_item01_title.setText(list.get(position).getTitle()); }else{ myViewHolder.rcv_item02_title.setText(list.get(position).getTitle()); myViewHolder.rcv_item02_img.setImageURI(list.get(position).getPicUrl()); } } //条目数量 @Override public int getItemCount() { return list.size(); } class MyViewHolder extends RecyclerView.ViewHolder{ private final TextView rcv_item01_title; private final TextView rcv_item02_title; private final SimpleDraweeView rcv_item02_img; public MyViewHolder(View view) { super(view); //找到引入布局的控件的ID rcv_item01_title = view.findViewById(R.id.rcv_item01_title); rcv_item02_title = view.findViewById(R.id.rcv_item02_title); rcv_item02_img = view.findViewById(R.id.rcv_item02_img); } } }
14.初始化Fresco使用默认配置加载图片
package com.example.rikao0419.app; import android.app.Application; import com.facebook.drawee.backends.pipeline.Fresco; public class MyApp extends Application{ @Override public void onCreate() { super.onCreate(); //初始化Fresco使用默认配置加载图片 Fresco.initialize(this); } }
15.主布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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" android:orientation="vertical" tools:context="com.example.rikao0419.view.MainActivity"> <!--标题布局--> <LinearLayout android:layout_width="match_parent" android:layout_height="80px" android:background="#007FFF" android:layout_gravity="center_vertical" android:gravity="center_vertical" android:orientation="horizontal"> <EditText android:layout_width="match_parent" android:layout_height="50px" android:textColor="#ffffff" android:background="#3399FF" android:paddingLeft="20px" android:hint="搜索" /> </LinearLayout> <!--XRecyclerView主布局--> <com.jcodecraeer.xrecyclerview.XRecyclerView android:id="@+id/main_xrcv" android:layout_width="match_parent" android:layout_height="match_parent"> </com.jcodecraeer.xrecyclerview.XRecyclerView> </LinearLayout>
16.偶数条目布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="10px"> <!--XRecyclerView偶数条目布局--> <TextView android:id="@+id/rcv_item01_title" android:layout_width="match_parent" android:layout_height="100px" android:layout_gravity="center_vertical" android:gravity="center_vertical" android:text="格林:理解科尔吸食大麻 不过我从没吸过"/> </LinearLayout>
17.奇数条目布局
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" xmlns:fresco="http://schemas.android.com/apk/res-auto" android:padding="10px"> <!--XRecyclerView奇数条目布局--> <TextView android:id="@+id/rcv_item02_title" android:layout_width="400px" android:layout_height="wrap_content" android:layout_centerVertical="true" android:gravity="center_vertical" android:text="格林:理解科尔吸食大麻 不过我从没吸过"/> <!--XRecyclerView奇数条目圆形图片布局--> <com.facebook.drawee.view.SimpleDraweeView android:layout_marginLeft="20px" android:id="@+id/rcv_item02_img" android:layout_width="100px" android:layout_height="100px" fresco:actualImageScaleType="centerCrop" fresco:placeholderImageScaleType="centerCrop" fresco:roundAsCircle="true" android:layout_toRightOf="@id/rcv_item02_title"/> </RelativeLayout>