TouTiao开源项目 分析笔记11 以总体到局部的思路 构建图片主列表

1.构建图片主列表的整体片段PhotoTabLayout

1.1.首先创建一个PhotoTabLayout片段

public class PhotoTabLayout extends Fragment {

    private static final String TAG = "PhotoTabLayout";
    private static PhotoTabLayout instance = null;
    private static int pageSize = InitApp.AppContext.getResources().getStringArray(R.array.photo_id).length;
    private String categoryId[] = InitApp.AppContext.getResources().getStringArray(R.array.photo_id);
    private String categoryName[] = InitApp.AppContext.getResources().getStringArray(R.array.photo_name);
    private TabLayout tabLayout;
    private ViewPager viewPager;
    private List<Fragment> fragmentList = new ArrayList<>();
    private BasePagerAdapter adapter;

    public static PhotoTabLayout getInstance() {
        if (instance == null) {
            instance = new PhotoTabLayout();
        }
        return instance;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_photo_tab, container, false);
        initView(view);
        initData();
        return view;
    }

    @Override
    public void onResume() {
        super.onResume();
        tabLayout.setBackgroundColor(SettingUtil.getInstance().getColor());
    }

    private void initView(View view) {
        tabLayout = view.findViewById(R.id.tab_layout_photo);
        viewPager = view.findViewById(R.id.view_pager_photo);

        tabLayout.setupWithViewPager(viewPager);
        tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
        tabLayout.setBackgroundColor(SettingUtil.getInstance().getColor());
        viewPager.setOffscreenPageLimit(pageSize);
    }

    private void initData() {
        for (int i = 0; i < categoryId.length; i++) {
            Fragment fragment = PhotoArticleView.newInstance(categoryId[i]);
            fragmentList.add(fragment);
        }
        adapter = new BasePagerAdapter(getChildFragmentManager(), fragmentList, categoryName);
        viewPager.setAdapter(adapter);
    }

    public void onDoubleClick() {
        if (fragmentList != null && fragmentList.size() > 0) {
            int item = viewPager.getCurrentItem();
            ((BaseListFragment) fragmentList.get(item)).onRefresh();
        }
    }

    @Override
    public void onDestroy() {
        if (instance != null) {
            instance = null;
        }
        super.onDestroy();
    }
}

1.2.这个片段需要一个布局fragment_photo_tab.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">

    <android.support.design.widget.TabLayout
        android:id="@+id/tab_layout_photo"
        style="@style/TabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minHeight="?attr/actionBarSize"
        android:theme="@style/AppTheme.AppBarOverlay"
        app:tabTextColor="@color/gray">
    </android.support.design.widget.TabLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager_photo"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:layout="@layout/fragment_list">
    </android.support.v4.view.ViewPager>

</LinearLayout>

1.3.布局真实效果预览

  

1.4.然后就是tabLayout的静态文字

  在资源文件中values中的photo_category.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string-array name="photo_name">
        <item>全部</item>
        <item>老照片</item>
        <item>故事照片</item>
        <item>摄影集</item>
    </string-array>

    <string-array name="photo_id">
        <item>组图</item>
        <item>gallery_old_picture</item>
        <item>gallery_story</item>
        <item>gallery_photograthy</item>
    </string-array>
</resources>

1.5.然后就是将图片主列表的4个小type用一个BasePagerAdapter联系起来

  下面的代码在上方的PhotoTabLayout.java中的一个函数中,这里再拿出来讲一下。

private void initData() {
        for (int i = 0; i < categoryId.length; i++) {
            //这里用了PhotoArticleView,图片中所有fragment都是用这个类,所以要新建这个类了,下面再详细讲解这个类的构造过程
            Fragment fragment = PhotoArticleView.newInstance(categoryId[i]);
            fragmentList.add(fragment);
        }
         //这里就是将文字和片段统一的过程了,最重要的就是这个BasePagerAdapter将所有片段集合,设置到viewPager的适配器中
        adapter = new BasePagerAdapter(getChildFragmentManager(), fragmentList, categoryName);
        viewPager.setAdapter(adapter);
    }    

1.6.看一下这个片段的适配器吧

  名字叫做BasePagerAdapter

public class BasePagerAdapter extends FragmentStatePagerAdapter {

