前言:成印昨天发布了他最近闭关10天,开发的一个直播开源项目,我体验了下,觉得还不错,推荐给大家,点击文末【阅读原文】,可访问项目的github地址,觉得不错,也不忘给他star下,毕竟开源不易。下面是他的来稿。ps:(最近我正在参加CSDN 2016年度博客之星评选, 11月28日到12月18日每天都可以为我投一票 ,投票地址前篇文章中【阅读原文】就有,我朋友圈也有相关分享,也可直接链接:http://blog.csdn.net/vote/candidate.html?username=hejjunlin。)

直播一直是个很火的趋势,特别是在今年以来让不少平凡的草根百姓也和狠狠“火”了一把,什么某游戏主播年薪一千五百万,某女主播直播吃饼干,吃饭,月入十万,等等。。但这些跟我们没有半点关系。但都没有关系,代码还能愉快的敲下去,砖还得搬,搬还得钻。也是抱着学习的态度和对技术的热诚,动动手写下这项目,然后分享给大家。先看下今天的Agenda:

  1. 树形结构的架构思路

  2. 模块化的开放方法

  3. 总结

1.树形结构的架构思路

很多有经验的开发人员,在一定的项目洗礼之后,逐渐形成一套可行的敏捷开发的方案,就是俗话中的套路。本人也有一套路,命称树形套路。在这里阐述的所谓树形,是从项目出发,以数据走向到每个功能点、页面的发散型项目观,在树形中的每个节点,可以按照个人的特点以为一个Activity、Fragment等作为一个节点,Intent、FragmentAdapter作为连接节点之间的纽带。 再细化,将Activity、Fragment作为一个树根发散来看待项目架构。最终,在树形项目架构中,便会产生1级、2级、3级节点出来 。 在同一级别的节点,有共同点,使用模板设计模式从中抽取。

以本项目中的推荐页来说

从功能层面看到 tab 精彩推荐和 tab 颜值控、英雄联盟等属于第一节点级别。但是精彩推荐和其他tab下的效果有很大的差别。而其他tab下的都是列表形式。那么精彩推荐可以单独分离一个Fragment,其他Tab可以抽象出一个BaseLiveWraperFragment。在这些BaseLiveWraperFragment中,其中颜值控的页面每个Item显示和其他不同。那么以LoveLiveListFragment作为父类,将数据绑定和Item布局的设定延迟到具体的子类LoveLiveListFragment中,实现子列表的独特展现。示例代码:

public class LoveLiveListFragment extends BaseLiveWraperFragment {

private LiveInteractor mLiveInteractor;

private int mScreenWidth;

public static LoveLiveListFragment newInstance(Bundle args) {

LoveLiveListFragment fragment = new LoveLiveListFragment();

fragment.setArguments(args);

return fragment;

}

@Override

public int getListItemLayout() {

return R.layout.listitem_love; //item 布局

}

@Override

protected void convertItem(ViewHolder holder, final PlayBean playBean, int position) { //item数据绑定

holder.setImageUrl(R.id.thumnails,playBean.thumb,new GlideRoundTransform(mActivity,5));

holder.setText(R.id.tv_viewnum,playBean.view);

holder.setText(R.id.intro,playBean.title);

..省略数行.

}

@Override

public void getDataError(String errmsg) {

showToast("获取颜值控数据失败");

}

}

父类BaseLiveWraperFragment相关方法:

public class BaseLiveWraperFragment extends BaseListFragment<PlayBean> {

protected String mUrl;

private LiveInteractor mLiveInteractor;

private String mTag;

public static BaseLiveWraperFragment newInstance(Bundle args) {

BaseLiveWraperFragment fragment = new BaseLiveWraperFragment();

fragment.setArguments(args);

return fragment;

}

public int getListItemLayout() { //item 布局

return R.layout.listitem_live;

}

@Override

protected void convertItem(ViewHolder holder, final PlayBean playBean, int position) { //item数据绑定

holder.setImageUrl(R.id.thumnails,playBean.thumb,new GlideRoundTransform(mActivity,5));

holder.setText(R.id.title,playBean.title);

..省略数行.

}

@Override

protected void initData() {  //获取网络数据

Bundle arguments = getArguments();

mUrl = arguments.getString("url", "");

mTag = arguments.getString("tag", "");

mLiveInteractor = new LiveInteractor();

mLiveInteractor.loadPlayList(this,mUrl);

}

@Override

public void getDataError(String errmsg) {

showToast("获取"+mTag+"数据失败");

}

}

而以BaseListFragment为跟节点,很多列表的实现都以此延伸,从然产生另一个“树”。这样,咱们可以将大大提高了代码了重用性、拓展性。结构也清晰明了。 对这一块有相同的开发思路就是对Presenter的处理是类似的,这里不深探究。

2. 模块化的开放方法

如果说树形方法是纵向的开发思路。那么模块化的开发方法就是横向的实现方式。在每一个节点中,以Activity为例,一个Activity所包含的功能中,可以想象为若干的Part组成。Part可以是功能或者View都可以。以项目中的直播页面为示例:

就目前的CommonLiveUI中:本人将Part分为:

  1. 播放器

  2. 竖屏控件持有者

  3. 横屏控件持有者

在onCreate方法中对其初始化操作,完了就放养了

@Override

protected void onCreate(Bundle savedInstanceState) {

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

super.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

super.onCreate(savedInstanceState);

setContentView(R.layout.act_commonliveplayer);

//1.初始化dagger2

mActivityComponent.inject(this);

mBasePresent=livePlayerPresenterImpl;

livePlayerPresenterImpl.attachView(this);

initPlayer();  //2.初始化播放器

initVerControll();//3.初始化竖屏控件持有者

initHorContrll();//4.初始化横屏控件持有者

initData();//5.初始化数据

}

初始化完,让各回各家,各找各妈。结合mvp+dagger2下来,优雅的解耦。而其余的代码,就是各种回调,刷新UI等等。

protected void onResume() {

super.onResume();

if (playerHolder!=null)

playerHolder.onResume();

}

@Override

protected void onPause() {

super.onPause();

if (playerHolder!=null)

playerHolder.onPause();

}

@Override

protected void onDestroy() {

if (playerHolder!=null){

playerHolder.release();

playerHolder=null;

}

verticalControll.onDestroy();

horizontalControll.onDestroy();

super.onDestroy();

}

@Override

protected void toPrepare() {

if (playerHolder!=null)

playerHolder.prepare();

}

@Override

public void onConfigurationChanged(Configuration newConfig) {

super.onConfigurationChanged(newConfig);

if (getRequestedOrientation()==ActivityInfo.SCREEN_ORIENTATION_PORTRAIT){

//portrait

}else {

//landscape

}

}

@Override

public void setRequestedOrientation(int requestedOrientation) {

super.setRequestedOrientation(requestedOrientation);

if (requestedOrientation==ActivityInfo.SCREEN_ORIENTATION_PORTRAIT){

isVertical=true;

verticalControll.onCreate();

horizontalControll.onDestroy();

}else {

isVertical=false;

horizontalControll.onCreate();

verticalControll.onDestroy();

}

}

@Override

public void onConnecting() {

mLoadingView.setVisibility(View.VISIBLE);

}

@Override

public void onReConnecting() {

showToastTips("正在重连...");

}

@Override

public void onConnectSucces() {

mLoadingView.setVisibility(View.GONE);

}

@Override

public void onConnectFailed() {

showToastTips("连接失败");

}

@Override

public void onPlayComleted() {

showToastTips("主播离开了");

}

@Override

public void onPlayerStart() {

bgImage.animate().alpha(0).setDuration(1000).start();

}

@Override

public void onPlayePause() {

}

@Override

public void onRoomData(JSONObject roomJson) {

mRoomDataController = new RoomDataController(roomJson);

mPlayerPath = mRoomDataController.getPlayerPath(0);

playerHolder = new LivePlayerHolder(this,mSurfaceView,mCodec,mPlayerPath);

playerHolder.startPlayer();

}

@Override

public void onBackPressed() {

if (getRequestedOrientation()==ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE){

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

ViewGroup.LayoutParams params =

(ViewGroup.LayoutParams) mSurfaceView.getLayoutParams();

params.width=mPortWidth;

params.height=mPortHeight;

ViewGroup.LayoutParams mStatusbarParams = mStatusbar.getLayoutParams();

mStatusbarParams.height= (int) (getResources().getDimension(R.dimen.status_bar_height)+0.5f);

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);

return;

}

if (playerHolder!=null)

playerHolder.release();

super.onBackPressed();

}

