【001】【视频开发】ijkplayer

1.将ijkplayer的引入

 

【声明全局的编译环境的指定】

【生成类库】

【拷贝example下的wiget下的media文件夹】

【拷贝文件】

【暂时不使用exoplayer-删除】

【拷贝string字符串及stringPref文件】

【代码块编译gradle编译<--没有问题之后拷贝.so】

【引入权限】

【添加控件】

【初始化】

 

 

【说明】后续还会有一些文件的缺失,自行拷贝即可。

 2. progressBar的引入

【源码】【video_loading.xml】

 1 <rotate xmlns:android="http://schemas.android.com/apk/res/android"
 2     android:fromDegrees="0"
 3     android:toDegrees="1080"
 4     android:pivotX="50%"
 5     android:pivotY="50%">
 6 
 7     <!-- android:innerRadiusRatio="3" 表示内环半径 -->
 8     <!-- android:thicknessRatio="10" 表示环厚度半径 -->
 9     <!-- android:useLevel="false" 表示有渐变-->
10 
11     <shape
12         android:shape="ring"
13         android:innerRadiusRatio="3"
14         android:thicknessRatio="10"
15         android:useLevel="false">
16 
17         <!-- gradient 梯度-->
18         <!-- android:centerY="0.5" 表示渐变中心y的相对位置-->
19         <!-- android:type="sweep" sweep表示扫描式, linear表示线性, radial辐射式-->
20     <gradient
21         android:startColor="@color/loading_start_color"
22         android:centerColor="@color/loading_center_color"
23         android:endColor="@color/loading_end_color"
24         android:centerY="0.5"
25         android:useLevel="false"
26         android:type="sweep"/>
27 
28     </shape>
29 
30 </rotate>

【activity_play.xml】

  1 <?xml version="1.0" encoding="utf-8"?>
  2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3     xmlns:tools="http://schemas.android.com/tools"
  4     android:id="@+id/activity_play"
  5     android:layout_width="match_parent"
  6     android:layout_height="match_parent"
  7     android:background="@android:color/black"  //+++++++
  8     android:gravity="center" //+++++++
  9     android:keepScreenOn="true"> //+++++++ 播放不熄灭屏幕
 10 
 11     <FrameLayout      //+++++++
 12         android:id="@+id/fl_surface_container"
 13         android:layout_width="match_parent"
 14         android:layout_height="match_parent">
 15 
 16     <com.hejunlin.imooc_supervideo.widget.media.IjkVideoView
 17         android:id="@+id/video_view"
 18         android:layout_width="match_parent"
 19         android:layout_height="match_parent"
 20         android:layout_gravity="center"/>
 21 
 22             //加载转圈的动画
 23         <RelativeLayout
 24             android:id="@+id/rl_loading_layout"
 25             android:layout_width="match_parent"
 26             android:layout_height="match_parent">
 27 
 28             <TextView
 29                 android:id="@+id/tv_loading_info"
 30                 android:layout_width="wrap_content"
 31                 android:layout_height="wrap_content"
 32                 android:layout_below="@+id/pb_loading"
 33                 android:layout_centerInParent="true"
 34                 android:layout_marginTop="@dimen/dimen_12dp"
 35                 android:textSize="@dimen/dimen_32sp"
 36                 android:textColor="@color/white"/>
 37 
 38             <!--android:indeterminate 表示不确定的进度-->
 39             <ProgressBar
 40                 android:id="@+id/pb_loading"
 41                 android:layout_width="@dimen/dimen_120dp"
 42                 android:layout_height="@dimen/dimen_120dp"
 43                 android:layout_centerInParent="true"
 44                 android:indeterminate="false"
 45                 android:indeterminateDrawable="@drawable/video_loading"
 46                 android:padding="@dimen/dimen_10dp"
 47                 android:layout_marginTop="@dimen/dimen_120dp"/>
 48 
 49 
 50         </RelativeLayout>
 51 
 52         <TextView
 53             android:id="@+id/tv_horiontal_gesture"
 54             android:layout_width="match_parent"
 55             android:layout_height="wrap_content"
 56             android:shadowDx="1.0"
 57             android:shadowDy="1.0"
 58             android:shadowColor="@color/black"
 59             android:textColor="@color/white"
 60             android:textSize="@dimen/dimen_64sp"
 61             android:visibility="gone"
 62             android:textStyle="bold"
 63             android:gravity="center"/>
 64 
 65         <TextView
 66             android:id="@+id/tv_vertical_gesture"
 67             android:layout_width="wrap_content"
 68             android:layout_height="wrap_content"
 69             android:layout_gravity="center"
 70             android:gravity="center_horizontal"
 71             android:background="@drawable/black_bg"
 72             android:paddingLeft="@dimen/dimen_100dp"
 73             android:paddingRight="@dimen/dimen_100dp"
 74             android:paddingTop="@dimen/dimen_40dp"
 75             android:paddingBottom="@dimen/dimen_40dp"
 76             android:textSize="@dimen/dimen_64sp"
 77             android:textStyle="bold"
 78             android:textColor="@color/white"
 79             android:visibility="gone"/>
 80 
155 
224 </RelativeLayout>

3.播放功能的添加

【播放】

【运行点击播放】

【bug】

原因是没有将InfoHodlerVideo移除掉,只移除了一部分

【解决办法】将InfoHodlerVideo所有源码注释掉

4.设置为启动进入之后是横屏

5.progressBar 在正常播放之后消失

【问题】

【PlayActivity.java】

 1  @Override
 2     protected void initView() {
 3         ......
 4         IjkMediaPlayer.native_profileBegin("libijkplayer.so");
 5         mLoadingLayout = bindViewId(R.id.rl_loading_layout);
 6         mLoadingText = bindViewId(R.id.tv_loading_info);
 7         mLoadingText.setText("正在加载中...");
 8         mVideoView.setVideoURI(Uri.parse(mUrl));
 9         mVideoView.setOnPreparedListener(new IMediaPlayer.OnPreparedListener() {
10             @Override
11             public void onPrepared(IMediaPlayer mp) {
12                 mVideoView.start();
13             }
14         });
15         //设置监听
16         mVideoView.setOnInfoListener(new IMediaPlayer.OnInfoListener() {
17             @Override
18             public boolean onInfo(IMediaPlayer mp, int what, int extra) {
19                 switch (what) {
20                     case IjkMediaPlayer.MEDIA_INFO_BUFFERING_START: //开始加载,则loading显示
21                         mLoadingLayout.setVisibility(View.VISIBLE);
22                         break;
23                     case IjkMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START://开始播放或者是缓存结束,则loading不显示
24                     case IjkMediaPlayer.MEDIA_INFO_BUFFERING_END:
25                         mLoadingLayout.setVisibility(View.GONE);
26                         break;
27                 }
28                 return false;
29             }
30         });
31     ............
32     }

 【测试】在自己播放之后自己横屏显示,并且loading动画消失

