指尖菜谱App从0到1-精选模块实现(1)
来源:互联网 发布:中国省市区数据库 编辑:程序博客网 时间:2024/05/08 18:53
前面几篇相关文章介绍了,项目的准备、初建等相关工作。这篇将用于介绍精选模块的实现。看了很多供应商提供的接口如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.csdn.net/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)
- 指尖菜谱App从0到1-精选模块实现(1)
- 指尖菜谱App从0到1-项目开发准备
- 指尖菜谱App从0到1-项目初次开发
- 指尖菜谱App从0到1-无限循环轮播广告的实现
- “我的菜谱“APP--添加菜谱功能的实现
- 从 0 到 1 打造直播 App
- 从0到1打造直播 App
- 从0到1打造直播 App
- 从0到1打造直播 App
- 从0到1打造直播 App
- ℃江让您从精通到入门:App登陆模块的实现
- iOS 从0到1搭建高可用App框架
- iOS 从0到1搭建高可用App框架
- iOS 从0到1搭建高可用App框架
- iOS 从0到1搭建高可用App框架
- iOS开发之从0到1搭建App框架
- iOS 从0到1搭建高可用App框架
- iOS 从0到1搭建高可用App框架
- 我给媳妇解释设计模式:第一部分
- 笔记:boost中split函数的用法
- 1107. Social Clusters (30)解题报告
- 04-树5 Root of AVL Tree (25分)
- linux 内核移植和根文件系统的制作
- 指尖菜谱App从0到1-精选模块实现(1)
- MFC简易音乐播放器
- 每天对着点电脑坐久了
- SSH框架部署到服务器上js中url中文乱码问题
- RERAN:安卓系统的定时和点击的录制和回放——(5)
- spring boot 配合前端实现跨域
- MCMC中的Metropolis–Hastings算法与吉布斯采样
- LintCode 52-下一个排列
- OpenGL入门学习