Android 资讯类App项目实战 第五章 视频模块

前言:

正在做一个资讯类app,打算一边做一边整理,供自己学习与巩固。用到的知识复杂度不高,仅适于新手。经验不多,如果写出来的代码有不好的地方欢迎讨论。

以往的内容

第一章 滑动顶部导航栏

第二章 retrofit获取网络数据

第三章 新闻模块

第四章 电影模块

第五章 视频模块

本章内容最终效果:

视频模块效果.gif

知识点:

MVP,RxJava,RecyclerView,JZVideoPlayerStandard

学习目标:

1、MVP模式的使用

2、使用RxJava处理复杂请求过程。

3、使用RecyclerView显示视频列表数据。

视频模块的视频播放方面主要用了第三方视频库JiaoZiVideoPlayer。除了网络视频播放,本章还运用RxJava解决复杂的网络请求(嵌套请求和循环请求)。

项目实战:

注意

本章用到的drawable资源、values资源皆存放在百度网盘

(请将values文件夹中的style.xml或color.xml更新一致后再运行,如有后续更新自行修改)

1.1 项目结构

Android 资讯类App项目实战 第五章 视频模块_第1张图片
image.png

需导入的库:
导入JiaoZiVideoPlayer。

compile 'cn.jzvd:jiaozivideoplayer:6.2.10'
Android 资讯类App项目实战 第五章 视频模块_第2张图片
image.png

用到的Api:
http://is.snssdk.com/api/news/feed/v51/?category=video
http://ib.365yg.com/video/urls/v/1/toutiao/mp4/v02004f00000bbpbk3l2v325q7lmkds0?r=6781281688452415&s=2734808831

1.2 属性类

本章分别用到3个属性类:TodayBean,TodayContentBean和VideoUrlBean。TodayBean是头条视频信息的数据,但因为返回的数据里最重要的content数据是个字符串,需要用我们将它解析成Json对象,所以诞生了TodayContentBean。VideoUrlBean则是我们获取视频地址需要用到的数据。

TodayBean的内容大家通过api:http://is.snssdk.com/api/news/feed/v51/?category=video返回数据,再复制用GsonFormat生成就好。
VideoUrlBean同理,用api:
http://ib.365yg.com/video/urls/v/1/toutiao/mp4/v02004f00000bbpbk3l2v325q7lmkds0?r=6781281688452415&s=2734808831

这里TodayContentBean的生成比较麻烦,我直接提供给大家content部分的json解析,大家复制后用GsonFormat生成:

