1.实现订阅号的基础类

1.1.本地订阅号的Bean类==>MediaChannelBean

public class MediaChannelBean implements Parcelable {

    public static final Creator<MediaChannelBean> CREATOR = new Creator<MediaChannelBean>() {
@Override
public MediaChannelBean createFromParcel(Parcel in) {
return new MediaChannelBean(in);
} @Override
public MediaChannelBean[] newArray(int size) {
return new MediaChannelBean[size];
}
};
private String id;
private String name;
private String avatar;
private String type;
private String followCount;
private String descText;
private String url; public MediaChannelBean() {
} protected MediaChannelBean(Parcel in) {
id = in.readString();
name = in.readString();
avatar = in.readString();
type = in.readString();
followCount = in.readString();
descText = in.readString();
url = in.readString();
} @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeString(name);
dest.writeString(avatar);
dest.writeString(type);
dest.writeString(followCount);
dest.writeString(descText);
dest.writeString(url);
} @Override
public int describeContents() {
return 0;
} public String getId() {
return id;
} public void setId(String id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getAvatar() {
return avatar;
} public void setAvatar(String avatar) {
this.avatar = avatar;
} public String getType() {
return type;
} public void setType(String type) {
this.type = type;
} public String getFollowCount() {
return followCount;
} public void setFollowCount(String followCount) {
this.followCount = followCount;
} public String getDescText() {
return descText;
} public void setDescText(String descText) {
this.descText = descText;
} public String getUrl() {
return url;
} public void setUrl(String url) {
this.url = url;
}
}

1.2.数据库建立订阅号的基础表==>MediaChannelTable 

public class MediaChannelTable {
/**
* 头条号信息表
*/
public static final String TABLENAME = "MediaChannelTable"; /**
* 字段部分
*/
public static final String ID = "id";
public static final String NAME = "name";
public static final String AVATAR = "avatar";
public static final String TYPE = "type";
public static final String FOLLOWCOUNT = "followCount";
public static final String DESCTEXT = "descText";
public static final String URL = "url"; /**
* 字段ID 数据库操作建立字段对应关系 从0开始
*/
public static final int ID_ID = 0;
public static final int ID_NAME = 1;
public static final int ID_AVATAR = 2;
public static final int ID_TYPE = 3;
public static final int ID_FOLLOWCOUNT = 4;
public static final int ID_DESCTEXT = 5;
public static final int ID_URL = 6; /**
* 创建表
*/
public static final String CREATE_TABLE = "create table if not exists " + TABLENAME + "(" +
ID + " text primary key, " +
NAME + " text, " +
AVATAR + " text, " +
TYPE + " text, " +
FOLLOWCOUNT + " text, " +
DESCTEXT + " text, " +
URL + " text) ";
}

1.3.实现最底层订阅号的数据库操作

  

public class MediaChannelDao {
private SQLiteDatabase db; public MediaChannelDao(){
this.db= DatabaseHelper.getDatabase();
} public void initData(){
add("4377795668", "新华网", "http://p2.pstatp.com/large/3658/7378365093", "news",
"", "传播中国,报道世界;权威声音,亲切表达。", "http://toutiao.com/m4377795668/");
add("52445544609", "互联网的这点事", "http://p3.pstatp.com/large/ef300164e786ff295da", "news",
"", "每天为你速递最新、最鲜、最有料的互联网科技资讯!", "http://toutiao.com/m52445544609/");
} public boolean add(String id,
String name,
String avatar,
String type,
String followCount,
String descText,
String url) {
ContentValues values = new ContentValues();
values.put(MediaChannelTable.ID, id);
values.put(MediaChannelTable.NAME, name);
values.put(MediaChannelTable.AVATAR, avatar);
values.put(MediaChannelTable.TYPE, type);
values.put(MediaChannelTable.FOLLOWCOUNT, followCount);
values.put(MediaChannelTable.DESCTEXT, descText);
values.put(MediaChannelTable.URL, url);
long result = db.insert(MediaChannelTable.TABLENAME, null, values);
return result != -1;
} public List<MediaChannelBean> queryAll() {
Cursor cursor = db.query(MediaChannelTable.TABLENAME, null, null, null, null, null, null);
List<MediaChannelBean> list = new ArrayList<>();
while (cursor.moveToNext()) {
MediaChannelBean bean = new MediaChannelBean();
bean.setId(cursor.getString(MediaChannelTable.ID_ID));
bean.setName(cursor.getString(MediaChannelTable.ID_NAME));
bean.setAvatar(cursor.getString(MediaChannelTable.ID_AVATAR));
bean.setType(cursor.getString(MediaChannelTable.ID_TYPE));
bean.setFollowCount(cursor.getString(MediaChannelTable.ID_FOLLOWCOUNT));
bean.setDescText(cursor.getString(MediaChannelTable.ID_DESCTEXT));
bean.setUrl(cursor.getString(MediaChannelTable.ID_URL));
list.add(bean);
}
cursor.close();
return list;
} public boolean queryIsExist(String id) {
Cursor cursor = db.query(MediaChannelTable.TABLENAME, null, MediaChannelTable.ID + "=?", new String[]{id}, null, null, null);
if (cursor.moveToNext()) {
cursor.close();
return true;
}
cursor.close();
return false;
} public boolean delete(String mediaId) {
int id = db.delete(MediaChannelTable.TABLENAME, MediaChannelTable.ID + "=?", new String[]{mediaId});
return id != -1;
}
}

  