6.mediaplayer状态机

【说明】必须学习的内容

【箭头】表示工作流的工作的过程;

【椭圆】表示状态;

【箭头旁边的方法】执行此方法才能到达的状态;

 7.播放的流程图

 8.上下panle的布局添加

  1 <?xml version="1.0" encoding="utf-8"?>
  2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3     xmlns:tools="http://schemas.android.com/tools"
  4     android:id="@+id/activity_play"
  5     android:layout_width="match_parent"
  6     android:layout_height="match_parent"
  7     android:background="@android:color/black"  //+++++++
  8     android:gravity="center" //+++++++
  9     android:keepScreenOn="true"> //+++++++
 10 
 11     <FrameLayout      //+++++++
 12         android:id="@+id/fl_surface_container"
 13         android:layout_width="match_parent"
 14         android:layout_height="match_parent">
 15 
 16     <com.hejunlin.imooc_supervideo.widget.media.IjkVideoView
 17         android:id="@+id/video_view"
 18         android:layout_width="match_parent"
 19         android:layout_height="match_parent"
 20         android:layout_gravity="center"/>
 21 
 22             //加载转圈的动画
 23         <RelativeLayout
 24             android:id="@+id/rl_loading_layout"
 25             android:layout_width="match_parent"
 26             android:layout_height="match_parent">
 27 
 28             <TextView
 29                 android:id="@+id/tv_loading_info"
 30                 android:layout_width="wrap_content"
 31                 android:layout_height="wrap_content"
 32                 android:layout_below="@+id/pb_loading"
 33                 android:layout_centerInParent="true"
 34                 android:layout_marginTop="@dimen/dimen_12dp"
 35                 android:textSize="@dimen/dimen_32sp"
 36                 android:textColor="@color/white"/>
 37 
 38             <!--android:indeterminate 表示不确定的进度-->
 39             <ProgressBar
 40                 android:id="@+id/pb_loading"
 41                 android:layout_width="@dimen/dimen_120dp"
 42                 android:layout_height="@dimen/dimen_120dp"
 43                 android:layout_centerInParent="true"
 44                 android:indeterminate="false"
 45                 android:indeterminateDrawable="@drawable/video_loading"
 46                 android:padding="@dimen/dimen_10dp"
 47                 android:layout_marginTop="@dimen/dimen_120dp"/>
 48 
 49 
 50         </RelativeLayout>
 51 
 52         <TextView
 53             android:id="@+id/tv_horiontal_gesture"
 54             android:layout_width="match_parent"
 55             android:layout_height="wrap_content"
 56             android:shadowDx="1.0"
 57             android:shadowDy="1.0"
 58             android:shadowColor="@color/black"
 59             android:textColor="@color/white"
 60             android:textSize="@dimen/dimen_64sp"
 61             android:visibility="gone"
 62             android:textStyle="bold"
 63             android:gravity="center"/>
 64 
 65         <TextView
 66             android:id="@+id/tv_vertical_gesture"
 67             android:layout_width="wrap_content"
 68             android:layout_height="wrap_content"
 69             android:layout_gravity="center"
 70             android:gravity="center_horizontal"
 71             android:background="@drawable/black_bg"
 72             android:paddingLeft="@dimen/dimen_100dp"
 73             android:paddingRight="@dimen/dimen_100dp"
 74             android:paddingTop="@dimen/dimen_40dp"
 75             android:paddingBottom="@dimen/dimen_40dp"
 76             android:textSize="@dimen/dimen_64sp"
 77             android:textStyle="bold"
 78             android:textColor="@color/white"
 79             android:visibility="gone"/>
 80 
 81         <FrameLayout //顶部相关的panel
 82             android:id="@+id/fl_player_top_container"
 83             android:layout_width="match_parent"
 84             android:layout_height="@dimen/dimen_70dp"
 85             android:layout_gravity="top"
 86             android:background="@color/player_panel_background_color"
 87             android:paddingTop="@dimen/dimen_10dp"
 88             android:paddingBottom="@dimen/dimen_10dp">
 89 
 90             <LinearLayout
 91                 android:layout_width="wrap_content"
 92                 android:layout_height="wrap_content"
 93                 android:layout_gravity="center_vertical"
 94                 android:orientation="horizontal">
 95 
 96                 <ImageView
 97                     android:id="@+id/iv_player_close"
 98                     android:layout_width="wrap_content"
 99                     android:layout_height="wrap_content"
