前面几篇相关文章介绍了,项目的准备、初建等相关工作。这篇将用于介绍精选模块的实现。看了很多供应商提供的接口如Mob、阿凡达数据以及聚合接口。最后决定使用聚合数据提供的微信精选api。
选择聚合数据理由:简单实用;数据每天都有更新;免费。
其接口的申请地址,及相关介绍请详情https://www.juhe.cn/docs/api/id/147
1、微信精选接口说明
接口地址:public static final String WEIXIN_CHOICE = “http://v.juhe.cn/weixin/query“;
接口返回的json数据如下:
{
"reason": "success",
"result": {
"list": [
{
"id": "wechat_20150401071581",
"title": "号外:集宁到乌兰花的班车出事了!!!!!",
"source": "内蒙那点事儿",
"firstImg": "http://zxpic.gtimg.com/infonew/0/wechat_pics_-214279.jpg/168",
"mark": "",
"url": "http://v.juhe.cn/weixin/redirect?wid=wechat_20150401071581"
},
{
"id": "wechat_20150402028462",
"title": "【夜读】梁晓声:你追求的,就是你人生的意义",
"source": "人民日报",
"firstImg": "http://zxpic.gtimg.com/infonew/0/wechat_pics_-214521.jpg/168",
"mark": "",
"url": "http://v.juhe.cn/weixin/redirect?wid=wechat_20150402028462"
}
],
"totalPage": 16,
"ps": 20,
"pno": 1
},
"error_code": 0
}
从数据中可以很轻易的看出每一个字段,其中list下的数组正是我们需要的数据。更加其我们可以封装出一个对象,以供Gson进行解析。
这里起名为JuheWXChoice,具体代码如下
public class JuheWXChoice {
private int error_code;//返回码
private String reason;//返回说明
private Result result;//结果集
/********get & set************/
...
public String getReason() {
return reason;
}
public class Result {
List<Content> list;
/********get & set************/
...
}
public class Content {
private String id;
private String title;
private String source;//来源
private String firstImg;//缩略图
private String mark;
private String url;
/********get & set************/
...
@Override
public String toString() {
return "Content{" +
"id='" + id + '\'' +
", title='" + title + '\'' +
", source='" + source + '\'' +
", firstImg='" + firstImg + '\'' +
", mark='" + mark + '\'' +
", url='" + url + '\'' +
'}';
}
}
}
注意点:封装的对象属性名一定要与json数据的字段一致,private Result result属性的‘result’与json数据的‘result’相对应,如果把名字一变,将会出现解析异常。当然分装的对象中可以少,也就是说private String id;去了,依旧可以解析,只不过没有对象中没有id这属性了。
2、通过接口进行数据加载
更加接口的说明我们在进行get时需要传入的参数分别为key与pno,其它默认就行。
再此之前我们新建一个NetAction类,用于App中的所有数据加载工作,当然相关的加载我们还是得使用之前封装好的NetUtils类详情请看http://blog.youkuaiyun.com/it_faquir/article/details/52982494介绍。
public void getJuheWXChoice(String page, final List<JuheWXChoice.Content> choice) {
Map<String, String> param = new HashMap<>();
param.put("key", "" + MyApplication.JUHE_KEY);
param.put("pno", "" + page);//第几页
NetUtils.get(NetUri.JUHE.WEIXIN_CHOICE, param, new StringCallback() {
@Override
public void onError(Call call, Exception e, int i) {
}
@Override
public void onResponse(String s, int i) {
Gson gson = new Gson();
JuheWXChoice juheWXChoice = gson.fromJson(s, JuheWXChoice.class);
choice.addAll(juheWXChoice.getResult().getList());
netLoadings.get(KUID_CHOICE_LIST).netLoadingComp(KUID_CHOICE_LIST);
}
});
}
我们会发现其中有个netLoadings.get(KUID_CHOICE_LIST).netLoadingComp(KUID_CHOICE_LIST);,这个的实现目的是为了在加载完数据后通知界面进行相应的更新。其实也这里用了观察者模式。
首先写一个接口,专门用于此。如下:
/**
* 观察者模式网络加载专用接口,kuid作为某个事件的一个id。
*/
public interface NetLoadingListener {
void netLoadingComp(int kuid);
}
你会好奇,kuid是干嘛的,其实作者目的是为了能够使此接口适用于不同环境的网络加载中,以kuid作为唯一标识,而不用重复写多个类似的接口。
在NetAction中我们需要如下Map用于存放NetLoadingListener,便可应用中kuid来找到对象的NetLoadingListener,进行相应的事件通知。
private static Map<Integer, NetLoadingListener> netLoadings = new HashMap<>();
//添加网络加载事件
public static void addNetLoadingListener(int kuid, NetLoadingListener listener) {
netLoadings.put(kuid, listener);
System.out.println("add ok");
}
在ChoiceFragment的onCreate中实现实现相应的接口
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//添加监听器
NetAction.addNetLoadingListener(NetAction.KUID_CHOICE_LIST, this);
netAction = NetAction.newAction();
netAction.getJuheWXChoice("" + curPager, choiceList);
}
/**
* 监听器触发处,网络数据获取完成,触发此
* @param kuid
*/
@Override
public void netLoadingComp(int kuid) {
if (kuid == NetAction.KUID_CHOICE_LIST) {
mAdapter.notifyDataSetChanged();
}
}
当数据加载成功后,netLoadingComp方法便被调用,此此时的List < JuheWXChoice.Content> choiceList引用的对象便不为空,且有数据,我们即可进行正常的显示数据。
3、利用RecycleView进行数据显示
根据加载的数据,我们可以设计item需要显示的内容:
因此我们可以对此进行相应的界面编写
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/choice_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorWhite"
android:clickable="true"
android:elevation="2dp"
android:orientation="vertical"
android:padding="5dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/choice_list_img"
android:layout_width="80dp"
android:layout_height="80dp" />
<TextView
android:id="@+id/choice_list_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="10dp"
android:layout_toEndOf="@+id/choice_list_img"
android:layout_toRightOf="@+id/choice_list_img"
android:lines="3"
android:text="@string/app_name"
android:textColor="@color/colorBlack"
android:textSize="14sp" />
<TextView
android:id="@+id/choice_list_source"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginRight="10dp"
android:text="@string/app_name"
android:textSize="12sp" />
</RelativeLayout>
</LinearLayout>
在ChoiceFragment中进行相应的RecycleAdapter的编写与RecycleView显示即可,完整代码如下
/**
* Created by hgs on 2016/10/26.
*/
public class ChoiceFragment extends BaseFragment implements NetLoadingListener, MySwipe.OnUpLoadingListener, SwipeRefreshLayout.OnRefreshListener {
private static ChoiceFragment choiceFragment;
//数据
private List<JuheWXChoice.Content> choiceList = new ArrayList<>();
private NetAction netAction;
private int curPager = 1;//记录当前所显示的页
private ObjectAnimator animation;
private ChoiceRecycleAdapter mAdapter;
@BindView(R.id.main_bar_title)
TextView tvTitle;
@BindView(R.id.choice_recycle)
RecyclerView cRecycle;
@BindView(R.id.choice_mySwipe)
MySwipe mySwipe;
@BindView(R.id.loading_layout)
View loadingLayout;
@BindView(R.id.loading_icon)
ImageView loadingIcon;
public static ChoiceFragment newInstance() {
if (choiceFragment == null) {
choiceFragment = new ChoiceFragment();
}
return choiceFragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//添加监听器
NetAction.addNetLoadingListener(NetAction.KUID_CHOICE_LIST, this);
netAction = NetAction.newAction();
netAction.getJuheWXChoice("" + curPager, choiceList);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_choice, container, false);
ButterKnife.bind(this, view);
initView();
return view;
}
private void initView() {
tvTitle.setText("指尖精选");
//recycleView
cRecycle.setLayoutManager(new LinearLayoutManager(getContext()));
mAdapter = new ChoiceRecycleAdapter(choiceList);
cRecycle.setAdapter(mAdapter);
}
/**
* 监听器触发处,网络数据获取完成,触发此
*
* @param kuid
*/
@Override
public void netLoadingComp(int kuid) {
if (kuid == NetAction.KUID_CHOICE_LIST) {
mAdapter.notifyDataSetChanged();
}
}
@Override
public void scrollMoving(int scrollY, int distance) {
if (loadingLayout != null) {
loadingLayout.setVisibility(View.VISIBLE);
showUpLoadingAnim(loadingIcon);
}
}
class ChoiceRecycleAdapter extends RecyclerView.Adapter<MyAdapterHolder> {
List<JuheWXChoice.Content> choiceList;
ChoiceRecycleAdapter(List<JuheWXChoice.Content> choiceList) {
this.choiceList = choiceList;
}
@Override
public MyAdapterHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(getContext()).inflate(R.layout.choice_list_layout, null);
return new MyAdapterHolder(view);
}
@Override
public void onBindViewHolder(MyAdapterHolder holder, int position) {
String imgUri = choiceList.get(position).getFirstImg();
if (imgUri == null || imgUri.isEmpty()) {
holder.listImg.setVisibility(View.GONE);
} else
netAction.loadImage(getContext(), choiceList.get(position).getFirstImg(), holder.listImg);
holder.listSource.setText("" + choiceList.get(position).getSource());
holder.listTitle.setText("" + choiceList.get(position).getTitle());
holder.setItemClickListener(choiceList.get(position).getUrl());
}
@Override
public int getItemCount() {
return choiceList.size();
}
}
class MyAdapterHolder extends RecyclerView.ViewHolder{
@BindView(R.id.choice_list_img)
ImageView listImg;
@BindView(R.id.choice_list_title)
TextView listTitle;
@BindView(R.id.choice_list_source)
TextView listSource;
@BindView(R.id.choice_list)
LinearLayout listLayout;
public MyAdapterHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
需要注意的是,作者在这里使用了ButterKnife框架,通过注解的方式来简化了findViewById的方式,具体详情https://github.com/JakeWharton/butterknife。
好了我们来看看效果如何吧。
不过你会发现没法进行下拉刷新与上拉加载以及item的点击,查看详细的内容。后续请关注指尖菜谱App从0到1-精选模块实现(2)