专属空间十一 ——私人影院(在线看电视台的直播)
今天做的是一个看电视台直播的功能。
MainActivity的布局是listView,直播布局页面写的是videoview中嵌套上下的一个panel和加载的一个动画。
上面的显示的是卫视名称和当前的时间。
需要注意的是直播源,也就是播放的卫视的网址链接,需要去在网上找或者是自己去抓取,网上找的话推荐去
http://www.hdpfans.com这个网站去找,也给大家推荐一个我自己用的:https://ys.xitaofan.com/zbtv/zb.txt。
点击HDP直播,然后找上图这种的点开就会有网址链接,但是不一定有效。需要自己去测试。
这样的话就需要你去下载一个VLC软件,打开后点击File-network,利用网络串流输入你找的这个网址链接测试是否有效。有效的话他就会播放电视台的直播。也就意味着你可用在你的代码中。
这个软件还用了vitamio框架,可以去github上下载:https://github.com/yixia/VitamioBundle
1、在你的项目建立一个model下的android library,或者直接而将vitamio导入你的android项目-File->new->Import Module,导入vitmio文件夹。注意的是导入之后vitamio目录下的build.gradle中配置,要和app目录下的build.gradle中的配置相同:
2、在你的app的build下dependence中加入依赖implementation project(':vitamoi')
3、需要在AndroidManifest中加入权限
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
4、需要在Application中vitamio初始化Activity,和下图面一样。
<activity
android:name="io.vov.vitamio.activity.InitActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
android:launchMode="singleTop"
android:theme="@android:style/Theme.NoTitleBar"
android:windowSoftInputMode="stateAlwaysHidden" />
切记:我们代码中的videoview和Mediaplayer用的都是vitamio中的。hander用的是原生自带的android.os. 。
完成效果图:
java:
package com.example.tvshow; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.widget.ListView; public class MainActivity extends AppCompatActivity { private ListView mListView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mListView = (ListView) findViewById(R.id.live_program); mListView.setAdapter(new ItemProgramAdapter(MainActivity.this)); } }
package com.example.tvshow; import android.content.Context; import android.content.Intent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; public class ItemProgramAdapter extends BaseAdapter { private Context mContext;//数据集 private String[] mDataList = new String[]{ "凤凰卫视","广西卫视","陕西卫视","厦门卫视","韩国阿里郎","香港电影","湖南卫视", "广东卫视","黑龙江卫视" }; private String[] mUrlList = new String[]{ "http://117.169.72.6:8080/ysten-businessmobile/live/fhchinese/1.m3u8", "http://112.50.243.8/PLTV/88888888/224/3221225836/1.m3u8", "http://111.13.111.242/otttv.bj.chinamobile.com/PLTV/88888888/224/3221225896/1.m3u8", "http://ott.fj.chinamobile.com/PLTV/88888888/224/3221226781/1.m3u8", "http://amdlive.ctnd.com.edgesuite.net/arirang_1ch/smil:arirang_1ch.smil/playlist.m3u8", "rtmp://58.200.131.2:1935/livetv/fhdy", "http://223.110.243.173/PLTV/3/224/3221227220/index.m3u8", "http://223.110.243.136/PLTV/3/224/3221227249/index.m3u8", "http://111.13.111.242/otttv.bj.chinamobile.com/PLTV/88888888/224/3221226239/1.m3u8" }; @Override public int getCount() { return mDataList.length; } public ItemProgramAdapter(Context context){ mContext = context; } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertview, ViewGroup viewGroup) { ViewHolder holder; if(convertview == null){ convertview = LayoutInflater.from(mContext).inflate(R.layout.item_program_adapter,null); holder = new ViewHolder(convertview); convertview.setTag(holder); }else{ holder = (ViewHolder) convertview.getTag(); } holder.textView.setText(mDataList[position]); holder.textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(mContext,LiveActivity.class); intent.putExtra("url",mUrlList[position]); intent.putExtra("title",mDataList[position]); mContext.startActivity(intent); } }); return convertview; } private class ViewHolder { TextView textView; public ViewHolder(View view){ textView = (TextView)view.findViewById(R.id.tv_item_program_title); } } }
package com.example.tvshow; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import android.content.DialogInterface; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.util.Log; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; import java.text.SimpleDateFormat; import java.util.Calendar; import io.vov.vitamio.LibsChecker; import io.vov.vitamio.MediaPlayer; import io.vov.vitamio.Vitamio; import io.vov.vitamio.widget.VideoView; public class LiveActivity extends AppCompatActivity { private static final String TAG = LiveActivity.class.getSimpleName(); private String mUrl; private String mTitle; private ImageView mBackButton; private TextView mTextView; private TextView mSysTime; private io.vov.vitamio.widget.VideoView mVideoView; private static final int RETRY_TIMES = 5; private static final int AUTO_HIDE_TIME = 5000; private int mCount; private RelativeLayout mLoadingLayout; private Uri mUri; private RelativeLayout mRootView; private LinearLayout mTopLayout; private LinearLayout mBottomLayout; private Handler mHandler = new Handler(Looper.getMainLooper()); private ImageView mPlayButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_live); mUrl = getIntent().getStringExtra("url"); mTitle = getIntent().getStringExtra("title"); Log.d(TAG,">> onCreate mTitle=" + mTitle + ", mUrl=" +mUrl); initView(); initPlayer(); } private void initPlayer() { Vitamio.isInitialized(getApplicationContext()); Vitamio.initialize(this); //设置视频解码监听 if (!LibsChecker.checkVitamioLibs(this)) { return; } mUri = Uri.parse(mUrl); mPlayButton = (ImageView) findViewById(R.id.iv_play);//播放按钮 mPlayButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if(mVideoView.isPlaying()){ mVideoView.stopPlayback(); mPlayButton.setImageResource(R.drawable.pause_button_normal); }else { mVideoView.setVideoURI(mUri); mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mVideoView.start(); } }); mPlayButton.setImageResource(R.drawable.play_button_normal); } } }); mVideoView = (VideoView) findViewById(R.id.surface_view);//播放界面 mVideoView.setVideoURI(mUri);//解析地址 /*new AlertDialog.Builder(LiveActivity.this) .setMessage("hello") .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { ; } }).setCancelable(false).show(); */ mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mediaPlayer) { mVideoView.start(); } }); /*MediaController controller = new MediaController(this); mVideoView.setMediaController(controller);*/ mVideoView.setOnErrorListener(new MediaPlayer.OnErrorListener() { @Override public boolean onError(MediaPlayer mediaPlayer, int i, int i1) { if(mCount > RETRY_TIMES){ new AlertDialog.Builder(LiveActivity.this) .setMessage(R.string.err_message) .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { LiveActivity.this.finish(); } }).setCancelable(false).show(); }else{ mVideoView.stopPlayback(); mVideoView.setVideoURI(Uri.parse(mUrl)); } mCount++; return false; } }); mVideoView.setOnInfoListener(new MediaPlayer.OnInfoListener() { @Override public boolean onInfo(MediaPlayer mediaPlayer, int i, int i1) { switch (i){ case MediaPlayer.MEDIA_INFO_BUFFERING_START: mLoadingLayout.setVisibility(View.VISIBLE); break; case MediaPlayer.MEDIA_INFO_BUFFERING_END: //音频先于视频出来 case MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING: //边下边播 case MediaPlayer.MEDIA_INFO_DOWNLOAD_RATE_CHANGED: mLoadingLayout.setVisibility(View.GONE); break; } return false; } }); } private void initView() { mBackButton = (ImageView) findViewById(R.id.iv_back); mBackButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { finish(); } }); mTextView = (TextView) findViewById(R.id.tv_title); mTextView.setText(mTitle); mSysTime = (TextView)findViewById(R.id.tv_systime); mSysTime.setText(getCurrentTime()); mLoadingLayout = (RelativeLayout) findViewById(R.id.rl_loading_layout); mRootView = (RelativeLayout) findViewById(R.id.activity_live); mTopLayout = (LinearLayout) findViewById(R.id.ll_top_layout); mBottomLayout = (LinearLayout) findViewById(R.id.ll_play_layout); mRootView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if(mBottomLayout.getVisibility() == View.VISIBLE || mTopLayout.getVisibility() == View.VISIBLE){ mTopLayout.setVisibility(View.GONE); mBottomLayout.setVisibility(View.GONE); return; } if(mVideoView.isPlaying()){ //正在播放 mPlayButton.setImageResource(R.drawable.play_button_normal); }else{ mPlayButton.setImageResource(R.drawable.pause_button_normal); } mTopLayout.setVisibility(View.VISIBLE); mBottomLayout.setVisibility(View.VISIBLE); mHandler.postDelayed(new Runnable() { @Override public void run() { mTopLayout.setVisibility(View.GONE); mBottomLayout.setVisibility(View.GONE); } },AUTO_HIDE_TIME); } }); } private String getCurrentTime(){ Calendar c = Calendar.getInstance(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String time = sdf.format(c.getTime()); return time; } @Override protected void onStop(){ super.onStop(); mCount = 0; if(mVideoView != null){ mVideoView.stopPlayback(); } } }
Drawable中的vedio_loading.xml
<?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:fromDegrees="0" android:pivotX="50%" android:pivotY="50%" android:toDegrees="1080.0"> <shape android:innerRadiusRatio="3" android:shape="ring" android:thicknessRatio="10" android:useLevel="false"> <gradient android:centerColor="#FFDC35" android:centerY="0.50" android:endColor="#CE0000" android:startColor="#FFFFFF" android:type="sweep" android:useLevel="false" /> </shape> </rotate>
layout中的:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.tvshow.MainActivity"> <ListView android:id="@+id/live_program" android:layout_width="match_parent" android:layout_height="wrap_content" /> </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/tv_item_program_title" android:layout_width="match_parent" android:layout_height="50dp" android:textSize="24sp" android:gravity="center" android:text="CCTV"/> </LinearLayout>
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:id="@+id/activity_live" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.tvshow.LiveActivity"> <io.vov.vitamio.widget.VideoView android:id="@+id/surface_view" android:layout_width="match_parent" android:layout_height="match_parent"/> <!--TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="666" android:textSize="50sp" android:textColor="@color/white" android:layout_centerHorizontal="true" android:layout_alignParentLeft="true"/--> <!--顶部panel--> <RelativeLayout android:id="@+id/rl_loading_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/rl_lodaing_bg"> <ProgressBar android:id="@+id/pd_loading" android:layout_width="60dp" android:layout_height="60dp" android:layout_centerInParent="true" android:indeterminate="false" android:indeterminateDrawable="@drawable/vedio_loading" /> <TextView android:id="@+id/tv_loading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/pd_loading" android:layout_centerHorizontal="true" android:text="@string/loading" android:textColor="@color/White" android:textSize="24sp" /> </RelativeLayout> <LinearLayout android:id="@+id/ll_top_layout" android:layout_width="match_parent" android:layout_height="40dp" android:background="@color/player_panel_bg" android:layout_alignParentTop="true" android:visibility="gone" android:orientation="horizontal"> <ImageView android:id="@+id/iv_back" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/return_button_normal" android:layout_gravity="center_vertical" android:paddingRight="5dp"/> <TextView android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/White" android:textSize="20sp" android:text="@string/item_title_default" android:layout_gravity="center_vertical"/> <TextView android:id="@+id/tv_systime" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/sys_time" android:textColor="@color/White" android:textSize="20sp" android:layout_marginLeft="190dp" android:layout_gravity="center_vertical"/> </LinearLayout> <!--底部panel--> <LinearLayout android:id="@+id/ll_play_layout" android:layout_width="match_parent" android:layout_height="40dp" android:background="@color/player_panel_bg" android:layout_alignParentBottom="true" android:visibility="gone" android:orientation="horizontal"> <ImageView android:id="@+id/iv_play" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/play_button_normal" android:layout_gravity="center_vertical" android:paddingLeft="10dp" android:paddingRight="15dp"/> </LinearLayout> </RelativeLayout>
可参考https://github.com/Realding/LiveApp