100                     android:paddingLeft="@dimen/dimen_15dp"
101                     android:paddingRight="@dimen/dimen_15dp"
102                     android:layout_gravity="center_vertical"
103                     android:src="@drawable/titlebar_return_white"/>
104 
105                 <TextView
106                     android:id="@+id/tv_player_video_name"
107                     android:layout_width="wrap_content"
108                     android:layout_height="wrap_content"
109                     android:layout_gravity="center_vertical"
110                     android:ellipsize="end"
111                     android:singleLine="true"
112                     android:textColor="@color/white"
113                     android:textSize="@dimen/dimen_32sp"/>
114 
115             </LinearLayout>
116 
117             <LinearLayout
118                 android:layout_width="wrap_content"
119                 android:layout_height="wrap_content"
120                 android:layout_gravity="right|center_vertical"
121                 android:orientation="horizontal">
122 
123                 <ImageView  //电池电量
124                     android:id="@+id/iv_battery"
125                     android:layout_width="wrap_content"
126                     android:layout_height="wrap_content"
127                     android:layout_marginRight="@dimen/dimen_10dp"
128                     android:layout_gravity="center_vertical"
129                     android:background="@drawable/ic_battery_10"/>
130 
131                 <TextView
132                     android:id="@+id/tv_sys_time"  //系统时间
133                     android:layout_width="wrap_content"
134                     android:layout_height="wrap_content"
135                     android:layout_gravity="center_vertical"
136                     android:layout_marginRight="@dimen/dimen_10dp"
137                     android:text="16:56"
138                     android:textColor="@color/white"
139                     android:textSize="@dimen/dimen_32sp"/>
140 
141 
142             </LinearLayout>
143 
144         </FrameLayout>
145 
146         <ImageView
147             android:id="@+id/iv_player_center_pause" //暂停的图标
148             android:layout_width="wrap_content"
149             android:layout_height="wrap_content"
150             android:background="@drawable/player_pause_selector"
151             android:layout_gravity="center"
152             android:visibility="gone"/>  //只有在暂停的时候才出现
153     </FrameLayout>
154 
155     <LinearLayout  //底部相关的panel
156         android:id="@+id/ll_player_bottom_layout"
157         android:layout_width="match_parent"
158         android:layout_height="@dimen/dimen_70dp"
159         android:orientation="horizontal"
160         android:layout_alignParentBottom="true"
161         android:background="@color/player_panel_background_color"
162         android:gravity="center">
163         
164                 <!--选中之后的某个状态的切换???-->
165         <CheckBox  
166             android:id="@+id/cb_play_pause"
167             android:layout_width="wrap_content"
168             android:layout_height="wrap_content"
169             android:layout_marginLeft="@dimen/dimen_26dp"
170             android:button="@drawable/player_playbtn_selector"
171             android:checked="true"/>
172 
173         <ImageView
174             android:id="@+id/iv_next_video"
175             android:layout_width="wrap_content"
176             android:layout_height="wrap_content"
177             android:layout_marginLeft="@dimen/dimen_10dp"
178             android:src="@drawable/panel_next_selector"/>
179 
180             <!--当前播放的时间-->
181         <TextView
182             android:id="@+id/tv_current_video_time"
183             android:layout_width="wrap_content"
184             android:layout_height="wrap_content"
185             android:layout_gravity="center_vertical"
186             android:text="03:00"
187             android:textColor="@color/white"
188             android:textSize="@dimen/dimen_20sp"/>
189 
190         <SeekBar
191             android:id="@+id/sb_player_seekbar"
192             android:layout_width="match_parent"
193             android:layout_height="wrap_content"
194             style="@style/playerSeekBarStyle"  //指定样式,其中使用到了drawable-list
195             android:layout_gravity="center_vertical"
196             android:layout_weight="1.0"
197             android:indeterminate="false"
198             android:max="100"
199             android:progress="0"
200             android:paddingRight="@dimen/dimen_10dp"
201             android:paddingLeft="@dimen/dimen_10dp"
202             android:thumbOffset="@dimen/dimen_10dp" />
203                 <!--视频总时间-->
204         <TextView
205             android:id="@+id/tv_total_video_time"
206             android:layout_width="wrap_content"
207             android:layout_height="wrap_content"
208             android:text="15:00"
209             android:textSize="@dimen/dimen_20sp"
210             android:textColor="@color/white"
211             android:layout_marginLeft="@dimen/dimen_10dp"/>
212 
213         <!--码流属性-->
214         <TextView
215             android:id="@+id/tv_bitstream"  
216             android:layout_width="wrap_content"
217             android:layout_height="wrap_content"
218             android:layout_marginLeft="@dimen/dimen_10dp"
219             android:text="高清"
220             android:textColor="@color/white"
221             android:textSize="@dimen/dimen_20sp"
222             android:layout_marginRight="@dimen/dimen_10dp"/>
223 
224     </LinearLayout>
225 </RelativeLayout>

9.上下panel的处理

9.1 初始化底部paneld布局

【PlayActivity.java】

 1 private void initTopAndBottomView() {
 2         mTopLayout = bindViewId(R.id.fl_player_top_container);
 3         mBottomLayout = bindViewId(R.id.ll_player_bottom_layout);
 4         mBackButton = bindViewId(R.id.iv_player_close);//返回按钮
 5         mVideoNameView = bindViewId(R.id.tv_player_video_name);//video标题
 6         mBatteryView = bindViewId(R.id.iv_battery);
 7         mSysTimeView = bindViewId(R.id.tv_sys_time);//系统时间
 8         mBigPauseButton = bindViewId(R.id.iv_player_center_pause);//屏幕中央暂停按钮
 9         mPlayOrPauseButton = bindViewId(R.id.cb_play_pause);//底部播放暂停按钮
10         mVideoCurrentTime = bindViewId(R.id.tv_current_video_time);//当前播放进度
11         mVideoTotalTime = bindViewId(R.id.tv_total_video_time);//视频总时长
12         mBitStreamView = bindViewId(R.id.tv_bitstream);//码流
13         mSeekBar = bindViewId(R.id.sb_player_seekbar);
14         mSeekBar.setMax(1000);
15         mSeekBar.setOnSeekBarChangeListener(mSeekBarChangeListener);
16         mFormatterBuilder = new StringBuilder();
17         mFormatter = new Formatter(mFormatterBuilder,Locale.getDefault());
18     }

 9.2 初始化listener

【说明】主要是对按钮事件的监听设置,此处遗留了handlePlayPause()方法

 1    private void initListener() {
 2         mBackButton.setOnClickListener(new View.OnClickListener() {
 3             @Override
 4             public void onClick(View v) {
 5                 finish();
 6             }
 7         });
 8         mBigPauseButton.setOnClickListener(new View.OnClickListener() {
 9             @Override
10             public void onClick(View v) {
11                 mVideoView.start();
12                 updatePlayPauseStatus(true);
13             }
14         });
15         mPlayOrPauseButton.setOnClickListener(new View.OnClickListener() {
16             @Override
17             public void onClick(View v) {
18                 handlePlayPause(); //处理pause事件
19             }
20         });
21     }

9.3 数据的初始化

【设置播放的视频的name】

1  @Override
2     protected void initData() {
3         Log.d(TAG, ">> initData mVideo=" + mVideo);
4         if (mVideo != null) {
5             Log.d(TAG, ">> initData mVideoName" + mVideo.getVideoName());
6             mVideoNameView.setText(mVideo.getVideoName());
7         }
8     }

