主布局:
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 xmlns:app="http://schemas.android.com/apk/res-auto" 5 xmlns:tools="http://schemas.android.com/tools" 6 android:layout_width="match_parent" 7 android:layout_height="match_parent" 8 tools:context="net.bwie.surfaceviewvideolist.MainActivity"> 9 10 <android.support.v7.widget.RecyclerView 11 android:id="@+id/recycler_view" 12 android:layout_width="match_parent" 13 android:layout_height="match_parent" 14 app:layoutManager="android.support.v7.widget.LinearLayoutManager"/> 15 16 </RelativeLayout>
主布局的Item:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="wrap_content" 5 android:orientation="vertical"> 6 7 <TextView 8 android:id="@+id/progress_tv" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 11 android:text="当前进度"/> 12 13 <Button 14 android:id="@+id/play_btn" 15 android:layout_width="wrap_content" 16 android:layout_height="wrap_content" 17 android:text="播放"/> 18 19 <TextView 20 android:id="@+id/title_tv" 21 android:layout_width="wrap_content" 22 android:layout_height="wrap_content" 23 android:text="标题"/> 24 25 <net.bwie.surfaceviewvideolist.widget.VideoSurfaceView 26 android:id="@+id/video_view" 27 android:layout_width="match_parent" 28 android:layout_height="200dp" 29 android:layout_gravity="center_horizontal"/> 30 31 </LinearLayout>
主界面Activity:
1 /** 2 * 1、封装播放视频的SurfaceView 3 * 2、网络请求数据(手写bean):bean、httpservice 4 * 3、放在RecyclerView中展示 5 * 4、item中放入SurfaceView 6 * 5、点击播放弹出通知 7 * 6、进度 8 */ 9 public class MainActivity extends AppCompatActivity implements Callback<KaiyanBean> { 10 11 protected RecyclerView mRecyclerView; 12 private Object mData; 13 14 @Override 15 protected void onCreate(Bundle savedInstanceState) { 16 super.onCreate(savedInstanceState); 17 super.setContentView(R.layout.activity_main); 18 initView(); 19 20 initData(); 21 } 22 23 private void initData() { 24 Retrofit retrofit = new Retrofit.Builder() 25 .baseUrl("http://baobab.kaiyanapp.com/") 26 .addConverterFactory(GsonConverterFactory.create()).build(); 27 28 retrofit.create(KaiyanHttpService.class) 29 .getKaiyanCall() 30 .enqueue(this); 31 } 32 33 private void initView() { 34 mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view); 35 } 36 37 @Override 38 public void onResponse(Call<KaiyanBean> call, Response<KaiyanBean> response) { 39 KaiyanBean kaiyanBean = response.body(); 40 41 List<VideoBean> videoList = new ArrayList<>(); 42 43 for (KaiyanBean.ItemBean itemBean : kaiyanBean.getItemList()) { 44 Log.d("1507","type: " + itemBean.getType()+ ", title : " + itemBean.getData().getTitle() + "url : " + itemBean.getData().getPlayUrl()); 45 46 if ("video".equals(itemBean.getType())) { 47 // 过滤掉type不为video的数据 48 VideoBean videoBean = new VideoBean(itemBean.getData().getTitle(), itemBean.getData().getPlayUrl()); 49 videoList.add(videoBean); 50 } 51 52 } 53 54 VideoListAdapter adapter = new VideoListAdapter(this, videoList); 55 mRecyclerView.setAdapter(adapter); 56 } 57 58 @Override 59 public void onFailure(Call<KaiyanBean> call, Throwable t) { 60 61 } 62 }
Bean:
1 package net.bwie.surfaceviewvideolist.bean; 2 3 import java.util.List; 4 5 public class KaiyanBean { 6 7 private List<ItemBean> itemList; 8 9 public List<ItemBean> getItemList() { 10 return itemList; 11 } 12 13 public void setItemList(List<ItemBean> itemList) { 14 this.itemList = itemList; 15 } 16 17 public static class ItemBean { 18 public String getType() { 19 return type; 20 } 21 22 public void setType(String type) { 23 this.type = type; 24 } 25 26 private String type; 27 private DataBean data; 28 29 public DataBean getData() { 30 return data; 31 } 32 33 public void setData(DataBean data) { 34 this.data = data; 35 } 36 37 public static class DataBean { 38 39 private String title; 40 private String playUrl; 41 42 public String getTitle() { 43 return title; 44 } 45 46 public void setTitle(String title) { 47 this.title = title; 48 } 49 50 public String getPlayUrl() { 51 return playUrl; 52 } 53 54 public void setPlayUrl(String playUrl) { 55 this.playUrl = playUrl; 56 } 57 } 58 59 } 60 61 }
1 package net.bwie.surfaceviewvideolist.bean; 2 3 public class VideoBean { 4 5 private String title; 6 private String playUrl; 7 8 public VideoBean(String title, String playUrl) { 9 this.title = title; 10 this.playUrl = playUrl; 11 } 12 13 public String getTitle() { 14 return title; 15 } 16 17 public void setTitle(String title) { 18 this.title = title; 19 } 20 21 public String getPlayUrl() { 22 return playUrl; 23 } 24 25 public void setPlayUrl(String playUrl) { 26 this.playUrl = playUrl; 27 } 28 }
Http:
1 package net.bwie.surfaceviewvideolist.httpservice; 2 3 import net.bwie.surfaceviewvideolist.bean.KaiyanBean; 4 5 import retrofit2.Call; 6 import retrofit2.http.GET; 7 8 public interface KaiyanHttpService { 9 10 @GET("api/v4/tabs/selected?udid=11111&vc=168&vn=3.3.1&deviceModel=Huawei%36&first_channel=eyepetizer_baidu_market&last_channel=eyepetizer_baidu_market&system_version_code=20") 11 Call<KaiyanBean> getKaiyanCall(); 12 13 }
封装类:
1 /** 2 * 能播放视频的SurfaceView,封装MediaPlayer 3 * 提供一个public方法用于设置播放路径和播放的方法 4 */ 5 public class VideoSurfaceView extends SurfaceView implements SurfaceHolder.Callback, MediaPlayer.OnPreparedListener { 6 private SurfaceHolder mHolder; 7 private MediaPlayer mMediaPlayer; 8 9 public VideoSurfaceView(Context context, AttributeSet attrs) { 10 super(context, attrs); 11 12 init(); 13 } 14 15 private void init() { 16 // 获得缓冲区持有者 17 mHolder = getHolder(); 18 // 设置生命周期的回调 19 mHolder.addCallback(this); 20 } 21 22 // 设置播放路径并播放 23 public void playVideo(String path) { 24 if (mMediaPlayer == null) { 25 mMediaPlayer = new MediaPlayer(); 26 // 准备完毕监听器 27 mMediaPlayer.setOnPreparedListener(this); 28 } 29 30 try { 31 // 重置MediaPlayer 32 mMediaPlayer.reset(); 33 // 设置画面播放源 34 mMediaPlayer.setDisplay(mHolder); 35 // 设置播放源 36 mMediaPlayer.setDataSource(path); 37 // 准备播放 38 mMediaPlayer.prepareAsync(); 39 } catch (Exception e) { 40 e.printStackTrace(); 41 Log.e("1507", e.getMessage()); 42 } 43 44 } 45 46 // 停止播放 47 public void stop() { 48 if (mMediaPlayer != null) { 49 mMediaPlayer.stop(); 50 } 51 } 52 53 @Override 54 public void surfaceCreated(SurfaceHolder holder) { 55 56 } 57 58 @Override 59 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 60 61 } 62 63 @Override 64 public void surfaceDestroyed(SurfaceHolder holder) { 65 if (mMediaPlayer != null) { 66 mMediaPlayer.release();// 释放资源 67 mMediaPlayer = null; 68 } 69 } 70 71 @Override 72 public void onPrepared(MediaPlayer mp) { 73 mMediaPlayer.start(); 74 } 75 }
Adapter:
1 public class VideoListAdapter extends RecyclerView.Adapter<VideoListAdapter.ViewHolder> { 2 3 private Context mContext; 4 private List<VideoBean> mDatas; 5 6 // 记录上一次播放的VideoView 7 private VideoSurfaceView mPlayingView; 8 9 public VideoListAdapter(Context context, List<VideoBean> datas) { 10 mContext = context; 11 mDatas = datas; 12 } 13 14 @Override 15 public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 16 View itemView = LayoutInflater.from(mContext) 17 .inflate(R.layout.item_video, parent, false); 18 return new ViewHolder(itemView); 19 } 20 21 @Override 22 public void onBindViewHolder(final ViewHolder holder, int position) { 23 final VideoBean videoBean = mDatas.get(position); 24 25 holder.mTitleTextView.setText(videoBean.getTitle()); 26 27 // item刚复用进入屏幕时,无论是否播放都停止并隐藏 28 holder.mSurfaceView.stop(); 29 holder.mSurfaceView.setVisibility(View.INVISIBLE); 30 31 holder.mPlayBtn.setOnClickListener(new View.OnClickListener() { 32 @Override 33 public void onClick(View v) { 34 35 // 下一次播放时,停止上一次播放 36 if (mPlayingView != null) { 37 mPlayingView.stop(); 38 mPlayingView.setVisibility(View.INVISIBLE); 39 } 40 41 // 播放当前位置的视频 42 holder.mSurfaceView.setVisibility(View.VISIBLE);// 显示 43 holder.mSurfaceView.playVideo(videoBean.getPlayUrl()); 44 45 mPlayingView = holder.mSurfaceView; 46 } 47 }); 48 } 49 50 @Override 51 public int getItemCount() { 52 return mDatas == null ? 0 : mDatas.size(); 53 } 54 55 static class ViewHolder extends RecyclerView.ViewHolder { 56 57 Button mPlayBtn; 58 TextView mTitleTextView; 59 TextView mProgressTextView; 60 VideoSurfaceView mSurfaceView; 61 62 public ViewHolder(View itemView) { 63 super(itemView); 64 65 mPlayBtn = ((Button) itemView.findViewById(R.id.play_btn)); 66 mTitleTextView = ((TextView) itemView.findViewById(R.id.title_tv)); 67 mProgressTextView = ((TextView) itemView.findViewById(R.id.progress_tv)); 68 mSurfaceView = ((VideoSurfaceView) itemView.findViewById(R.id.video_view)); 69 } 70 } 71 72 }
别忘了加权限:
1 <uses-permission android:name="android.permission.INTERNET"/>
2 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
导包:
1 compile 'com.android.support:recyclerview-v7:26.0.0-alpha1'
2 compile 'com.squareup.retrofit2:converter-gson:2.3.0'
3 compile 'com.squareup.okhttp3:okhttp:3.9.0'
4 compile 'com.github.bumptech.glide:glide:3.8.0'