2.构建订阅号视图页面

2.1.创建订阅号视图布局==>fragment_media.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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/windowBackground"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior"> <android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"> <android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"> <TextView
android:id="@+id/tv_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/media_hint_desc"/> <android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fadeScrollbars="true"
android:scrollbarFadeDuration="1"
android:scrollbars="vertical"/> </android.support.design.widget.CoordinatorLayout> </android.support.v4.widget.SwipeRefreshLayout> </LinearLayout>

  预览图片:

  

2.2.定义一个长按监听事件==>长按弹出提示框 

public interface IOnItemLongClickListener {

    /**
* RecyclerView Item长按事件
*/
void onLongClick(View view, int position);
}

2.3.构建一个订阅号视图类 

public class MediaChannelView extends RxFragment implements SwipeRefreshLayout.OnRefreshListener {

    private static final String TAG = "MediaChannelView";
private static MediaChannelView instance = null;
private RecyclerView recyclerView;
private SwipeRefreshLayout swipeRefreshLayout;
private MultiTypeAdapter adapter;
private MediaChannelDao dao = new MediaChannelDao();
private TextView tv_desc;
private String isFirstTime = "isFirstTime";
private List<MediaChannelBean> list; public static MediaChannelView getInstance() {
if (instance == null) {
instance = new MediaChannelView();
}
return instance;
} @Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_media, container, false);
initView(view);
initData();
return view;
} @Override
public void onResume() {
super.onResume();
swipeRefreshLayout.setColorSchemeColors(SettingUtil.getInstance().getColor());
setAdapter();
} private void initData() {
SharedPreferences editor = getActivity().getSharedPreferences(TAG, Context.MODE_PRIVATE);
boolean result = editor.getBoolean(isFirstTime, true);
if (result) {
dao.initData();
editor.edit().putBoolean(isFirstTime, false).apply();
}
setAdapter();
} private void setAdapter() {
Observable
.create(new ObservableOnSubscribe<List<MediaChannelBean>>() {
@Override
public void subscribe(@NonNull ObservableEmitter<List<MediaChannelBean>> e) throws Exception {
list = dao.queryAll();
e.onNext(list);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(this.<List<MediaChannelBean>>bindUntilEvent(FragmentEvent.DESTROY))
.subscribe(new Consumer<List<MediaChannelBean>>() {
@Override
public void accept(@NonNull List<MediaChannelBean> list) throws Exception {
adapter.setItems(list);
adapter.notifyDataSetChanged();
if (list.size() == 0) {
tv_desc.setVisibility(View.VISIBLE);
} else {
tv_desc.setVisibility(View.GONE);
}
}
});
} private void initView(View view) {
recyclerView = view.findViewById(recycler_view);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); swipeRefreshLayout = view.findViewById(R.id.refresh_layout);
swipeRefreshLayout.setColorSchemeColors(SettingUtil.getInstance().getColor());
swipeRefreshLayout.setOnRefreshListener(this);
tv_desc = view.findViewById(R.id.tv_desc); IOnItemLongClickListener listener = new IOnItemLongClickListener() {
@Override
public void onLongClick(View view, int position) {
final MediaChannelBean item = list.get(position);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("取消订阅\" " + item.getName() + " \"?");
builder.setPositiveButton(R.string.button_enter, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
new Thread(new Runnable() {
@Override
public void run() {
dao.delete(item.getId());
setAdapter();
}
}).start();
dialog.dismiss();
}
});
builder.setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.show();
}
};
adapter = new MultiTypeAdapter();
Register.registerMediaChannelItem(adapter, listener);
recyclerView.setAdapter(adapter);
} @Override
public void onRefresh() {
swipeRefreshLayout.setRefreshing(true);
setAdapter();
swipeRefreshLayout.setRefreshing(false);
} @Override
public void onDestroyView() {
super.onDestroyView();
if (instance != null) {
instance = null;
}
}
}

  注意:如果setAdapter简化成下面这个函数,直观效果一直。 