9.4 系统时间的显示

【获取系统时间】属于java的基本知识

 1 package com.hejunlin.imooc_supervideo.utils;
 2 
 3 import java.text.SimpleDateFormat;
 4 import java.util.Date;
 5 
 6 public class DateUtils {
 7 
 8     public static String getCurrentTime() {
 9         SimpleDateFormat format = new SimpleDateFormat("HH:mm");
10         Date curDate = new Date(System.currentTimeMillis());
11         String str = format.format(curDate);
12         return str;
13     }
14 
15 }

【定义】常量

1     private static final int CHECK_TIME = 1;
2     private static final int CHECK_BATTERY = 2;
3     private static final int CHECK_PROGRESS = 3;

【定义handler】

 1 class EventHandler extends Handler {
 2         public EventHandler(Looper looper) {
 3             super(looper);
 4         }
 5 
 6         @Override
 7         public void handleMessage(Message msg) {
 8             super.handleMessage(msg);
 9             switch (msg.what) {
10                 case CHECK_TIME:
11                     runOnUiThread(new Runnable() {
12                         @Override
13                         public void run() {
14                             mSysTimeView.setText(DateUtils.getCurrentTime()); //设置时间
15                         }
16                     });
17                     break;36             }
37         }
38     }
1 @Override
2     protected void initView() {
3         ......
4         mEventHandler = new EventHandler(Looper.myLooper()); //EventHandler 的初始化
5         ......
6     }

9.5 显示/隐藏上下panel

1     private EventHandler mEventHandler;
2     private boolean mIsPanelShowing = false; //判断是否显示
3 private static final int AUTO_HIDE_TIME = 10000; //显示上下panle的时间
 1 /**
 2      * 开关是否显示上下panel
 3      */
 4     private void toggleTopAndBottomLayout() {
 5         if (mIsPanelShowing) {
 6             hideTopAndBottomLayout();
 7         } else {
 8             showTopAndBottomLayout();
 9             //先显示,没有任何操作,就5s后隐藏
10             mEventHandler.postDelayed(new Runnable() {
11                 @Override
12                 public void run() {
13                     hideTopAndBottomLayout();
14                 }
15             }, AUTO_HIDE_TIME);
16         }
17     }
18 

【上下panel调用的时机】

1     @Override
2     protected void initView() {
.....
3 toggleTopAndBottomLayout();
4 }

9.6 隐藏上下panel

 1 /**
 2      * 隐藏上下的panel
 3      */
 4     private void hideTopAndBottomLayout() {
 5         if (mIsDragging == true) {
 6             return;
 7         }
 8         mIsPanelShowing = false;
 9         mTopLayout.setVisibility(View.GONE);
10         mBottomLayout.setVisibility(View.GONE);
11     }

9.7 显示上下的panel-系统时间的显示

 1     /**
 2      * 显示上下的panel
 3      */
 4     private void showTopAndBottomLayout() {
 5         mIsPanelShowing = true;
 6         mTopLayout.setVisibility(View.VISIBLE);
 7         mBottomLayout.setVisibility(View.VISIBLE);
 8        
 9         if (mEventHandler != null) {
10             mEventHandler.removeMessages(CHECK_TIME); //先移除信息
11             Message msg = mEventHandler.obtainMessage(CHECK_TIME); 
12             mEventHandler.sendMessage(msg);//发送信息
13         }
14        
15     }
 1     class EventHandler extends Handler {
 2         public EventHandler(Looper looper) {
 3             super(looper);
 4         }
 5 
 6         @Override
 7         public void handleMessage(Message msg) {
 8             super.handleMessage(msg);
 9             switch (msg.what) {
10                 case CHECK_TIME:
11                     runOnUiThread(new Runnable() {
12                         @Override
13                         public void run() {
14                             mSysTimeView.setText(DateUtils.getCurrentTime());
15                         }
16                     });
17                     break;
18             }
19         }
20     }

9.8 电池电量的显示

【通过广播获取系统的电量】

 1   /**
 2      * 通过广播获取系统电量情况
 3      */
 4     private BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() {
 5         @Override
 6         public void onReceive(Context context, Intent intent) {
 7             mBatteryLevel = intent.getIntExtra("level", 0);
 8             Log.d(TAG, ">> mBatteryReceiver onReceive mBatteryLevel=" + mBatteryLevel);
 9         }
10     };

【注册广播】

1  @Override
2     protected void initView() {
3      ......
4       registerReceiver(mBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));  //注册获取系统电量的广播
5     .....
6 }