@Override

public void onVerticalClickFullScreen() {

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

Display display =

getWindow().getWindowManager().getDefaultDisplay();

DisplayMetrics metrics = new DisplayMetrics();

display.getMetrics(metrics);

int heightPixels = metrics.heightPixels;

int widthPixels = metrics.widthPixels;

Log.e("metrics","heightPixels"+heightPixels);

Log.e("metrics","widthPixels"+widthPixels);

ViewGroup.LayoutParams params =

(ViewGroup.LayoutParams) mSurfaceView.getLayoutParams();

int height = params.height;

int width = params.width;

//status bar

ViewGroup.LayoutParams mStatusbarParams = mStatusbar.getLayoutParams();

mStatusbarParams.height=0;

getWindow().getDecorView().setSystemUiVisibility(View.INVISIBLE);

Log.e("mSurfaceView","width"+width);

Log.e("mSurfaceView","height"+height);

mPortWidth=width;

mPortHeight=height;

params.width=widthPixels;

params.height=heightPixels;

}

@Override

public boolean onTouch(View v, MotionEvent event) {

LogUtil.i("TOUCH  "+isVertical);

verticalControll.onTouchEvent(isVertical,event);

horizontalControll.onTouchEvent(isVertical,event);

return false;

}

代码不超过300行。以此完成功能的模块化,非常直观的阅读。这样,少挖点坑,为后来接手的人减少点酷刑。