private void setAdapter(){
list=dao.queryAll();
adapter.setItems(list);
adapter.notifyDataSetChanged();
if (list.size() == 0) {
tv_desc.setVisibility(View.VISIBLE);
} else {
tv_desc.setVisibility(View.GONE);
}
}

  但是,如果订阅号的数量很多很多后,这种效果远远不如订阅的方法性能好。

  所以我们统一就用订阅的方式吧。

  而且更加重要的是,如果没有数据的时候,

  这里要进行界面操作,如果直接在io线程会发生异常的。

2.4.发现Register中还没有注册类型以及传入监听求

 public static void registerMediaChannelItem(@NonNull MultiTypeAdapter adapter, @NonNull IOnItemLongClickListener listener) {
adapter.register(MediaChannelBean.class, new MediaChannelViewBinder(listener));
}

  这里发现了监听器传进去了,说明绑定类中要给每一行都要设置这个listener

  然后这里又看到MediaChannelViewBinder绑定类还没有实现呢!

  第三点主要讲解这个简单的绑定类。

3.订阅号视图绑定类

3.1.首先看一下视图布局吧。==>item_media_channel.xml 

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/viewBackground"> <LinearLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:foreground="?attr/selectableItemBackground"
android:padding="8dp"> <com.meiji.toutiao.widget.CircleImageView
android:id="@+id/cv_avatar"
android:layout_width="52dp"
android:layout_height="52dp"
android:layout_gravity="center"
android:scaleType="centerCrop"
android:src="@color/textColorPrimary"/> <RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"> <TextView
android:id="@+id/tv_mediaName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@+id/tv_followCount"
android:layout_toStartOf="@+id/tv_followCount"
android:maxLines="1"
android:textSize="16sp"
android:textStyle="bold"
tools:text="新华国际"/> <TextView
android:id="@+id/tv_followCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:text=""
tools:text="111人关注"/> <TextView
android:id="@+id/tv_descText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_mediaName"
android:layout_marginTop="4dp"
android:ellipsize="end"
android:maxLines="1"
android:textSize="14sp"
tools:text="中国军力超越日本 日本为什么不怕中国?普京一句话让国人顿悟"/>
</RelativeLayout> </LinearLayout> <View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_below="@+id/content"
android:background="@color/line_divider"/> </RelativeLayout>

  视图效果预览:

  

3.2.然后就是这个绑定类了==>MediaChannelViewBinder 

