zoukankan      html  css  js  c++  java
  • 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.
  • 相关阅读:
    正则表达式
    9.4、分布式进程
    Linux文件编辑工具——VIM
    14 Linux网络管理
    13.Linux系统服务
    12.Linux进程管理
    11.Linux磁盘管理——lvm,raid
    10.Linux磁盘管理
    09.Linux软件包管理——(YUM 、RPM)
    07.Linux 压缩打包
  • 原文地址:https://www.cnblogs.com/Jason-Jan/p/8033393.html
Copyright © 2011-2022 走看看