【注销广播】

 1     class EventHandler extends Handler {
 2         public EventHandler(Looper looper) {
 3             super(looper);
 4         }
 5 
 6   @Override
 7     protected void onPause() {
 8         super.onPause();
 9         if (mBatteryReceiver != null) {
10             unregisterReceiver(mBatteryReceiver);
11             mBatteryReceiver = null;
12         }
13     }

 【电量信息的发送】

 1     /**
 2      * 显示上下的panel
 3      */
 4     private void showTopAndBottomLayout() {
 5        
 6         if (mEventHandler != null) {     
 7             ......
 8             mEventHandler.removeMessages(CHECK_BATTERY);
 9             Message batterymsg = mEventHandler.obtainMessage(CHECK_BATTERY);
10             mEventHandler.sendMessage(batterymsg);
11             ......
12         }
13     }

 

【电量信息的设置】

 1  class EventHandler extends Handler {
 2         public EventHandler(Looper looper) {
 3             super(looper);
 4         }
 5 
 6         @Override
 7         public void handleMessage(Message msg) {
 8             super.handleMessage(msg);
 9             switch (msg.what) {
10                 ......
11                 case CHECK_BATTERY:
12                     runOnUiThread(new Runnable() {
13                         @Override
14                         public void run() {
15                             setCurrentBattery();
16                         }
17                     });
18                     break;
19                ......
20             }
21         }
22     }

 

【设置】

 1  /**
 2      * 根据不同的电量的状态设置不同的drawable文件夹下的图片
 3      */
 4     private void setCurrentBattery() {
 5         Log.d(TAG, ">> setCurrentBattery level " + mBatteryLevel);
 6         if ( 0 < mBatteryLevel && mBatteryLevel <= 10) {
 7             mBatteryView.setBackgroundResource(R.drawable.ic_battery_10);
 8         } else if (10 < mBatteryLevel && mBatteryLevel <= 20) {
 9             mBatteryView.setBackgroundResource(R.drawable.ic_battery_20);
10         } else if (20 < mBatteryLevel && mBatteryLevel <= 50) {
11             mBatteryView.setBackgroundResource(R.drawable.ic_battery_50);
12         } else if (50 < mBatteryLevel && mBatteryLevel <= 80) {
13             mBatteryView.setBackgroundResource(R.drawable.ic_battery_80);
14         } else if (80 < mBatteryLevel && mBatteryLevel <= 100) {
15             mBatteryView.setBackgroundResource(R.drawable.ic_battery_100);
16         }
17     }

9.9 video 标题的设置

【标题的设置】

1 @Override
2     protected void initData() {
3         Log.d(TAG, ">> initData mVideo=" + mVideo);
4         if (mVideo != null) {
5             Log.d(TAG, ">> initData mVideoName" + mVideo.getVideoName());
6             mVideoNameView.setText(mVideo.getVideoName());
7         }
8  }

【标题的获取】从网络的json数据获取并设置,分为两个路径,一个是letv,一个是sohu

【letv】

 1  //取video相关信息
 2     public void onGetVideo(final Album album, int pageSize, int pageNo, final OnGetVideoListener listener) {
 3         final String url = String.format(ALBUM_VIDEOS_URL_FORMAT, album.getAlbumId(), pageNo, pageSize, "-1", "1");
 4         OkHttpUtils.excute(url, new Callback() {
 5         ....
 6          @Override
 7             public void onResponse(Call call, Response response) throws IOException {
 8             ......
 9             //videoInfo表示每个视频info
10                                     JSONObject videoInfo = jsonArray.getJSONObject(i);
11                                     video.setAid(Long.parseLong(album.getAlbumId()));
12                                     video.setSite(album.getSite().getSiteId());
13                                     //nameCn: "择天记03"
14                                     if (!TextUtils.isEmpty(videoInfo.optString("nameCn"))) {  //信息获取的设置
15                                         video.setVideoName(videoInfo.optString("nameCn"));
16                                     }
17                                     //mid: "64271196" 表示解释乐视视频源需要的
18                                     if (!TextUtils.isEmpty(videoInfo.optString("mid"))) {
19                                         video.setMid(Long.parseLong(videoInfo.optString("mid")));
20                                     }
21                                     if (!TextUtils.isEmpty(videoInfo.optString("id"))) {
22                                         video.setVid(Long.parseLong(videoInfo.optString("id")));
23                                     }
24                                     videoList.add(video);
25                                 }

9.10 码流的设置

【码流的获取】从哪里获取的???从上一个页面的设置的type中获取的;

1     @Override
2     protected void initView() {
3         mUrl = getIntent().getStringExtra("url");
4         mLiveTitle = getIntent().getStringExtra("title");
5         mStreamType = getIntent().getIntExtra("type", 0); //获取码流的类型
6         mCurrentPosition = getIntent().getIntExtra("currentPosition", 0);
7         mVideo = getIntent().getParcelableExtra("video");

【码流的设置】

 1  /**
 2      * 显示上下的panel
 3      */
 4     private void showTopAndBottomLayout() {
 5         ......
 6         switch (mStreamType) {
 7             case AlbumDetailActivity.StreamType.SUPER:
 8                 mBitStreamView.setText(getResources().getString(R.string.stream_super));//超清
 9                 break;
10             case AlbumDetailActivity.StreamType.NORMAL:
11                 mBitStreamView.setText(getResources().getString(R.string.stream_normal));//标清
12                 break;
13             case AlbumDetailActivity.StreamType.HIGH:
14                 mBitStreamView.setText(getResources().getString(R.string.stream_high));//高清
15                 break;
16             default:
17                 break;
18         }
19         ......
20     }

9.11 播放/暂停

 1  @Override
 2     protected void initView() {
 3     ......
 4     mVideoView.setOnPreparedListener(new IMediaPlayer.OnPreparedListener() {
 5             @Override
 6             public void onPrepared(IMediaPlayer mp) {
 7                 mVideoView.start(); //开始播放
 8             }
 9         });
10         .....
11    }
 1 private void initListener() {
 2         ......
 3         mBigPauseButton.setOnClickListener(new View.OnClickListener() {
 4             @Override
 5             public void onClick(View v) {
 6                 mVideoView.start();// 暂停按键再次按下的时候,开始播放
 7                 updatePlayPauseStatus(true); //更新按键的显示
 8             }
 9         });
10         mPlayOrPauseButton.setOnClickListener(new View.OnClickListener() {
11             @Override
12             public void onClick(View v) {
13                 handlePlayPause(); //处理pause事件
14             }
15         });
16     }
17     
18 
19 private void updatePlayPauseStatus(boolean isPlaying) {
20         mBigPauseButton.setVisibility(isPlaying ? View.GONE : View.VISIBLE);
21         mPlayOrPauseButton.invalidate(); // 重绘
22         mPlayOrPauseButton.setChecked(isPlaying);    //图标切换为选中
23         mPlayOrPauseButton.refreshDrawableState(); //更新drable的状态
24     }
25     
26 
27     private void handlePlayPause() {
28         if (mVideoView.isPlaying()) {//视频正在播放
29             mVideoView.pause();
30             updatePlayPauseStatus(false);
31         } else {
32             mVideoView.start();
33             updatePlayPauseStatus(true);
34         }
35     }

9.11 视频拖拽功能

【说明】从服务器获取的时间格式需要重新格式化,使用到javaUtils中的Formatter 

1     private SeekBar mSeekBar;
2     private Formatter mFormatter;  //直接从服务器获取的
3     private StringBuilder mFormatterBuilder; //字符的拼接

 【seekBar的初始化】

1  private void initTopAndBottomView() {
2        ......
3         mSeekBar = bindViewId(R.id.sb_player_seekbar);
4         mSeekBar.setMax(1000);
5         mSeekBar.setOnSeekBarChangeListener(mSeekBarChangeListener);
6         mFormatterBuilder = new StringBuilder();
7         mFormatter = new Formatter(mFormatterBuilder,Locale.getDefault());
8         ......
9     }

 【seekBar的状态的监听】

 1 private SeekBar.OnSeekBarChangeListener mSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
 2         // seekbar进度发生变化时回调
 3         @Override
 4         public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
 5             if (!fromUser) {
 6                 return;
 7             }
 8             long duration = mVideoView.getDuration();//视频时长
 9             long nowPosition = (duration * progress) / 1000L;
10             mVideoCurrentTime.setText(stringForTime((int) nowPosition));  //需要专门的时间的格式转化
11         }
12 
13         // seekbar开始拖动时回调
14         @Override
15         public void onStartTrackingTouch(SeekBar seekBar) {
16             mIsDragging = true; //显示panel
17         }
18 
19         // seekbar拖动完成后回调
20         @Override
21         public void onStopTrackingTouch(SeekBar seekBar) {
22             mIsDragging = false;
23             int progress = seekBar.getProgress();//最后拖动停止的进度
24             long duration = mVideoView.getDuration();//视频时长
25             long newPosition = (duration * progress) / 1000L;//当前的进度
26             mVideoView.seekTo((int) newPosition); //视频跳转到对应的视频位置
27             mEventHandler.postDelayed(new Runnable() {
28                 @Override
29                 public void run() {
30                     hideTopAndBottomLayout(); //视频seek到指定的进度值之后,panel在3秒后消失
31                 }
32             },AFTER_DRAGGLE_HIDE_TIME);
33         }
34     };

 【时间格式的转换】

 1  private String stringForTime(int timeMs) {
 2         int totalSeconds = timeMs / 1000;
 3         int seconds = totalSeconds % 60; //换成秒
 4         int minutes = (totalSeconds / 60) % 60;
 5         int hours = (totalSeconds / 3600);
 6         mFormatterBuilder.setLength(0);
 7         if (hours > 0) {
 8             return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString();
 9         } else {
10             return mFormatter.format("%02d:%02d", minutes, seconds).toString();
11         }
12     }

 【进度的时机】

 1  /**
 2      * 显示上下的panel
 3      */
 4     private void showTopAndBottomLayout() {
 5         ......
 6         mBottomLayout.setVisibility(View.VISIBLE);
 7         updateProgress();  //在panel更新进度
 8         if (mEventHandler != null) {
 9             mEventHandler.removeMessages(CHECK_TIME);
10             Message msg = mEventHandler.obtainMessage(CHECK_TIME);
11             ......

【更新进度】

 1 private void updateProgress() {
 2         int currentPosition = mVideoView.getCurrentPosition();//当前的视频位置
 3         int duration = mVideoView.getDuration();//视频时长
 4         if (mSeekBar != null) {
 5             if (duration > 0) {
 6                 //转成long型,避免溢出
 7                 long pos = currentPosition * 1000L/ duration;
 8                 mSeekBar.setProgress((int) pos);
 9             }
10             int perent = mVideoView.getBufferPercentage();//已经缓冲的进度
11             mSeekBar.setSecondaryProgress(perent);//设置缓冲进度
12             mVideoCurrentTime.setText(stringForTime(currentPosition));
13             mVideoTotalTime.setText(stringForTime(duration));
14         }
15     }

【实时监测视频的位置】

 1      class EventHandler extends Handler {
 2         public EventHandler(Looper looper) {
 3             super(looper);
 4         }
 5 
 6         @Override
 7         public void handleMessage(Message msg) {
 8             super.handleMessage(msg);
 9             switch (msg.what) {
10                ......
11                 case CHECK_PROGRESS:
12                     runOnUiThread(new Runnable() {
13                         @Override
14                         public void run() {
15                             long duration = mVideoView.getDuration();
16                             long nowduration = (mSeekBar.getProgress() * duration)/1000L;
17                             mVideoCurrentTime.setText(stringForTime((int)nowduration));
18                         }
19                     });
20                     break;
21             }
22         }
23     }
24         

 【进度的监测】在显示panel时进行progress的检测

 1     /**
 2      * 显示上下的panel
 3      */
 4     private void showTopAndBottomLayout() {
 5         ......
 6         if (mEventHandler != null) {
 7             mEventHandler.removeMessages(CHECK_PROGRESS);
 8             Message progressmsg = mEventHandler.obtainMessage(CHECK_PROGRESS);
 9             mEventHandler.sendMessage(progressmsg);
10         }
11        ......
12     }

10. 视频手势相关的操作

10.1 GestureDetector 类的实现

【说明】新建一个类:GestureDetector.OnGestureListener,并overide一系列的方法

 1 public class GestureDetectorController implements GestureDetector.OnGestureListener {
 2 
 3     private static final String TAG = GestureDetectorController.class.getSimpleName();
 4     private GestureDetector mGestureDetector;
 5     private IGestureListener mGestureListener;
 6     private int mWidth;
 7     private ScrollType mCurrentType;
 8 
 9     public GestureDetectorController(Context context, IGestureListener listener) {
10         /**
11         * 需要判断坐标值,因此需要知道屏幕的宽度
12         */
13         mWidth = context.getResources().getDisplayMetrics().widthPixels;
14         mGestureListener = listener;
15         mGestureDetector = new GestureDetector(context, this);
16     }
17 
18     ......
19     /**
20     * 手指滑动的类型
21     */
22      public enum ScrollType {
23         NOTHING, //滑动无操作
24         VERTICAL_LEFT,  //左半边竖滑亮度
25         VERTICAL_RIGH, //右半边竖滑音量
26         HORIZONTAL //水平滑动,seek进度调整
27     }
28 
29 
30     public interface IGestureListener {
31         void onScrollStart(ScrollType type);//开始滑动
32         void onScrollHorizontal(float x1, float x2);//水平滑动
33         void onScrollVerticalLeft(float y1, float y2);//左滑
34         void onScrollVerticalRight(float y1, float y2);//右滑
35     }
36 }

 

【其他动作的处理】

 1  //在按下的时候设置类型为无动作响应
 2   @Override
 3     public boolean onDown(MotionEvent e) {
 4         mCurrentType = NOTHING;
 5         return true;
 6     }
 7 
 8     @Override
 9     public void onShowPress(MotionEvent e) {
10 
11     }
12 
13     @Override
14     public boolean onSingleTapUp(MotionEvent e) {
15         return false;
16     }
17 
18     @Override
19     public void onLongPress(MotionEvent e) {
20 
21     }
22 
23     @Override
24     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
25         return true; // 返回true
26     }

 

【滑动相关的参数的传递】

【1】滑动的类型的设置

【2】位置坐标的传递

 1   @Override
 2     public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
 3         if (mGestureListener != null) {
 4             if (mCurrentType != NOTHING) {
 5                 switch (mCurrentType) {
 6                     case VERTICAL_LEFT:
 7                         mGestureListener.onScrollVerticalLeft(distanceY, e1.getY() - e2.getY());
 8                         break;
 9                     case VERTICAL_RIGH:
10                         mGestureListener.onScrollVerticalRight(distanceY, e1.getY() - e2.getY());
11                         break;
12                     case HORIZONTAL:
13                         mGestureListener.onScrollHorizontal(distanceX, e2.getX() - e1.getX());
14                         break;
15                 }
16                 return false;
17             }
18         }
19         //水平方向上滑动判断
20         if (Math.abs(distanceY) <= Math.abs(distanceX)) {
21             mCurrentType = ScrollType.HORIZONTAL;
22             mGestureListener.onScrollStart(mCurrentType);
23             return false;
24         }
25 
26         //将屏幕分为1/3判断
27         int i = mWidth / 3;
28         //左滑判断
29         if (e1.getX() <= i) {
30             mCurrentType = ScrollType.VERTICAL_LEFT;
31             mGestureListener.onScrollStart(mCurrentType);
32         } else if (e1.getX() > i*2) {//右滑判断
33             mCurrentType = ScrollType.VERTICAL_RIGH;
34             mGestureListener.onScrollStart(mCurrentType);
35         } else {
36             mCurrentType = NOTHING;
37         }
38         return false;
39     }

 

10.2 GestureDetector 类的使用

【实现接口并复写方法】

1 public class PlayActivity extends BaseActivity implements GestureDetectorController.IGestureListener{
2 
3     private static final String TAG = PlayActivity.class.getSimpleName();
4     private static final int CHECK_TIME = 1;

 

【初始化GestureDetector 

1 private void initGesture() {
2         mGestureController = new GestureDetectorController(this, this);
3     }

 

【布局当中添加信息的显示】音量的改变的大小值,亮度改变的大小值等等

 1  <TextView
 2             android:id="@+id/tv_horiontal_gesture"
 3             android:layout_width="match_parent"
 4             android:layout_height="wrap_content"
 5             android:shadowDx="1.0"
 6             android:shadowDy="1.0"
 7             android:shadowColor="@color/black"
 8             android:textColor="@color/white"
 9             android:textSize="@dimen/dimen_64sp"
10             android:visibility="gone"
11             android:textStyle="bold"
12             android:gravity="center"/>
13 
14         <TextView
15             android:id="@+id/tv_vertical_gesture"
16             android:layout_width="wrap_content"
17             android:layout_height="wrap_content"
18             android:layout_gravity="center"
19             android:gravity="center_horizontal"
20             android:background="@drawable/black_bg"
21             android:paddingLeft="@dimen/dimen_100dp"
22             android:paddingRight="@dimen/dimen_100dp"
23             android:paddingTop="@dimen/dimen_40dp"
24             android:paddingBottom="@dimen/dimen_40dp"
25             android:textSize="@dimen/dimen_64sp"
26             android:textStyle="bold"
27             android:textColor="@color/white"
28             android:visibility="gone"/>

 

10.3 水平滑动的初始响应

【常用变量的定义】此处省略了TextView滑动信息显示的控件的查找

 1     private GestureDetectorController mGestureController;
 2     private TextView mDragHorizontalView;
 3     private TextView mDragVerticalView;
 4     private long mScrollProgress;  //滑动的进度值
 5     private boolean mIsHorizontalScroll;  //标识是否为水平滑动
 6     private boolean mIsVerticalScroll; //标识是否为竖直滑动
 7     private int mCurrentLight; 
 8     private int mMaxLight = 255;
 9     private int mCurrentVolume;
10     private int mMaxVolume = 10

 

【水平滑动的响应】

 1 @Override
 2     public void onScrollStart(GestureDetectorController.ScrollType type) {
 3         mIsMove = true; //是否在屏幕上滑动
 4         ......
 5         switch (type) {
 6             case HORIZONTAL:
 7                 mDragHorizontalView.setVisibility(View.VISIBLE);
 8                 mScrollProgress = -1;
 9                 mIsHorizontalScroll = true;//水平滑动标识
10                 break;
11            ......
12         }
13     }

 

10.4 左半边部分区域的初始响应

【组合图片和文字】

1     //用于组合图片及文字
2     private void setComposeDrawableAndText(TextView textView, int drawableId, Context context) {
3         Drawable drawable = context.getResources().getDrawable(drawableId);
4         //这四个参数表示把drawable绘制在矩形区域
5         drawable.setBounds(0,0, drawable.getMinimumWidth(), drawable.getMinimumHeight());
6         //设置图片在文字的上方
7         //The Drawables must already have had drawable.setBounds called.
8         textView.setCompoundDrawables(null, drawable, null , null);
9     }

 

【更新亮度TextView】需要转化为百分比的显示

1 //更新垂直方向上滑动时的百分比
2     private void updateVerticalText(int current, int total) {
3         NumberFormat formater = NumberFormat.getPercentInstance();
4         formater.setMaximumFractionDigits(0);//设置整数部分允许最大小数位 66.5%->66%
5         String percent = formater.format((double)(current)/(double) total);
6         mDragVerticalView.setText(percent);
7     }

 

 【左半边部分区域的垂直的动作的响应】

 1 @Override
 2     public void onScrollStart(GestureDetectorController.ScrollType type) {
 3         mIsMove = true;
 4         switch (type) {
 5             ......
 6             case VERTICAL_LEFT:
 7                 setComposeDrawableAndText(mDragVerticalView, R.drawable.ic_light, this);
 8                 mDragVerticalView.setVisibility(View.VISIBLE);
 9                 updateVerticalText(mCurrentLight, mMaxLight);
10                 mIsVerticalScroll = true;
11                 break;
12             ......
13     }

 

10.5 右半边部分区域的初始响应

 1 @Override
 2     public void onScrollStart(GestureDetectorController.ScrollType type) {
 3         mIsMove = true;
 4         switch (type) {
 5            ......
 6             case VERTICAL_RIGH:
 7                 if (mCurrentVolume > 0) {
 8                     setComposeDrawableAndText(mDragVerticalView, R.drawable.volume_normal, this);
 9                 } else {
10                     setComposeDrawableAndText(mDragVerticalView, R.drawable.volume_no, this);
11                 }
12                 mDragVerticalView.setVisibility(View.VISIBLE);
13                 updateVerticalText(mCurrentVolume, mMaxVolume);
14                 mIsVerticalScroll = true;
15                 break;
16         }
17         ......
18     }

 

10.6 屏幕左半边垂直滑动更新系统的亮度

【系统获取的亮度值变量】默认值是系统的值,即使获取出来也是一样的。

1     private int mMaxLight = 255;
2     private int mCurrentVolume;
3     private int mMaxVolume = 10;

 

【更新系统的亮度】

 1 @Override
 2     public void onScrollVerticalLeft(float y1, float y2) {
 3         int height = getResources().getDisplayMetrics().heightPixels;
 4         int offset = (int) (mMaxLight * y1)/ height;
 5         if (Math.abs(offset) > 0) {
 6             mCurrentLight += offset;//得到变化后的亮度
 7             mCurrentLight = Math.max(0, Math.min(mMaxLight, mCurrentLight));
 8             // 更新系统亮度
 9             SysUtils.setBrightness(this, mCurrentLight);
10             SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit();
11             editor.putInt("shared_preferences_light", mCurrentLight);
12             editor.commit();
13             updateVerticalText(mCurrentLight, mMaxLight);
14         }
15     }

 

SysUtils类

 1 public class SysUtils {
 2 
 3     //获取亮度
 4     public static int getBrightness(Context context) {
 5         return Settings.System.getInt(context.getContentResolver(),"screen_brightness", -1);
 6     }
 7     //设置亮度
 8     public static void setBrightness(Context context, int param) {
 9         Settings.System.putInt(context.getContentResolver(), "screen_brightness", param);
10     }
11     //获取亮度的sharedPreferences文件--系统默认的信息保存文件
12     public static int getDefaultBrightness(Context context) {
13         return PreferenceManager.getDefaultSharedPreferences(context).getInt("shared_preferences_light", -1);
14     }
15 
16 }

 

【亮度的初始化】

1 private void initLight() {
2         mCurrentLight = SysUtils.getDefaultBrightness(this);
3         if (mCurrentLight == -1) {//获取不到亮度sharedpreferences文件
4             mCurrentLight = SysUtils.getBrightness(this);
5         }
6     }

 

10.7 屏幕右半边垂直滑动更新系统的音量

屏幕右半边垂直滑动的参数的设置

 1  @Override
 2     public void onScrollVerticalRight(float y1, float y2) {
 3         int height = getResources().getDisplayMetrics().heightPixels;
 4         int offset = (int) (mMaxVolume * y1)/ height;
 5         if (Math.abs(offset) > 0) {
 6             mCurrentVolume += offset;//得到变化后的声音
 7             mCurrentVolume = Math.max(0, Math.min(mMaxVolume, mCurrentVolume));
 8             // 更新系统声音
 9             mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, mCurrentVolume/10, 0);
10             updateVerticalText(mCurrentVolume, mMaxVolume);
11         }
12     }

 

【初始化音量 】

1 private void initAudio() {
2         mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
3         setVolumeControlStream(AudioManager.STREAM_MUSIC);
4         mAudioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
5         mMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) * 10;// 系统声音取值是0-10,*10为了和百分比相关
6         mCurrentVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC) * 10;
7     }

 

【释放声音abandonAudioFocus

 1  @Override
 2     protected void onPause() {
 3         super.onPause();
 4         if (mBatteryReceiver != null) {
 5             unregisterReceiver(mBatteryReceiver);
 6             mBatteryReceiver = null;
 7         }
 8         //释放audiofocus
 9         mAudioManager.abandonAudioFocus(null);
10     }

 

10.8 水平方向滑动更新进度

【水平方向滑动动作】

 1  // 更新进度
 2     @Override
 3     public void onScrollHorizontal(float x1, float x2) {
 4         int width = getResources().getDisplayMetrics().widthPixels;
 5         int MAX_SEEK_STEP = 300000;//最大滑动5分钟
 6         int offset = (int) (x2 / width * MAX_SEEK_STEP) + mVideoView.getCurrentPosition();
 7         long progress = Math.max(0, Math.min(mVideoView.getDuration(), offset));
 8         mScrollProgress = progress;
 9         updateHorizontalText(progress);
10     }

 

updateHorizontalText

1  //更新水平方向seek的进度, duration表示变化后的duration
2     private void updateHorizontalText(long duration) {
3         String text = stringForTime((int)duration) + "/" + stringForTime(mVideoView.getDuration());
4         mDragHorizontalView.setText(text);
5     }

 

10.9 TouchEvent事件的处理

 1 @Override
 2     public boolean onTouchEvent(MotionEvent event) {
 3         if (event.getAction() == MotionEvent.ACTION_UP) {
 4             if (mIsMove == false) {
 5                 toggleTopAndBottomLayout();
 6             } else {
 7                 mIsMove = false;
 8             }
 9             //水平方向,up时,seek到对应位置播放
10             if (mIsHorizontalScroll) {
11                 mIsHorizontalScroll = false;
12                 mVideoView.seekTo((int)mScrollProgress);
13                 //一次down,up结束后mDragHorizontalView隐藏
14                 mDragHorizontalView.setVisibility(View.GONE);
15             }
16             if (mIsVerticalScroll) {
17                 mDragVerticalView.setVisibility(View.GONE);
18                 mIsVerticalScroll = false;
19             }
20         }
21         return mGestureController.onTouchEvent(event);
22     }
posted @ 2018-07-16 19:22  OzTaking  阅读(683)  评论(0)    收藏  举报