{
"abstract":"视频讲述: 现在相亲都不问房子和车了, 都开始问这个问题, 结局亮了。","action_extra":"{\"channel_id\": 3431225546}","action_list":[{"action":1,"desc":"","extra":{}},{"action":3,"desc":"","extra":{}},{"action":7,"desc":"","extra":{}},{"action":9,"desc":"","extra":{}}],"aggr_type":1,"allow_download":false,"article_sub_type":0,"article_type":0,"article_url":"http://toutiao.com/group/6561954781336699400/","ban_comment":0,"ban_danmaku":false,"behot_time":1528701219,"bury_count":2250,"cell_flag":262155,"cell_layout_style":1,"cell_type":0,"comment_count":82,"content_decoration":"","cursor":1528701219999,"danmaku_count":0,"digg_count":1805,"display_url":"http://toutiao.com/group/6561954781336699400/","filter_words":[{"id":"8:0","is_selected":false,"name":"看过了"},{"id":"9:1","is_selected":false,"name":"内容太水"},{"id":"5:2074939231","is_selected":false,"name":"拉黑作者:小军生活圈"},{"id":"6:16087","is_selected":false,"name":"不想看:美女"}],"forward_info":{"forward_count":7},"group_flags":32832,"group_id":6561954781336699400,"has_m3u8_video":false,"has_mp4_video":0,"has_video":true,"hot":0,"ignore_web_transform":1,"interaction_data":"","is_subject":false,"item_id":6561954781336699400,"item_version":0,"keywords":"视频,美女","large_image_list":[{"height":326,"uri":"video1609/896f00091aee6992e724","url":"http://p1.pstatp.com/video1609/896f00091aee6992e724","url_list":[{"url":"http://p1.pstatp.com/video1609/896f00091aee6992e724"},{"url":"http://pb3.pstatp.com/video1609/896f00091aee6992e724"},{"url":"http://pb9.pstatp.com/video1609/896f00091aee6992e724"}],"width":580}],"level":0,"log_pb":{"impr_id":"20180611151339010008061137517240"},"media_info":{"avatar_url":"http://p9.pstatp.com/large/46f800012fe8ec43d9d9","follow":false,"is_star_user":false,"media_id":1584581706610701,"name":"小军生活圈","recommend_reason":"","recommend_type":0,"user_id":68698278295,"user_verified":true,"verified_content":""},"media_name":"小军生活圈","middle_image":{"height":360,"uri":"list/896f00091aee6992e724","url":"http://p1.pstatp.com/list/300x196/896f00091aee6992e724.webp","url_list":[{"url":"http://p1.pstatp.com/list/300x196/896f00091aee6992e724.webp"},{"url":"http://pb3.pstatp.com/list/300x196/896f00091aee6992e724.webp"},{"url":"http://pb9.pstatp.com/list/300x196/896f00091aee6992e724.webp"}],"width":640},"need_client_impr_recycle":1,"publish_time":1527904800,"read_count":566989,"repin_count":179,"rid":"20180611151339010008061137517240","share_count":6043,"share_info":{"cover_image":null,"description":null,"share_type":{"pyq":2,"qq":0,"qzone":0,"wx":0},"share_url":"http://m.toutiaoimg.cn/a6561954781336699400/?iid=0\u0026app=news_article","title":"美女相亲玩套路,看小伙如何整治美女?","token_type":1,"weixin_cover_image":{"height":1034,"uri":"large/pgc-image/15281038563343f512fdb88","url":"http://p3.pstatp.com/large/pgc-image/15281038563343f512fdb88","url_list":[{"url":"http://p3.pstatp.com/large/pgc-image/15281038563343f512fdb88"},{"url":"http://pb9.pstatp.com/large/pgc-image/15281038563343f512fdb88"},{"url":"http://pb1.pstatp.com/large/pgc-image/15281038563343f512fdb88"}],"width":1280}},"share_type":2,"share_url":"http://m.toutiaoimg.cn/a6561954781336699400/?iid=0\u0026app=news_article","show_dislike":true,"show_portrait":false,"show_portrait_article":false,"source":"小军生活圈","source_icon_style":1,"source_open_url":"sslocal://profile?refer=video\u0026uid=68698278295","tag":"video_movie","tag_id":6561954781336699400,"tip":0,"title":"美女相亲玩套路,看小伙如何整治美女?","ugc_recommend":{"activity":"","reason":"头条视频原创作者"},"url":"http://toutiao.com/group/6561954781336699400/","user_info":{"avatar_url":"http://p3.pstatp.com/thumb/46f800012fe8ec43d9d9","description":"每天推送原创搞笑视频,高端黑","follow":false,"follower_count":0,"name":"小军生活圈","user_auth_info":"{\"auth_type\": \"0\", \"other_auth\": {\"pgc\": \"头条视频原创作者\"}, \"auth_info\": \"头条视频原创作者\"}","user_id":68698278295,"user_verified":true,"verified_content":"头条视频原创作者"},"user_repin":0,"user_verified":1,"verified_content":"头条视频原创作者","video_detail_info":{"detail_video_large_image":{"height":326,"uri":"video1609/896f00091aee6992e724","url":"http://p1.pstatp.com/video1609/896f00091aee6992e724","url_list":[{"url":"http://p1.pstatp.com/video1609/896f00091aee6992e724"},{"url":"http://pb3.pstatp.com/video1609/896f00091aee6992e724"},{"url":"http://pb9.pstatp.com/video1609/896f00091aee6992e724"}],"width":580},"direct_play":1,"group_flags":32832,"show_pgc_subscribe":1,"video_id":"v02004c20000bc8bkmdqg5b4ln25l570","video_preloading_flag":1,"video_type":0,"video_watch_count":1499723,"video_watching_count":0},"video_duration":126,"video_id":"v02004c20000bc8bkmdqg5b4ln25l570","video_style":3
}

1.3 Retrofit

打开RetrofitService.java
增加两个需要用到的网络请求注解:

Android 资讯类App项目实战 第五章 视频模块_第3张图片
RetrofitService.java

然后到RetrofitHelper.java中写上Get方法

Android 资讯类App项目实战 第五章 视频模块_第4张图片
RetrofitHelper.java

到Api.java类中添加头条的host

Android 资讯类App项目实战 第五章 视频模块_第5张图片
Api.java

2.1 Model层

Model层的内容:


Model

状态监听接口IVideoLoadListener:

IVideoLoadListener

VideoModel的接口IVideoModel:

IVideoModel.java

发送请求的VideoModel类:

Android 资讯类App项目实战 第五章 视频模块_第6张图片
VideoModel.java

这里的视频播放列表地址的获取经历以下过程:
发送今日头条请求(getToday)获取到content数组 ==》 把content数组里的字符串用Gson转换为Json数据 ==》把json数据里的video_id取出来,做一系列加密和拼接操作得到获取视频播放地址的api ==》发送获取视频播放地址的网络请求(getVideoUrl) ==》取出单个videoUrlBean,把他们放进对象数组里。

如果用正常的网络获取的话,需要写一个嵌套请求,里面还得有一个循环。
用RxJava写的话,具体的操作就是各种flatMap的转换就行了。

2.2 View层

View层的内容只有一个IVideoView接口:

Android 资讯类App项目实战 第五章 视频模块_第7张图片
image.png

2.3 Presenter层

Presenter层的内容:


