结构图
activity_main.xml主布局
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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">
<android.support.v7.widget.RecyclerView
android:id="@+id/rlv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.constraint.ConstraintLayout>
MainActivity
package com.bw.zhoukao1;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.widget.Toast;
import com.bw.zhoukao1.adapter.NewsAdapter;
import com.bw.zhoukao1.presenter.NewsPresenter;
import com.bw.zhoukao1.view.NewsView;
import com.bw.zhoukao1.widget.MyDecoration;
import org.json.JSONArray;
public class MainActivity extends AppCompatActivity implements NewsView {
private RecyclerView rlv;
private NewsPresenter presenter;
private int page = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//找控件
rlv = findViewById(R.id.rlv);
//创建布局管理器
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
//设置布局管理器
rlv.setLayoutManager(linearLayoutManager);
//这句就是添加我们自定义的分隔线
rlv.addItemDecoration(new MyDecoration(this, MyDecoration.VERTICAL_LIST));
//实例p
presenter = new NewsPresenter(this);
//内部类使用弱引用管理外部类
presenter.attachView(this);
//调用p关联m
presenter.relecte(page);
//分页
//下拉刷新的时候page为1
presenter.relecte(page);
// 上拉加载 page++
presenter.relecte(page);
/**
* 继续研究
* 分页
* MVP 泛型 向上抽取
* OK 网络拦截器
* RecyclerView 添加动画
*/
}
@Override
public void onView(JSONArray datas) {
//接收数据
Log.i("xxx", datas.length() + "");
final NewsAdapter adapter = new NewsAdapter(this, datas);
rlv.setAdapter(adapter);
//长按监听
adapter.setOnRecyclerViewItemLongClickLisenter(new NewsAdapter.OnRecyclerViewItemLongClickLisenter() {
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onRecyclerViewItemLongClick(int position) {
//接收数据
Toast.makeText(MainActivity.this, "长按条目:" + position, Toast.LENGTH_SHORT).show();
//删除数据
adapter.removeItem(position);
}
});
}
//解决内存泄漏
@Override
protected void onDestroy() {
super.onDestroy();
presenter.detachView();
}
}
model层的NewsModel
package com.bw.zhoukao1.model;
import android.os.Handler;
import android.os.Message;
import com.bw.zhoukao1.utils.OkHttpUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
public class NewsModel {
private String url = "http://365jia.cn/news/api3/365jia/news/headline";
//在外部类中定义接口回调
public interface OnNewsLisenter {
void onNews(JSONArray datas);
}
private OnNewsLisenter lisenter;
public void setOnNewsLisenter(OnNewsLisenter lisenter) {
this.lisenter = lisenter;
}
//创建
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
String json = (String) msg.obj;
try {
JSONObject jsonObject = new JSONObject(json);
JSONObject data = jsonObject.getJSONObject("data");
JSONArray datas = data.getJSONArray("data");
//判空
if (lisenter != null) {
//回调数据
lisenter.onNews(datas);
}
} catch (JSONException e) {
e.printStackTrace();
}
break;
}
}
};
//获取网络数据
public void getNewsData(int page) {
OkHttpUtils.getInstance().doGet(url + "?page=" + page, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String json = response.body().string();
//发消息
Message message = new Message();
message.what = 0;
message.obj = json;
handler.sendMessage(message);
}
});
}
}
presenter层的NewsPresenter
package com.bw.zhoukao1.presenter;
import com.bw.zhoukao1.model.NewsModel;
import com.bw.zhoukao1.view.NewsView;
import org.json.JSONArray;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
/**
* @Auther: jiangnengbao
* @Date: 2019/2/18 15:45:09
* @Description:
*/
public class NewsPresenter<T> {
private final NewsModel model;
private final NewsView newsView;
//声明Reference引用
private Reference<T> reference;
//构造方法中实例m和v
public NewsPresenter(NewsView view) {
newsView = view;
model = new NewsModel();
}
//用弱引用管理view
public void attachView(T t) {
//实例
reference = new WeakReference<T>(t);
}
// p关联m
public void relecte(int page) {
model.getNewsData(page);
//设置监听
model.setOnNewsLisenter(new NewsModel.OnNewsLisenter() {
@Override
public void onNews(JSONArray datas) {
//接收数据
newsView.onView(datas);
}
});
}
//解除弱引用中的view
public void detachView() {
if (reference.get() != null) {
reference.clear();
reference = null;
}
}
}
view层的NewsView
package com.bw.zhoukao1.view;
import org.json.JSONArray;
/**
* @Auther: jiangnengbao
* @Date: 2019/2/18 16:27:33
* @Description:
*/
public interface NewsView {
void onView(JSONArray datas);
}
utils工具类OkHttpUtils
package com.bw.zhoukao1.utils;
import android.util.Log;
import java.util.Map;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.logging.HttpLoggingInterceptor;
/**
* @Auther: jiangnengbao 单例设计模式封装 懒汉
* @Date: 2019/2/18 15:48:44
* @Description:
*/
public class OkHttpUtils {
//私有的静态的成员变量,只声明不创建
private static OkHttpUtils okHttpUtils = null;
//私有的构造方法
private OkHttpUtils() {
}
//返回公共静态的实例方法
public static OkHttpUtils getInstance() {
if (okHttpUtils == null) {
synchronized (OkHttpUtils.class) {
if (okHttpUtils == null) {
okHttpUtils = new OkHttpUtils();
}
}
}
return okHttpUtils;
}
private static OkHttpClient okHttpClient = null;
//返回ok
public synchronized static OkHttpClient getOkHttpClient() {
if (okHttpClient == null) {
//创建日志拦截器
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
Log.i("xxx", message);
}
});
//设置日志拦截器模式
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
//创建okHttpClient
okHttpClient = new OkHttpClient.Builder().addInterceptor(loggingInterceptor).build();
}
return okHttpClient;
}
//get请求
public void doGet(String url, Callback callback) {
//创建OkHttpClient
OkHttpClient okHttpClient = getOkHttpClient();
//创建Request
Request request = new Request.Builder().url(url).build();
Call call = okHttpClient.newCall(request);
//执行异步
call.enqueue(callback);
}
//post请求
public void doPost(String url, Map<String, String> parmars, Callback callback) {
//创建OkHttpClient
OkHttpClient okHttpClient = getOkHttpClient();
//创建builder
FormBody.Builder builder = new FormBody.Builder();
//遍历集合
for (String key : parmars.keySet()) {
builder.add(key,parmars.get(key));
}
//构建FormBody
FormBody formBody = builder.build();
//创建Request
Request request = new Request.Builder().url(url).post(formBody).build();
Call call = okHttpClient.newCall(request);
//执行异步
call.enqueue(callback);
}
}
widget层的MyDecoration
package com.bw.zhoukao1.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class MyDecoration extends RecyclerView.ItemDecoration{
private Context mContext;
private Drawable mDivider;
private int mOrientation;
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
//我们通过获取系统属性中的listDivider来添加,在系统中的AppTheme中设置
public static final int[] ATRRS = new int[]{
android.R.attr.listDivider
};
public MyDecoration(Context context, int orientation) {
this.mContext = context;
final TypedArray ta = context.obtainStyledAttributes(ATRRS);
this.mDivider = ta.getDrawable(0);
ta.recycle();
setOrientation(orientation);
}
//设置屏幕的方向
public void setOrientation(int orientation){
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST){
throw new IllegalArgumentException("invalid orientation"); } mOrientation = orientation;
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == HORIZONTAL_LIST){
drawVerticalLine(c, parent, state);
}else {
drawHorizontalLine(c, parent, state);
}
}
//画横线, 这里的parent其实是显示在屏幕显示的这部分
public void drawHorizontalLine(Canvas c, RecyclerView parent, RecyclerView.State state){
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++){
final View child = parent.getChildAt(i);
//获得child的布局信息
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)child.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
//Log.d("wnw", left + " " + top + " "+right+" "+bottom+" "+i);
}
}
//画竖线
public void drawVerticalLine(Canvas c, RecyclerView parent, RecyclerView.State state){
int top = parent.getPaddingTop();
int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++){
final View child = parent.getChildAt(i);
//获得child的布局信息
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)child.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicWidth();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
//由于Divider也有长宽高,每一个Item需要向下或者向右偏移
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if(mOrientation == HORIZONTAL_LIST){
//画横线,就是往下偏移一个分割线的高度
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
}else {
//画竖线,就是往右偏移一个分割线的宽度
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}
item_one.xml布局
<?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=".MainActivity">
<TextView
android:id="@+id/tv_title1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/iv1"
android:layout_width="100dp"
android:layout_height="100dp" />
</LinearLayout>
item_two.xml布局
<?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="horizontal"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv_title2"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:text="111111111"/>
<ImageView
android:id="@+id/iv2"
android:layout_width="200dp"
android:layout_height="150dp"
android:src="@mipmap/ic_launcher"/>
</LinearLayout>
adapter层的适配器NewsAdapter
package com.bw.zhoukao1.adapter;
import android.content.Context;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bw.zhoukao1.R;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* @Auther: jiangnengbao
* @Date: 2019/2/18 16:37:27
* @Description:
*/
public class NewsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public interface OnRecyclerViewItemLongClickLisenter {
void onRecyclerViewItemLongClick(int position);
}
private OnRecyclerViewItemLongClickLisenter longClickLisenter;
public void setOnRecyclerViewItemLongClickLisenter(OnRecyclerViewItemLongClickLisenter longClickLisenter) {
this.longClickLisenter = longClickLisenter;
}
private static int TYPE_ONE = 0;
private static int TYPE_TWO = 1;
Context context;
JSONArray datas;
public NewsAdapter(Context context, JSONArray datas) {
this.context = context;
this.datas = datas;
}
//返回条目类型
@Override
public int getItemViewType(int position) {
if (position % 2 == 0) {
return TYPE_ONE;
} else {
return TYPE_TWO;
}
}
//创建ViewHolder
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int type) {
//根据类型判断条目布局样式
if (type == TYPE_ONE) {
View view1 = LayoutInflater.from(context).inflate(R.layout.item_one, null, false);
final ViewHolder1 viewHolder1 = new ViewHolder1(view1);
//长按系统view的监听
view1.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
//获取view对应的位置
int layoutPosition = viewHolder1.getLayoutPosition();
//接口回调数据
if (longClickLisenter != null) {
longClickLisenter.onRecyclerViewItemLongClick(layoutPosition);
}
return true;
}
});
return viewHolder1;
} else {
View view2 = LayoutInflater.from(context).inflate(R.layout.item_two, null, false);
final ViewHolder2 viewHolder2 = new ViewHolder2(view2);
//长按系统view的监听
view2.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
//获取view对应的位置
int layoutPosition = viewHolder2.getLayoutPosition();
if (longClickLisenter != null) {
//回调条目对应的位置
longClickLisenter.onRecyclerViewItemLongClick(layoutPosition);
}
return true;
}
});
return viewHolder2;
}
}
//给控件赋值
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
int itemViewType = getItemViewType(i);
if (itemViewType == TYPE_ONE) {
ViewHolder1 viewHolder1 = (ViewHolder1) viewHolder;
try {
JSONObject jsonObject = datas.getJSONObject(i);
viewHolder1.tv_title1.setText(jsonObject.getString("title"));
JSONArray pics = jsonObject.getJSONArray("pics");
String imageUrl = (String) pics.get(0);
Glide.with(context).load("http://365jia.cn/uploads/" + imageUrl).into(viewHolder1.iv1);
} catch (JSONException e) {
e.printStackTrace();
}
} else {
ViewHolder2 viewHolder2 = (ViewHolder2) viewHolder;
try {
JSONObject jsonObject = datas.getJSONObject(i);
viewHolder2.tv_title2.setText(jsonObject.getString("title"));
JSONArray pics = jsonObject.getJSONArray("pics");
String imageUrl = (String) pics.get(0);
Glide.with(context).load("http://365jia.cn/uploads/" + imageUrl).into(viewHolder2.iv2);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
@Override
public int getItemCount() {
return datas.length();
}
//删除对应条目数据
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public void removeItem(int position){
//操作数据源
datas.remove(position);
//刷新
notifyDataSetChanged();
}
//自定义ViewHolde
public class ViewHolder1 extends RecyclerView.ViewHolder {
private final TextView tv_title1;
private final ImageView iv1;
public ViewHolder1(@NonNull View itemView) {
super(itemView);
tv_title1 = itemView.findViewById(R.id.tv_title1);
iv1 = itemView.findViewById(R.id.iv1);
}
}
public class ViewHolder2 extends RecyclerView.ViewHolder {
private final TextView tv_title2;
private final ImageView iv2;
public ViewHolder2(@NonNull View itemView) {
super(itemView);
tv_title2 = itemView.findViewById(R.id.tv_title2);
iv2 = itemView.findViewById(R.id.iv2);
}
}
}
依赖
implementation 'com.android.support:recyclerview-v7:28.+'
implementation 'com.squareup.okio:okio:1.5.0'
implementation 'com.squareup.okhttp3:okhttp:3.2.0'
implementation 'com.github.bumptech.glide:glide:4.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.4.1'
implementation project(':xrecyclerview')
权限
<uses-permission android:name="android.permission.INTERNET"></uses-permission>