不过值得一提的是,在各种“持有者” 中,最好类似生命周期onCreate()和onDestory()方法,方便做资源释放,减少内存泄漏的发生。

部分截图:


横屏:

项目地址:https://github.com/a371166028/likequanmintv

总结

临时受邀于何俊林 ,写一篇分享文,也是非常感谢何俊林愿意我在此给大家分享。菜鸟一枚,利用闲暇时间写的小项目,在这里感谢大家的支持,同时很不要脸的向大家索求,喜欢的朋友可以给本人github一个star,分享结束。

第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。

直播项目之仿全民TV(已开源)相关推荐

  1. vue整合uniapp_基于vue+uniapp直播项目|uni-app仿抖音/陌陌直播室

    一.项目简介 uni-liveShow是一个基于vue+uni-app技术开发的集小视频/IM聊天/直播等功能于一体的微直播项目.界面仿制抖音|火山小视频/陌陌直播,支持编译到多端(H5.小程序.Ap ...

  2. 这个项目很骚气,已开源!作者脑洞也够大!!

    来源:公众号量子位 像文字云一样,用各种小图拼出大的图片,构建一个像素风的世界,就像<我的世界>里一样,一定非常有趣. 还可以拿来做拼贴画.十字绣等装饰. 在这个名为tiler的GitHu ...

  3. 斗鱼直播项目(已开源)

    推荐一个项目,仿斗鱼直播的,功能强大,可以借鉴学习. 目录结构 开发环境 更新日志 应用截图 下载地址 接口文档说明 项目中使用到的三方库说明 项目反馈 参考资料 一.开发环境 开发工具 开发语言 S ...

  4. (已开源)一款仿线上电商项目《有宠商城》

    本文来自赵若位同学开发的一款仿线上电商项目<有宠商城>,已经开源在github,点击阅读原文,可查看本项目github地址. 项目介绍: 前言:学如逆水行舟,不进则退: 1.这个项目是有上 ...

  5. GPT「高仿」问世:GPT-Neo,最大可达GPT-3大小,已开源 | AI日报

    GPT"高仿"问世:GPT-Neo,最大可达GPT-3大小,已开源 近日,有个名叫 EleutherAI的团队(创始成员为:Connor Leahy,Leo Gao和Sid Bla ...

  6. 【百度开放云开讲啦】全民TV、罗辑思维、百度揭秘直播核心技术

    启智创新 云领未来 7月30日,百度开放云全国巡讲北京站 正式开讲啦~ 现场照片 呃--光顾着盯茶点 差点错过了主持人的开场~ 认真听讲~认真听讲~ 至目前视频直播平台在全国近300家,直播用户近2亿 ...

  7. android高仿全民直播、多窗口管理、图标效果、开发框架,下拉上滑、UI框架等源码...

    Android精选源码 android仿UC浏览器多窗口管理界面 android高仿全民直播项目源码 android微信小程序设计模式,多任务窗体运行源码 Android项目源码在线课堂教育UI框架源 ...

  8. android高仿全民直播、多窗口管理、图标效果、开发框架,下拉上滑、UI框架等源码

    Android精选源码 android仿UC浏览器多窗口管理界面 android高仿全民直播项目源码 android微信小程序设计模式,多任务窗体运行源码 Android项目源码在线课堂教育UI框架源 ...

  9. 高仿斗鱼TV直播APP源码推荐

    菜鸟窝官网实战课程文章编辑招募中,如有兴趣加入可免费学习实战课程,联系方式:添加菜鸟君微信:keely-jzx 高仿斗鱼TV项目, 项目架构采用MVP模式,使用Retorfit2.0+RxJava1. ...

  10. 基于android的防抖音直播,基于vue+uniapp直播项目实现uni-app仿抖音/陌陌直播室功能...

    一.项目简介 uni-liveShow是一个基于vue+uni-app技术开发的集小视频/IM聊天/直播等功能于一体的微直播项目.界面仿制抖音|火山小视频/陌陌直播,支持编译到多端(H5.小程序.Ap ...

最新文章

  1. CodeIgniter类库
  2. AI教父杰弗里辛顿:AI反学习可能揭开人类梦境的奥秘
  3. node基础学习——操作文件系统fs
  4. JavaFX技巧13:学习Modena CSS文件
  5. java中写sql语句的小小细节
  6. With(ReadPast)就不会被阻塞吗?
  7. 深入解读Linux进程调度Schedule
  8. idea svn分支与分支合并_Idea svn 合并分支方式(坑)
  9. 世界三大统计分析软件sas splus spss
  10. u盘芯片 测试软件,U盘芯片检测工具(Chip Genius)
  11. burp数据包抓取操作
  12. 58私信怎么引流?58同城如何引流到微信?怎么用58同城做引流
  13. Beosin(成都链安)预警:黑客攻击EOS竞猜类游戏 已获利数百EOS
  14. 一小时爬千万数据的新浪微博爬虫
  15. 语法体系:快速区分同位语从句和定语从句day10
  16. js实现好看的图案 加勒比海盗(php拍黄片)
  17. 清华2020计算机系张晨,本科三篇顶会一作、超算竞赛冠军,2020清华本科特奖结果出炉...
  18. 提示找不到 XXX.dll 解决方法
  19. MAC地址查询 Linux/Unix操作系统mac地址怎么查
  20. unity中的四种灯光

热门文章

  1. 其他学习笔记(一)——MySQL基础配置+可视化工具安装与破解
  2. BiANet:用于快速高效实现RGB-D数据显著性目标检测的双边注意力模型
  3. 小Q正在给一条长度为n的道路设计路灯安置方案。 为了让问题更简单,小Q把道路视为n个方格,需要照亮的地方用'.'表示, 不需要照亮的障碍物格子用'X'表示。
  4. kaggle实战之流浪猫狗归处预测
  5. [error]:启用sqlserver配置管理器异常,内存不足
  6. HTTP、Asp.net管道与IIS
  7. websocket-shap 函数Broadcast的使用方法
  8. 上下文路径request.getContextPath();与${pageContext.request.contextPath}
  9. 将I1111改成I1112
  10. POJ 1002 电话号码字符串处理