    private List<Fragment> fragmentList;
    private List<String> titleList;

    public BasePagerAdapter(FragmentManager fm, List<Fragment> fragmentList, String[] titles) {
        super(fm);
        this.fragmentList = fragmentList;
        this.titleList = new ArrayList<>(Arrays.asList(titles));
    }

    public BasePagerAdapter(FragmentManager fm, List<Fragment> fragmentList, List<String> titleList) {
        super(fm);
        this.fragmentList = fragmentList;
        this.titleList = titleList;
    }

    @Override
    public Fragment getItem(int position) {
        return fragmentList.get(position);
    }

    @Override
    public int getCount() {
        return titleList.size();
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return titleList.get(position);
    }

    @Override
    public int getItemPosition(Object object) {
        return PagerAdapter.POSITION_NONE;
    }

    public void recreateItems(List<Fragment> fragmentList, List<String> titleList) {
        this.fragmentList = fragmentList;
        this.titleList = titleList;
        notifyDataSetChanged();
    }
}

1.7.第一阶段结束,主要完成了PhotoTabLayout这个图片主页面的布局和相应的逻辑。

  第二阶段主要处理4个分片段的布局和逻辑了。 


2.图片系列的文章的基础Bean类

2.1.第一集团数据返回==>调用API返回的数据

 /**
     * has_more : true
     * message : success
     * next : {"max_behot_time":1494154227}
     * data:[[.....]]
     */

2.2.第二集团数据返回==>上面的data返回的数据

//data返回的数据 

/**
         * image_url : http://p9.pstatp.com/list/640x360/1b820001767b34813c82
         * media_avatar_url : http://p1.pstatp.com/large/d2a0011291a5cfef5c3
         * article_genre : gallery
         * is_diversion_page : false
         * title : 我拍少女签约模特王纯粹少女视觉
         * middle_mode : false
         * gallary_image_count : 41
         * image_list : [{"url":"http://p3.pstatp.com/list/640x360/1b820001767b34813c82","width":620,"url_list":[{"url":"http://p9.pstatp.com/list/640x360/1b820001767b34813c82"},{"url":"http://pb1.pstatp.com/list/640x360/1b820001767b34813c82"},{"url":"http://pb3.pstatp.com/list/640x360/1b820001767b34813c82"}],"uri":"list/640x360/1b820001767b34813c82","height":855},{"url":"http://p3.pstatp.com/list/640x360/1b8700015c172e7de742","width":1280,"url_list":[{"url":"http://p3.pstatp.com/list/1b8700015c172e7de742"},{"url":"http://pb9.pstatp.com/list/1b8700015c172e7de742"},{"url":"http://pb1.pstatp.com/list/1b8700015c172e7de742"}],"uri":"list/1b8700015c172e7de742","height":720},{"url":"http://p9.pstatp.com/list/640x360/1b8500015b6a1c897705","width":1656,"url_list":[{"url":"http://p9.pstatp.com/list/1b8500015b6a1c897705"},{"url":"http://pb1.pstatp.com/list/1b8500015b6a1c897705"},{"url":"http://pb3.pstatp.com/list/1b8500015b6a1c897705"}],"uri":"list/1b8500015b6a1c897705","height":2415}]
         * more_mode : true
         * behot_time : 1494158550
         * source_url : /group/6408674663173767426/
         * source : 我拍少女
         * hot : 1
         * is_feed_ad : false
         * has_gallery : true
         * single_mode : false
         * comments_count : 1
         * group_id : 6408674663173767426
         * media_url : http://toutiao.com/m4439122761/
         * honey : true
         */

2.3.整个PhotoArticleBean类

public class PhotoArticleBean {

    /**
     * has_more : true
     * message : success
     * next : {"max_behot_time":1494154227}
     */

    private boolean has_more;
    private String message;
    private NextBean next;
    private List<DataBean> data;

    public boolean isHas_more() {
        return has_more;
    }