Presenter

IVideoPresenter接口:


IVideoPresenter

VideoPresenter:

public class VideoPresenter implements IVideoPresenter, IVideoLoadListener {

private IVideoModel iVideoModel;
private IVideoView iVideoView;

public VideoPresenter(IVideoView iVideoView) {
    this.iVideoView = iVideoView;
    this.iVideoModel = new VideoModel();
}

@Override
public void loadVideo() {
    iVideoView.showDialog();
    iVideoModel.loadVideo("video", this);
}

@Override
public void videoUrlSuccess(List mainUrlBeans, List contentBeans) {
    List videoList = new ArrayList<>();
    iVideoView.hideDialog();
    for (int i = 0; i < mainUrlBeans.size(); i++) {
        String mainUrl = mainUrlBeans.get(i).getData().getVideo_list().getVideo_1().getMain_url();
        final String url1 = (new String(Base64.decode(mainUrl.getBytes(), Base64.DEFAULT)));
        videoList.add(url1);
    }
    iVideoView.showVideo(contentBeans, videoList);
}

@Override
public void fail(Throwable throwable) {
    iVideoView.hideDialog();
    iVideoView.showErrorMsg(throwable);
}

public static String getVideoContentApi(String videoid) {
    String VIDEO_HOST = "http://ib.365yg.com";
    String VIDEO_URL = "/video/urls/v/1/toutiao/mp4/%s?r=%s";
    String r = getRandom();
    String s = String.format(VIDEO_URL, videoid, r);
    CRC32 crc32 = new CRC32();
    crc32.update(s.getBytes());
    String crcString = crc32.getValue() + "";
    String url = VIDEO_HOST + s + "&s=" + crcString;
    return url;
}

public static String getRandom() {
    Random random = new Random();
    StringBuilder result = new StringBuilder();
    for (int i = 0; i < 16; i++) {
        result.append(random.nextInt(10));
    }
    return result.toString();
}

public static TodayContentBean getTodayContentBean(String content) {
    Gson gson = new Gson();
    TodayContentBean bean = gson.fromJson(content, TodayContentBean.class);
    return bean;
}
}

3.1 item_video

由于我们的视频需要列表显示,所以还是得用到RecyclerView
而每一个item我们用的是基于MediaPlayer,IJKplayer,和ExoPlayer的第三方视频库JiaoZiVideoPlayer。

首先新建一个布局文件,命名为item_video






再到fg_video.xml文件中,把RecyclerView加上去:






    

    



3.2 ItemVideoAdapter

为我们刚刚写的item写一个适配器:

新建一个java文件,命名为ItemVideoAdapter

Android 资讯类App项目实战 第五章 视频模块_第8张图片
ItemVideoAdapter

3.3 Fragment

前面做了那么多,最终还是要在Fragment上设置才能让他们显示出来

FgVideoFragment.java
public class FgVideoFragment extends Fragment  implements IVideoView{

private IVideoPresenter iVideoPresenter;
private RecyclerView rv_video;
private ItemVideoAdapter itemVideoAdapter;
private SwipeRefreshLayout srl_video;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fg_video,container,false);
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    iVideoPresenter = new VideoPresenter(this);
    rv_video = view.findViewById(R.id.rv_video);
    srl_video = view.findViewById(R.id.srl_video);
    srl_video.setColorSchemeColors(Color.parseColor("#ffce3d3a"));
    iVideoPresenter.loadVideo();
    srl_video.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            iVideoPresenter.loadVideo();
        }
    });
    itemVideoAdapter = new ItemVideoAdapter(getActivity());
}

@Override
public void showVideo(List todayContentBeans, List videoList) {
    itemVideoAdapter.setData(todayContentBeans, videoList);
    rv_video.setLayoutManager(new LinearLayoutManager(getActivity(),
            LinearLayoutManager.VERTICAL, false));
    rv_video.setAdapter(itemVideoAdapter);
}

@Override
public void hideDialog() {
    srl_video.setRefreshing(false);
}

@Override
public void showDialog() {
    srl_video.setRefreshing(true);
}

@Override
public void showErrorMsg(Throwable throwable) {
    Toast.makeText(getContext(), "加载出错:"+throwable.getMessage(), Toast.LENGTH_SHORT).show();
}
}

最终效果:

视频模块效果2.gif

学习任务

根据提供的城市代码数组,通过以下Api,写一个RxJava的网络请求,把相应的城市情况Log出来。
数组:

Integer[] city={101280101,101280102,101280103,101280104,101280105, 101280201,101280202,101280203,101280204,101280205,101280206, 101280207,101280208,101280501};

api:

http://wthrcdn.etouch.cn/weather_mini?citykey=101010100

效果:


Android 资讯类App项目实战 第五章 视频模块_第9张图片
log

项目源码:https://github.com/Huigesi/IdleReaderDemo

上一章:
第四章 电影模块

你可能感兴趣的:(Android 资讯类App项目实战 第五章 视频模块)