保存到桌面加入收藏设为首页
IOS开发
当前位置:首页 > IOS开发

AndroidTV开发总结(六)构建一个TVapp的直播节目实例-安度博客

时间:2019-02-08 15:56:37   作者:   来源:   阅读:147   评论:0
内容摘要:请尊重分享成果,转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52966319近年来,nk" target="_blank">Android TV的迅速发展,传统的有线电视受到较大......
  • 请尊重分享成果,转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52966319

    近年来,nk" target="_blank">Android TV的迅速发展,传统的有线电视受到较大的冲击,在TV上用户同样也可以看到各个有线电视的直播频道,相对于手机,这种直播节目,体验效果更佳,尤其是一样赛事节目,大屏幕看得才够痛快,还可以邀几好友一起欣赏。今天将介绍构建一个TV app的直播节目实例此实例上传到Github: https://github.com/hejunlin2013/LivePlayback 喜欢可以star。Agenda如下:

    效果图 代码实现: 主页面:Recycleview对应Adapater 直播节目源 播放器 播放页处理 播放页的播放panel:

    先看下效果图:

    主界面:
    这里写图片描述

    这里写图片描述

    CCTV-1:

    这里写图片描述

    湖南卫视:

    这里写图片描述

    CCTV-第一剧场:

    这里写图片描述

    CCTV-15(音乐):

    这里写图片描述

    CCTV-14(少儿):

    这里写图片描述

    CCTV-13(新闻):

    这里写图片描述

    CCTV-12(社会与法):

    这里写图片描述

    CCTV-11(戏曲):

    这里写图片描述

    CCTV-10(科教):

    这里写图片描述

    CCTV-9(纪录):

    这里写图片描述

    CCTV-8(电视剧):

    这里写图片描述

    CCTV-第一剧场:

    这里写图片描述

    CCTV-15:

    这里写图片描述
    请尊重分享成果,转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52966319

    代码实现:

    主页面:Recycleview对应adapater 直播节目源 播放器 播放页处理

    主页面:

    /* * Copyright (C) 2016 hejunlin <hejunlin2013@gmail.com> * Licensed under the Apache License Version 2.0 (the &#39;License&#39;); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing software * distributed under the License is distributed on an &#39;AS IS&#39; BASIS * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */public class MainActivity extends Activity { private MetroViewBorderImpl mMetroViewBorderImpl; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mMetroViewBorderImpl = new MetroViewBorderImpl(this); mMetroViewBorderImpl.setBackgroundResource(R.drawable.border_color); loadRecyclerViewMenuItem(); } private void loadRecyclerViewMenuItem() { RecyclerView recyclerView = (RecyclerView) findViewById(R.id.ry_menu_item); GridLayoutManager layoutManager = new GridLayoutManager(this 1); layoutManager.setOrientation(LinearLayoutManager.VERTICAL); recyclerView.setLayoutManager(layoutManager); recyclerView.setFocusable(false); mMetroViewBorderImpl.attachTo(recyclerView); createOptionItemData(recyclerView R.layout.detail_menu_item); } private void createOptionItemData(RecyclerView recyclerView int id) { OptionItemAdapter adapter = new OptionItemAdapter(this id); recyclerView.setAdapter(adapter); recyclerView.scrollToPosition(0); }}

    播放页:

    /* * Copyright (C) 2016 hejunlin <hejunlin2013@gmail.com> * Licensed under the Apache License Version 2.0 (the &#39;License&#39;); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing software * distributed under the License is distributed on an &#39;AS IS&#39; BASIS * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */public class LiveActivity extends Activity { private IjkVideoView mVideoView; private RelativeLayout mVideoViewLayout; private RelativeLayout mLoadingLayout; private TextView mLoadingText; private TextView mTextClock; private String mVideoUrl = &#39;&#39;; private int mRetryTimes = 0; private static final int CONNECTION_TIMES = 5; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_live); mVideoUrl = getIntent().getStringExtra(&#39;url&#39;); mVideoView = (IjkVideoView) findViewById(R.id.videoview); mVideoViewLayout = (RelativeLayout) findViewById(R.id.fl_videoview); mLoadingLayout = (RelativeLayout) findViewById(R.id.rl_loading); mLoadingText = (TextView) findViewById(R.id.tv_load_msg); mTextClock = (TextView)findViewById(R.id.tv_time); mTextClock.setText(getDateFormate()); mLoadingText.setText(&#39;节目加载中...&#39;); initVideo(); } private String getDateFormate(){ Calendar c = Calendar.getInstance(); SimpleDateFormat df = new SimpleDateFormat(&#39;yyyy-MM-dd HH:mm:ss&#39;); String formattedDate = df.format(c.getTime()); return formattedDate; } public void initVideo() { // init player IjkMediaPlayer.loadLibrariesOnce(null); IjkMediaPlayer.native_profileBegin(&#39;libijkplayer.so&#39;); mVideoView.setVideoURI(Uri.parse(mVideoUrl)); mVideoView.setOnPreparedListener(new IMediaPlayer.OnPreparedListener() { @Override public void onPrepared(IMediaPlayer mp) { mVideoView.start(); } }); mVideoView.setOnInfoListener(new IMediaPlayer.OnInfoListener() { @Override public boolean onInfo(IMediaPlayer mp int what int extra) { switch (what) { case IjkMediaPlayer.MEDIA_INFO_BUFFERING_START: mLoadingLayout.setVisibility(View.VISIBLE); break; case IjkMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START: case IjkMediaPlayer.MEDIA_INFO_BUFFERING_END: mLoadingLayout.setVisibility(View.GONE); break; } return false; } }); mVideoView.setOnCompletionListener(new IMediaPlayer.OnCompletionListener() { @Override public void onCompletion(IMediaPlayer mp) { mLoadingLayout.setVisibility(View.VISIBLE); mVideoView.stopPlayback(); mVideoView.release(true); mVideoView.setVideoURI(Uri.parse(mVideoUrl)); } }); mVideoView.setonerrorListener(new IMediaPlayer.onerrorListener() { @Override public boolean onerror(IMediaPlayer mp int what int extra) { if (mRetryTimes > CONNECTION_TIMES) { new AlertDialog.Builder(LiveActivity.this) .setMessage(&#39;节目暂时不能播放&#39;) .setPositiveButton(R.string.VideoView_error_button new DialogInterface.onclickListener() { public void onclick(DialogInterface dialog int whichButton) { LiveActivity.this.finish(); } }) .setCancelable(false) .show(); } else { mVideoView.stopPlayback(); mVideoView.release(true); mVideoView.setVideoURI(Uri.parse(mVideoUrl)); } return false; } }); } @Override protected void onResume() { super.onResume(); } @Override protected void onPause() { super.onPause(); } @Override protected void onstop() { super.onstop(); if (!mVideoView.isBackgroundPlayEnabled()) { mVideoView.stopPlayback(); mVideoView.release(true); mVideoView.stopBackgroundPlay(); } IjkMediaPlayer.native_profileEnd(); } public static void activityStart(Context context String url) { Intent intent = new Intent(context LiveActivity.class); intent.putExtra(&#39;url&#39; url); context.startActivity(intent); } @Override public void onConfigurationchanged(Configuration newConfig) { super.onConfigurationchanged(newConfig); }}

    播放器是用二次封装的ijkplayer,从主页面传url到播放页面,关才mediaplayer相关,之前专门写了专题分析,mediaplayer的状态可参考《nk" target="_blank">Android Multimedia框架总结(一)MediaPlayer介绍之状态图及生命周期》
    第三方播放器典型特点就是另起一个mediaplayerservice,注意这是另外一个进程,为什么是另一个进程,可参见我的文章:MediaPlayer的C/S模型。对于ijkplayer这个框架,因为做实例,才引入,不做评价,也不会去深究,满足基本播放需求就ok。市场上有很多第三方播放框架,ijkplayervitamio百度云播放等。

    再看下播放页的播放panel:

    <?xml version=&#39;1.0&#39; encoding=&#39;utf-8&#39;?><RelativeLayout xmlns:android=&#39;http://schemas.android.com/apk/res/android&#39; android:layout_width=&#39;match_parent&#39; android:layout_height=&#39;match_parent&#39; android:background=&#39;#22000000&#39; android:orientation=&#39;vertical&#39;> <RelativeLayout android:id=&#39;@+id/fl_videoview&#39; android:layout_width=&#39;match_parent&#39; android:layout_height=&#39;match_parent&#39; android:background=&#39;@color/colorBlack&#39;> <com.hejunlin.liveplayback.ijkplayer.media.IjkVideoView android:id=&#39;@+id/videoview&#39; android:layout_width=&#39;match_parent&#39; android:layout_height=&#39;match_parent&#39; android:layout_centerInParent=&#39;true&#39; android:background=&#39;@color/colorBlack&#39;> </com.hejunlin.liveplayback.ijkplayer.media.IjkVideoView> <RelativeLayout android:id=&#39;@+id/rl_loading&#39; android:layout_width=&#39;match_parent&#39; android:layout_height=&#39;match_parent&#39; android:background=&#39;#de262a3b&#39;> <TextView android:id=&#39;@+id/tv_load_msg&#39; android:layout_width=&#39;wrap_content&#39; android:layout_height=&#39;wrap_content&#39; android:layout_below=&#39;@+id/pb_loading&#39; android:layout_centerInParent=&#39;true&#39; android:layout_marginTop=&#39;6dp&#39; android:textColor=&#39;#ffffff&#39; android:textSize=&#39;16sp&#39; /> <ProgressBar android:id=&#39;@+id/pb_loading&#39; android:layout_width=&#39;60dp&#39; android:layout_height=&#39;60dp&#39; android:layout_centerInParent=&#39;true&#39; android:layout_marginTop=&#39;60dp&#39; android:indeterminate=&#39;false&#39; android:indeterminateDrawable=&#39;@drawable/video_loading&#39; android:padding=&#39;5dp&#39; /> </RelativeLayout> <LinearLayout android:layout_width=&#39;match_parent&#39; android:layout_height=&#39;wrap_content&#39; android:background=&#39;@color/player_panel_background_color&#39;> <TextView android:id=&#39;@+id/tv_title&#39; android:layout_width=&#39;wrap_content&#39; android:layout_height=&#39;60dp&#39; android:textSize=&#39;24dp&#39; android:text=&#39;Android TV开发总结(六)构建一个TV app的直播节目实例&#39; android:layout_centerVertical=&#39;true&#39; android:layout_marginTop=&#39;18dp&#39; android:textColor=&#39;@color/white&#39;/> <TextView android:id=&#39;@+id/tv_time&#39; android:layout_width=&#39;wrap_content&#39; android:layout_height=&#39;60dp&#39; android:textSize=&#39;20dp&#39; android:layout_toRightOf=&#39;@id/tv_title&#39; android:layout_alignParentRight=&#39;true&#39; android:layout_centerVertical=&#39;true&#39; android:layout_marginLeft=&#39;60dp&#39; android:layout_marginTop=&#39;20dp&#39; android:textColor=&#39;@color/white&#39;/> </LinearLayout> </RelativeLayout></RelativeLayout>

    这里有几个点要注意 :

    为演示,并未对层级进行使用frameLayout及viewstubinclude等性能优化相关的,在实际商用项目中,建议写xml文件,尽可能遵循过少的层级,高级标签及frameLayout等技巧。 所有的size切勿直接写死,用 android:layout_marginTop=”@dimen/dimen_20dp”表示,string值统一写到string.xml中,这些基本的规范,会让你提高不少效率。

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


    这里写图片描述

    如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易

本站所有站内信息仅供娱乐参考,不作任何商业用途,不以营利为目的,专注分享快乐,欢迎收藏本站!
所有信息均来自:百度一下 (威尼斯人官网)