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

前言: 正在做一个资讯类app,打算一边做一边整理,供自己学习与巩固。用到的知识复杂度不高,仅适于新手。经验不多,如果写出来的代码有不好的地方欢迎讨论。
以往的内容 【Android|Android 资讯类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|Android 资讯类App项目实战 第五章 视频模块
文章图片
image.png 需导入的库:
导入JiaoZiVideoPlayer。

compile 'cn.jzvd:jiaozivideoplayer:6.2.10'

Android|Android 资讯类App项目实战 第五章 视频模块
文章图片
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|Android 资讯类App项目实战 第五章 视频模块
文章图片
RetrofitService.java 然后到RetrofitHelper.java中写上Get方法
Android|Android 资讯类App项目实战 第五章 视频模块
文章图片
RetrofitHelper.java 到Api.java类中添加头条的host
Android|Android 资讯类App项目实战 第五章 视频模块
文章图片
Api.java 2.1 Model层
Model层的内容:

Android|Android 资讯类App项目实战 第五章 视频模块
文章图片
Model 状态监听接口IVideoLoadListener:
Android|Android 资讯类App项目实战 第五章 视频模块
文章图片
IVideoLoadListener VideoModel的接口IVideoModel:
Android|Android 资讯类App项目实战 第五章 视频模块
文章图片
IVideoModel.java 发送请求的VideoModel类:
Android|Android 资讯类App项目实战 第五章 视频模块
文章图片
VideoModel.java 这里的视频播放列表地址的获取经历以下过程:
发送今日头条请求(getToday)获取到content数组 ==》 把content数组里的字符串用Gson转换为Json数据 ==》把json数据里的video_id取出来,做一系列加密和拼接操作得到获取视频播放地址的api ==》发送获取视频播放地址的网络请求(getVideoUrl) ==》取出单个videoUrlBean,把他们放进对象数组里。
如果用正常的网络获取的话,需要写一个嵌套请求,里面还得有一个循环。
用RxJava写的话,具体的操作就是各种flatMap的转换就行了。
2.2 View层
View层的内容只有一个IVideoView接口:
Android|Android 资讯类App项目实战 第五章 视频模块
文章图片
image.png 2.3 Presenter层
Presenter层的内容:

Android|Android 资讯类App项目实战 第五章 视频模块
文章图片
Presenter IVideoPresenter接口:

Android|Android 资讯类App项目实战 第五章 视频模块
文章图片
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|Android 资讯类App项目实战 第五章 视频模块
文章图片
ItemVideoAdapter 3.3 Fragment
前面做了那么多,最终还是要在Fragment上设置才能让他们显示出来
FgVideoFragment.java
public class FgVideoFragment extends Fragmentimplements 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|Android 资讯类App项目实战 第五章 视频模块
文章图片
log 项目源码:https://github.com/Huigesi/IdleReaderDemo
上一章:
第四章 电影模块

    推荐阅读