    public void setHas_more(boolean has_more) {
        this.has_more = has_more;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public NextBean getNext() {
        return next;
    }

    public void setNext(NextBean next) {
        this.next = next;
    }

    public List<DataBean> getData() {
        return data;
    }

    public void setData(List<DataBean> data) {
        this.data = data;
    }

    public static class NextBean{
        private int max_behot_time;
        public int getMax_behot_time(){
            return max_behot_time;
        }
        public void setMax_behot_time(int max_behot_tim){
            this.max_behot_time=max_behot_time;
        }
    }

    public static class DataBean implements Parcelable {
        public static final Creator<DataBean> CREATOR = new Creator<DataBean>() {
            @Override
            public DataBean createFromParcel(Parcel in) {
                return new DataBean(in);
            }

            @Override
            public DataBean[] newArray(int size) {
                return new DataBean[size];
            }
        };
        /**
         * image_url : http://p9.pstatp.com/list/640x360/1b820001767b34813c82
         * media_avatar_url : http://p1.pstatp.com/large/d2a0011291a5cfef5c3
         * article_genre : gallery
         * is_diversion_page : false
         * title : 我拍少女签约模特王纯粹少女视觉
         * middle_mode : false
         * gallary_image_count : 41
         * image_list : [{"url":"http://p3.pstatp.com/list/640x360/1b820001767b34813c82","width":620,"url_list":[{"url":"http://p9.pstatp.com/list/640x360/1b820001767b34813c82"},{"url":"http://pb1.pstatp.com/list/640x360/1b820001767b34813c82"},{"url":"http://pb3.pstatp.com/list/640x360/1b820001767b34813c82"}],"uri":"list/640x360/1b820001767b34813c82","height":855},{"url":"http://p3.pstatp.com/list/640x360/1b8700015c172e7de742","width":1280,"url_list":[{"url":"http://p3.pstatp.com/list/1b8700015c172e7de742"},{"url":"http://pb9.pstatp.com/list/1b8700015c172e7de742"},{"url":"http://pb1.pstatp.com/list/1b8700015c172e7de742"}],"uri":"list/1b8700015c172e7de742","height":720},{"url":"http://p9.pstatp.com/list/640x360/1b8500015b6a1c897705","width":1656,"url_list":[{"url":"http://p9.pstatp.com/list/1b8500015b6a1c897705"},{"url":"http://pb1.pstatp.com/list/1b8500015b6a1c897705"},{"url":"http://pb3.pstatp.com/list/1b8500015b6a1c897705"}],"uri":"list/1b8500015b6a1c897705","height":2415}]
         * more_mode : true
         * behot_time : 1494158550
         * source_url : /group/6408674663173767426/
         * source : 我拍少女
         * hot : 1
         * is_feed_ad : false
         * has_gallery : true
         * single_mode : false
         * comments_count : 1
         * group_id : 6408674663173767426
         * media_url : http://toutiao.com/m4439122761/
         * honey : true
         */

        private String image_url;
        private String media_avatar_url;
        private String article_genre;
        private boolean is_diversion_page;
        private String title;
        private boolean middle_mode;
        private int gallary_image_count;
        private boolean more_mode;
        private int behot_time;
        private String source_url;
        private String source;
        private int hot;
        private boolean is_feed_ad;
        private boolean has_gallery;
        private boolean single_mode;
        private int comments_count;
        private String group_id;
        private String media_url;
        private boolean honey;
        private List<ImageListBean> image_list;

        protected DataBean(Parcel in) {
            image_url = in.readString();
            media_avatar_url = in.readString();
            article_genre = in.readString();
            is_diversion_page = in.readByte() != 0;
            title = in.readString();
            middle_mode = in.readByte() != 0;
            gallary_image_count = in.readInt();
            more_mode = in.readByte() != 0;
            behot_time = in.readInt();
            source_url = in.readString();
            source = in.readString();
            hot = in.readInt();
            is_feed_ad = in.readByte() != 0;
            has_gallery = in.readByte() != 0;
            single_mode = in.readByte() != 0;
            comments_count = in.readInt();
            group_id = in.readString();
            media_url = in.readString();
            honey = in.readByte() != 0;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(image_url);
            dest.writeString(media_avatar_url);
            dest.writeString(article_genre);
            dest.writeByte((byte) (is_diversion_page ? 1 : 0));
            dest.writeString(title);
            dest.writeByte((byte) (middle_mode ? 1 : 0));
            dest.writeInt(gallary_image_count);
            dest.writeByte((byte) (more_mode ? 1 : 0));
            dest.writeInt(behot_time);
            dest.writeString(source_url);
            dest.writeString(source);
            dest.writeInt(hot);
            dest.writeByte((byte) (is_feed_ad ? 1 : 0));
            dest.writeByte((byte) (has_gallery ? 1 : 0));
            dest.writeByte((byte) (single_mode ? 1 : 0));
            dest.writeInt(comments_count);
            dest.writeString(group_id);
            dest.writeString(media_url);
            dest.writeByte((byte) (honey ? 1 : 0));
        }

        @Override
        public int describeContents() {
            return 0;
        }

        public String getImage_url() {
            return image_url;
        }

        public void setImage_url(String image_url) {
            this.image_url = image_url;
        }

        public String getMedia_avatar_url() {
            return media_avatar_url;
        }

        public void setMedia_avatar_url(String media_avatar_url) {
            this.media_avatar_url = media_avatar_url;
        }

        public String getArticle_genre() {
            return article_genre;
        }

        public void setArticle_genre(String article_genre) {
            this.article_genre = article_genre;
        }

        public boolean isIs_diversion_page() {
            return is_diversion_page;
        }

        public void setIs_diversion_page(boolean is_diversion_page) {
            this.is_diversion_page = is_diversion_page;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public boolean isMiddle_mode() {
            return middle_mode;
        }

        public void setMiddle_mode(boolean middle_mode) {
            this.middle_mode = middle_mode;
        }

        public int getGallary_image_count() {
            return gallary_image_count;
        }

        public void setGallary_image_count(int gallary_image_count) {
            this.gallary_image_count = gallary_image_count;
        }

        public boolean isMore_mode() {
            return more_mode;
        }

        public void setMore_mode(boolean more_mode) {
            this.more_mode = more_mode;
        }

        public int getBehot_time() {
            return behot_time;
        }

        public void setBehot_time(int behot_time) {
            this.behot_time = behot_time;
        }

        public String getSource_url() {
            return source_url;
        }

        public void setSource_url(String source_url) {
            this.source_url = source_url;
        }

        public String getSource() {
            return source;
        }

        public void setSource(String source) {
            this.source = source;
        }

        public int getHot() {
            return hot;
        }

        public void setHot(int hot) {
            this.hot = hot;
        }

        public boolean isIs_feed_ad() {
            return is_feed_ad;
        }

        public void setIs_feed_ad(boolean is_feed_ad) {
            this.is_feed_ad = is_feed_ad;
        }

        public boolean isHas_gallery() {
            return has_gallery;
        }

        public void setHas_gallery(boolean has_gallery) {
            this.has_gallery = has_gallery;
        }

        public boolean isSingle_mode() {
            return single_mode;
        }

        public void setSingle_mode(boolean single_mode) {
            this.single_mode = single_mode;
        }

        public int getComments_count() {
            return comments_count;
        }

        public void setComments_count(int comments_count) {
            this.comments_count = comments_count;
        }

        public String getGroup_id() {
            return group_id;
        }

        public void setGroup_id(String group_id) {
            this.group_id = group_id;
        }

        public String getMedia_url() {
            return media_url;
        }

        public void setMedia_url(String media_url) {
            this.media_url = media_url;
        }

        public boolean isHoney() {
            return honey;
        }

        public void setHoney(boolean honey) {
            this.honey = honey;
        }

        public List<ImageListBean> getImage_list() {
            return image_list;
        }

        public void setImage_list(List<ImageListBean> image_list) {
            this.image_list = image_list;
        }

        public static class ImageListBean {
            /**
             * url : http://p3.pstatp.com/list/640x360/1b820001767b34813c82
             * width : 620
             * url_list : [{"url":"http://p9.pstatp.com/list/640x360/1b820001767b34813c82"},{"url":"http://pb1.pstatp.com/list/640x360/1b820001767b34813c82"},{"url":"http://pb3.pstatp.com/list/640x360/1b820001767b34813c82"}]
             * uri : list/640x360/1b820001767b34813c82
             * height : 855
             */

            private String url;
            private int width;
            private String uri;
            private int height;
            private List<UrlListBean> url_list;

            public String getUrl() {
                return url;
            }

            public void setUrl(String url) {
                this.url = url;
            }

            public int getWidth() {
                return width;
            }

            public void setWidth(int width) {
                this.width = width;
            }

            public String getUri() {
                return uri;
            }

            public void setUri(String uri) {
                this.uri = uri;
            }

            public int getHeight() {
                return height;
            }

            public void setHeight(int height) {
                this.height = height;
            }

            public List<UrlListBean> getUrl_list() {
                return url_list;
            }

            public void setUrl_list(List<UrlListBean> url_list) {
                this.url_list = url_list;
            }

            public static class UrlListBean {
                /**
                 * url : http://p9.pstatp.com/list/640x360/1b820001767b34813c82
                 */

                private String url;

                public String getUrl() {
                    return url;
                }

                public void setUrl(String url) {
                    this.url = url;
                }
            }
        }
    }
}
View Code


3.图片系列的视图以及处理器控制

3.1.最底层视图以及处理器接口 

interface IPhotoArticle {

    interface View extends IBaseListView<Presenter> {

        /**
         * 请求数据
         */
        void onLoadData();
    }

    interface Presenter extends IBasePresenter {

        /**
         * 请求数据
         */
        void doLoadData(String... category);

        /**
         * 再起请求数据
         */
        void doLoadMoreData();

        /**
         * 设置适配器
         */
        void doSetAdapter(List<PhotoArticleBean.DataBean> dataBeen);

        void doShowNoMore();
    }
}

3.2.图片系列的视图

package com.jasonjan.headnews.module.photo;

import android.os.Bundle;
import android.view.View;

import com.jasonjan.headnews.adapter.DiffCallback;
import com.jasonjan.headnews.bean.common.LoadingBean;
import com.jasonjan.headnews.main.Register;
import com.jasonjan.headnews.module.base.BaseListFragment;
import com.jasonjan.headnews.util.OnLoadMoreListener;

import java.util.List;

import me.drakeet.multitype.Items;
import me.drakeet.multitype.MultiTypeAdapter;

/**
 * Created by JasonJan on 2017/12/13.
 */

public class PhotoArticleView extends BaseListFragment<IPhotoArticle.Presenter> implements IPhotoArticle.View {
    private static final String TAG = "PhotoArticleView";
    private String categoryId;
    
    public static PhotoArticleView newInstance(String categoryId){
        Bundle bundle=new Bundle();
        bundle.putString(TAG,categoryId);
        PhotoArticleView instance=new PhotoArticleView();
        instance.setArguments(bundle);
        return instance;
    }
    
    @Override
    protected void initData(){
        categoryId=getArguments().getString(TAG);
    }

    @Override
    protected void initView(View view) {
        super.initView(view);
        adapter = new MultiTypeAdapter(oldItems);
        Register.registerPhotoArticleItem(adapter);
        recyclerView.setAdapter(adapter);
        recyclerView.addOnScrollListener(new OnLoadMoreListener() {
            @Override
            public void onLoadMore() {
                if (canLoadMore) {
                    canLoadMore = false;
                    presenter.doLoadMoreData();
                }
            }
        });
    }

    @Override
    public void onLoadData() {
        onShowLoading();
        presenter.doLoadData(categoryId);
    }

    @Override
    public void onSetAdapter(final List<?> list) {
        Items newItems = new Items(list);
        newItems.add(new LoadingBean());
        DiffCallback.notifyDataSetChanged(oldItems, newItems, DiffCallback.PHOTO, adapter);
        oldItems.clear();
        oldItems.addAll(newItems);
        canLoadMore = true;
    }

    @Override
    public void setPresenter(IPhotoArticle.Presenter presenter) {
        if (null == presenter) {
            this.presenter = new PhotoArticlePresenter(this);
        }
    }

}

  然后发现处理器还没有设置呢。

  然后还有视图绑定也未实现(在自定义的Register中实现)

  然后还有处理新老数据来刷新(在自定义的Diffback中实现)

3.3.图片系列的处理器

package com.jasonjan.headnews.module.photo;

import com.jasonjan.headnews.bean.photo.PhotoArticleBean;
import com.jasonjan.headnews.main.ErrorAction;
import com.jasonjan.headnews.main.RetrofitFactory;
import com.jasonjan.headnews.util.TimeUtil;

import java.util.ArrayList;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;
import io.reactivex.schedulers.Schedulers;

/**
 * Created by JasonJan on 2017/12/13.
 */

public class PhotoArticlePresenter implements IPhotoArticle.Presenter {

    private static final String TAG="PhotoArticlePresenter";
    private IPhotoArticle.View view;
    private List<PhotoArticleBean.DataBean> dataList=new ArrayList<>();
    private String category;
    private String time;

    PhotoArticlePresenter(IPhotoArticle.View view) {
        this.view = view;
        this.time = TimeUtil.getCurrentTimeStamp();
    }

    @Override
    public void doLoadData(String... category){
        try {
            if (null == this.category) {
                this.category = category[0];
            }
        } catch (Exception e) {
            ErrorAction.print(e);
        }

        // 释放内存
        if (dataList.size() > 100) {
            dataList.clear();
        }

        RetrofitFactory.getRetrofit().create(IPhotoApi.class).getPhotoArticle(this.category, time)
                .subscribeOn(Schedulers.io())
                .switchMap(new Function<PhotoArticleBean, Observable<PhotoArticleBean.DataBean>>() {
                    @Override
                    public Observable<PhotoArticleBean.DataBean> apply(@NonNull PhotoArticleBean photoArticleBean) throws Exception {
                        List<PhotoArticleBean.DataBean> data = photoArticleBean.getData();
                        // 移除最后一项 数据有重复
                        if (data.size() > 0)
                            data.remove(data.size() - 1);
                        //time = photoArticleBean.getNext().getMax_behot_time()+"";
                        return Observable.fromIterable(data);
                    }
                })
                .filter(new Predicate<PhotoArticleBean.DataBean>() {
                    @Override
                    public boolean test(@NonNull PhotoArticleBean.DataBean dataBean) throws Exception {
                        // 去除重复新闻
                        for (PhotoArticleBean.DataBean bean : dataList) {
                            if (dataBean.getTitle().equals(bean.getTitle())) {
                                return false;
                            }
                        }
                        return true;
                    }
                })
                .toList()
                .compose(view.<List<PhotoArticleBean.DataBean>>bindToLife())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<List<PhotoArticleBean.DataBean>>() {
                    @Override
                    public void accept(@NonNull List<PhotoArticleBean.DataBean> list) throws Exception {
                        if (null != list && list.size() > 0) {
                            doSetAdapter(list);
                        } else {
                            doShowNoMore();
                        }
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(@NonNull Throwable throwable) throws Exception {
                        doShowNetError();
                        ErrorAction.print(throwable);
                    }
                });
    }

    @Override
    public void doLoadMoreData(){
        doLoadData();
    }

    @Override
    public void doSetAdapter(List<PhotoArticleBean.DataBean> dataBean){
        dataList.addAll(dataBean);
        view.onSetAdapter(dataList);
        view.onHideLoading();
    }

    @Override
    public void doRefresh() {
        if (dataList.size() != 0) {
            dataList.clear();
            time = TimeUtil.getCurrentTimeStamp()+"";
        }
        view.onShowLoading();
        doLoadData();
    }

    @Override
    public void doShowNetError() {
        view.onHideLoading();
        view.onShowNetError();
    }

    @Override
    public void doShowNoMore() {
        view.onHideLoading();
        view.onShowNoMore();
    }
}

3.4.图片系列文章的API接口请求

public interface IPhotoApi {

    /**
     * 获取图片标题等信息
     * http://www.toutiao.com/api/article/feed/?category=类型&as=A115C8457F69B85&cp=585F294B8845EE1&_=时间&count=30
     */
    @GET("http://www.toutiao.com/api/pc/feed/?as=A1C598BB87BE7DA&cp=58B72ED7AD3A0E1")
    Observable<PhotoArticleBean> getPhotoArticle(
            @Query("category") String category,
            @Query("max_behot_time") String maxBehotTime);

    /**
     * 获取图片内容HTML内容
     * 抓取 url 较复杂
     * 详情查看 {@linkplain com.meiji.toutiao.module.photo.content.PhotoContentPresenter#doLoadData(String...)}
     */
    @GET()
    @Headers("User-Agent:" + Constant.USER_AGENT_PC)
    Call<ResponseBody> getPhotoContentHTML(@Url String url);
}

3.5.然后是Register类中声明3中Binder

public static void registerPhotoArticleItem(@NonNull MultiTypeAdapter adapter) {
        adapter.register(PhotoArticleBean.DataBean.class, new PhotoArticleViewBinder());
        adapter.register(LoadingBean.class, new LoadingViewBinder());
        adapter.register(LoadingEndBean.class, new LoadingEndViewBinder());
    }

3.6.然后在DiffCallback中加这个类型吧

  在areItemsTheSame函数中添加Photo类型。

case PHOTO:
                    return ((PhotoArticleBean.DataBean) oldList.get(oldItemPosition)).getTitle().equals(
                            ((PhotoArticleBean.DataBean) newList.get(newItemPosition)).getTitle());

  在areContentsTheSame中添加Photo类型

 case PHOTO:
                    return ((PhotoArticleBean.DataBean) oldList.get(oldItemPosition)).getSource_url().equals(
                            ((PhotoArticleBean.DataBean) newList.get(newItemPosition)).getSource_url());
        


4.视图绑定类PhotoArticleViewBinder

4.1.视图绑定类的布局定义 

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    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="wrap_content"
    android:layout_marginBottom="4dp"
    android:layout_marginTop="4dp"
    android:background="@color/viewBackground"
    app:cardElevation="1dp">

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="?attr/selectableItemBackground"
        android:foreground="?attr/selectableItemBackground"
        android:padding="16dp">

        <LinearLayout
            android:id="@+id/header"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_vertical"
            android:orientation="horizontal">

            <com.meiji.toutiao.widget.CircleImageView
                android:id="@+id/iv_media"
                android:layout_width="22dp"
                android:layout_height="22dp"
                android:scaleType="centerCrop"/>

            <TextView
                android:id="@+id/tv_extra"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="8dp"
                android:layout_marginStart="8dp"
                android:ellipsize="end"
                android:maxLength="30"
                android:maxLines="1"
                android:textAppearance="@style/TextAppearance.AppCompat.Caption"
                tools:text="新闻源 - 1小时前"/>

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <ImageView
                    android:id="@+id/iv_dots"
                    android:layout_width="22dp"
                    android:layout_height="22dp"
                    android:layout_alignParentEnd="true"
                    android:layout_alignParentRight="true"
                    android:layout_centerVertical="true"
                    android:padding="4dp"
                    android:scaleType="center"
                    app:srcCompat="@drawable/ic_dots_horizontal_grey500_24dp"
                    tools:ignore="ContentDescription"/>
            </RelativeLayout>

        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/header"
            android:layout_marginTop="4dp"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tv_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:maxLines="1"
                android:textStyle="bold"
                tools:text="看完王健林的私人飞机,再看刘强东的,刚好相差1个小目标的钱"/>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="82dp"
                android:layout_marginTop="4dp"
                android:orientation="horizontal">

                <ImageView
                    android:id="@+id/iv_0"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_marginEnd="4dp"
                    android:layout_marginRight="4dp"
                    android:layout_weight="1"
                    android:src="@color/viewBackground"
                    tools:ignore="ContentDescription"/>

                <ImageView
                    android:id="@+id/iv_1"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_marginEnd="4dp"
                    android:layout_marginRight="4dp"
                    android:layout_weight="1"
                    android:src="@color/viewBackground"
                    tools:ignore="ContentDescription"/>

                <ImageView
                    android:id="@+id/iv_2"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:src="@color/viewBackground"
                    tools:ignore="ContentDescription"/>


            </LinearLayout>
        </LinearLayout>
    </RelativeLayout>
</android.support.v7.widget.CardView>

4.2.视图效果

  

4.3.视图绑定类

public class PhotoArticleViewBinder extends ItemViewBinder<PhotoArticleBean.DataBean, PhotoArticleViewBinder.ViewHolder> {

    @NonNull
    @Override
    protected PhotoArticleViewBinder.ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
        View view = inflater.inflate(R.layout.item_photo_article, parent, false);
        return new ViewHolder(view);
    }

    @Override
    protected void onBindViewHolder(@NonNull final ViewHolder holder, @NonNull final PhotoArticleBean.DataBean item) {

        final Context context = holder.itemView.getContext();

        try {
            String tv_title = item.getTitle();
            if (!TextUtils.isEmpty(item.getMedia_avatar_url())) {
                ImageLoader.loadCenterCrop(context, item.getMedia_avatar_url().replaceFirst("//","http://").trim(), holder.iv_media, R.color.viewBackground,R.mipmap.error_image);
            }

            if (item.getImage_list() != null) {
                int size = item.getImage_list().size();
                String[] ivs = new String[size];
                for (int i = 0; i < item.getImage_list().size(); i++) {
                    ivs[i] = item.getImage_list().get(i).getUrl().replaceFirst("//","http://").trim();
                }
                switch (ivs.length) {
                    case 1:
                        ImageLoader.loadCenterCrop(context, ivs[0], holder.iv_0, R.color.viewBackground,R.mipmap.error_image);
                        break;
                    case 2:
                        ImageLoader.loadCenterCrop(context, ivs[0], holder.iv_0, R.color.viewBackground,R.mipmap.error_image);
                        ImageLoader.loadCenterCrop(context, ivs[1], holder.iv_1, R.color.viewBackground,R.mipmap.error_image);
                        break;
                    case 3:
                        ImageLoader.loadCenterCrop(context, ivs[0], holder.iv_0, R.color.viewBackground,R.mipmap.error_image);
                        ImageLoader.loadCenterCrop(context, ivs[1], holder.iv_1, R.color.viewBackground,R.mipmap.error_image);
                        ImageLoader.loadCenterCrop(context, ivs[2], holder.iv_2, R.color.viewBackground,R.mipmap.error_image);
                        break;
                }
                Log.i("图片绑定类:","
头像地址="+item.getMedia_avatar_url().replaceFirst("//","")+"
图片链接="+ivs[0]+"
"+ivs[1]+"
"+ivs[2]);

            }

            String tv_source = item.getSource();
            String tv_datetime = item.getBehot_time() + "";
            String comments_count = item.getComments_count() + "评论";
            if (!TextUtils.isEmpty(tv_datetime)) {
                tv_datetime = TimeUtil.getTimeStampAgo(tv_datetime);
            }
            holder.tv_title.setText(tv_title);
            holder.tv_title.setTextSize(SettingUtil.getInstance().getTextSize());
            holder.tv_extra.setText(tv_source + " - " + comments_count + " - " + tv_datetime);
            holder.iv_dots.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    PopupMenu popupMenu = new PopupMenu(context,
                            holder.iv_dots, Gravity.END, 0, R.style.MyPopupMenu);
                    popupMenu.inflate(R.menu.menu_share);
                    popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                        @Override
                        public boolean onMenuItemClick(MenuItem menu) {
                            int itemId = menu.getItemId();
                            if (itemId == R.id.action_share) {
                                String shareUrl = item.getSource_url();
                                if (!shareUrl.contains("toutiao")) {
                                    shareUrl = "http://toutiao.com" + shareUrl;
                                }
                                IntentAction.send(context, item.getTitle() + "
" + shareUrl);
                            }
                            return false;
                        }
                    });
                    popupMenu.show();
                }
            });

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