package com.jasonjan.headnews.binder.media;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView; import com.jakewharton.rxbinding2.view.RxView;
import com.jasonjan.headnews.R;
import com.jasonjan.headnews.bean.media.MediaChannelBean;
import com.jasonjan.headnews.interfaces.IOnItemLongClickListener;
import com.jasonjan.headnews.main.ErrorAction;
import com.jasonjan.headnews.util.ImageLoader;
import com.jasonjan.headnews.widget.CircleImageView; import java.util.concurrent.TimeUnit; import io.reactivex.functions.Consumer;
import me.drakeet.multitype.ItemViewBinder; /**
* Created by JasonJan on 2017/12/14.
*/ public class MediaChannelViewBinder extends ItemViewBinder<MediaChannelBean,MediaChannelViewBinder.ViewHolder> { private IOnItemLongClickListener listener; public MediaChannelViewBinder(IOnItemLongClickListener listener) {
this.listener = listener;
} @NonNull
@Override
protected MediaChannelViewBinder.ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
View view = inflater.inflate(R.layout.item_media_channel, parent, false);
return new ViewHolder(view, listener);
} @Override
protected void onBindViewHolder(@NonNull final ViewHolder holder, @NonNull final MediaChannelBean item){
try {
final Context context = holder.itemView.getContext();
String url = item.getAvatar();
ImageLoader.loadCenterCrop(context, url, holder.cv_avatar, R.color.viewBackground);
holder.tv_mediaName.setText(item.getName());
holder.tv_descText.setText(item.getDescText()); RxView.clicks(holder.itemView)
.throttleFirst(1, TimeUnit.SECONDS)
.subscribe(new Consumer<Object>() {
@Override
public void accept(@io.reactivex.annotations.NonNull Object o) throws Exception {
// MediaHomeActivity.launch(item.getId());
}
});
} catch (Exception e) {
ErrorAction.print(e);
}
} public class ViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener { private CircleImageView cv_avatar;
private TextView tv_mediaName;
private TextView tv_followCount;
private TextView tv_descText;
private IOnItemLongClickListener listener; public ViewHolder(View itemView, IOnItemLongClickListener listener) {
super(itemView);
this.cv_avatar = itemView.findViewById(R.id.cv_avatar);
this.tv_mediaName = itemView.findViewById(R.id.tv_mediaName);
this.tv_followCount = itemView.findViewById(R.id.tv_followCount);
this.tv_descText = itemView.findViewById(R.id.tv_descText);
this.listener = listener;
itemView.setOnLongClickListener(this);
} @Override
public boolean onLongClick(View v) {
if (listener != null) {
listener.onLongClick(v, getLayoutPosition());
return true;
}
return false;
}
}
}

  这里先理一理RxView.clicks思路。

  这个ViewHolder继承于RecyclerView.ViewHolder

  绑定类由于继承ItemViewBinder,不得不去实现onBindViewHolder<T,这里面的ViewHolder>

  所以在这里面处理ViewHolder的holdr.itemView的时候

  要用到RxView.clicks(view)

  如下方的代码:

RxView.clicks(holder.itemView)
.throttleFirst(1, TimeUnit.SECONDS)
.subscribe(new Consumer<Object>() {
@Override
public void accept(@io.reactivex.annotations.NonNull Object o) throws Exception {
MediaHomeActivity.launch(item.getId());
}
});

  RxView代表着用了第三方库,结合了RxJava。

  采用订阅的方式处理点击事件。

  当然也可以不用这种方式,不过我还没发现这种方式的好处。

  这里的ThrottleFirst操作符会定期发射这个时间段里源Observable发射的第一个数据。

  参考博客:RxJava操作符(三)

4.效果预览

4.1.目前完成的工作

  新闻的主页面三种大类型

  图片的一种大类型(也只用了一种)

  视频的一种大类型(采用了新闻主页面的其中一种)

  订阅号的主页面的一种大类型(也只采用了一种)

  然后还有一些点击事件,调转到相应的活动页面还未实现。

4.2.目前手机真实数据效果

  

最新文章

  1. Form Builder的三种查询方法构建
  2. 转:Linux内部的时钟处理机制全面剖析
  3. MATLAB与C#混合编程 之 double与MWArray 、MWNumericArray 转化
  4. Quartz.NET开源作业调度框架系列(四):Plugin Job
  5. bootstrap - typeahead自动补全插件
  6. 想在BD自然排名中脱颖而出吗?加张合适的图片吧!
  7. 使用C语言在Win控制台中输出带颜色的文字
  8. Oracle 相关概念详解
  9. UVALive6571 It Can Be Arranged(最小路径覆盖)
  10. js细节
  11. 关于DISPLAY变量显示问题
  12. CSDN上最火的android项目
  13. Selenium2Library+ride学习笔记
  14. python使用get在百度搜索并保存第一页搜索结果
  15. SQL 将查询结果插入到另一张表中
  16. STL的一些基本操作
  17. (转)linux下查看已安装的软件与卸载
  18. Java学习--数组与方法
  19. HTML5 之 FileReader 方法上传并读取文件
  20. 算法篇---Shell排序(希尔)算法

热门文章

  1. JSP中的Property &#39;name&#39; not found on type java.lang.String
  2. Lua相关函数整理
  3. Android - 通过真实案例学习解内存泄漏问题,最终发现Android原生Bug
  4. 【MATLAB】画信号频谱的子函数
  5. Azure降价辣么多,省下的预算该怎么花?
  6. April 7 2017 Week 14 Friday
  7. *5. Longest Palindromic Substring (dp) previous blogs are helpful
  8. 测试笔记:本地存储localstorage与sessionstorage
  9. 会话技术: Cookie Session JSP
  10. 剑指offer39 平衡二叉树