    public class ViewHolder extends RecyclerView.ViewHolder {

        private CircleImageView iv_media;
        private TextView tv_extra;
        private TextView tv_title;
        private ImageView iv_0;
        private ImageView iv_1;
        private ImageView iv_2;
        private ImageView iv_dots;

        public ViewHolder(View itemView) {
            super(itemView);
            this.iv_media = itemView.findViewById(R.id.iv_media);
            this.tv_extra = itemView.findViewById(R.id.tv_extra);
            this.tv_title = itemView.findViewById(R.id.tv_title);
            this.iv_0 = itemView.findViewById(R.id.iv_0);
            this.iv_1 = itemView.findViewById(R.id.iv_1);
            this.iv_2 = itemView.findViewById(R.id.iv_2);
            this.iv_dots = itemView.findViewById(R.id.iv_dots);
        }
    }
}


5.目前效果预览

5.1.目前完成的工作

  新闻的三种大类型

  图片的一种大类型,这种大类型有4个分类,为全部、老照片、故事照片和摄影集。

  但是每种类型的评论以及详细页面还未实现。

  因为图片调用今日头条的API不稳定,有时候可以获得数据,有时候无法获得。

  所以这里是无法确保每次刷新都有新的数据。

5.2.手机真实数据预览

   



既然选择了,便不顾风雨兼程。Just follow yourself.
原文地址:https://www.cnblogs.com/Jason-Jan/p/8033393.html