首先,要做一个本地视频播放器,需要克服的第一个困难就是遍历一下本地所有的视频文件:
刚开始的时候我用的是下面的方法去遍历
Cursor cursor=getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,null, null ,null,null); if(cursor!=null&&cursor.moveToFirst()){ do{ TextView textView=(TextView)findViewById(R.id.textView); // textView.setText(cursor.getString(1)); count++;//统计视频个数 }while (cursor.moveToNext()); } cursor.close(); Toast.makeText(this,String.valueOf(count),Toast.LENGTH_LONG).show();
非常简单,就是利用了contentprovided的MediaStore方法去找,但是后来发现蛋疼,明明有很多视频,遍历出来只有2个,后来查资料才知道,无法识别.rmvb格式的视频。然后就只能用下面的方法了:(扫描sd卡下全部的视频文件)
package com.example.admin.materialdesign; import android.app.ProgressDialog; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.media.MediaMetadataRetriever; import android.media.MediaPlayer; import android.net.Uri; import android.os.AsyncTask; import android.os.Environment; import android.provider.MediaStore; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import android.widget.VideoView; import java.io.EOFException; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.ArrayList; import java.util.List; import list_been.VideoInfo; import list_been.Video_recycler_been; public class Main2Activity extends AppCompatActivity { private List<Video_recycler_been> video_recycler_beens = new ArrayList<>(); private ProgressDialog progressDialog ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); search(); } /* 开始搜索 */ public void search(){ ScannerAnsyTask ansyTask=new ScannerAnsyTask(); //videoInfoss=ansyTask.doInBackground(); ansyTask.execute(); } /* 异步任务具体 */ public class ScannerAnsyTask extends AsyncTask<Void,Integer,List<VideoInfo>> { private List<VideoInfo> videoInfos=new ArrayList<VideoInfo>(); @Override protected void onPreExecute(){ // progressDialog.setTitle("正在搜索。。。"); progressDialog= new ProgressDialog(Main2Activity.this); progressDialog.setMessage("正在搜索。。。"); progressDialog.setCancelable(false); progressDialog.show(); } @Override protected List<VideoInfo> doInBackground(Void... params) { videoInfos=getVideoFile(videoInfos, Environment.getExternalStorageDirectory()); //videoInfos=filterVideo(videoInfos); return videoInfos; } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); //videoInfos=filterVideo(videoInfos); // Toast.makeText(Main2Activity.this,String.valueOf(values.()),Toast.LENGTH_LONG).show(); } @Override protected void onPostExecute(List<VideoInfo> videoInfo) { RecyclerView recyclerView=(RecyclerView)findViewById(R.id.rec); LinearLayoutManager layoutManager = new LinearLayoutManager(Main2Activity.this); recyclerView.setLayoutManager(layoutManager); Video_Adapter video_adapter = new Video_Adapter(video_recycler_beens); video_adapter.setOnItemClickListener(new Video_Adapter.itemOnclick() { @Override public void onclick(int position) { Video_recycler_been V = video_recycler_beens.get(position); Intent intent = new Intent(Main2Activity.this,MainActivity.class); intent.putExtra("path",V.getPath()) ; startActivity(intent); } }); recyclerView.setAdapter(video_adapter); init(videoInfo); } /** * 获取视频文件 * @param list * @param file * @return */ private List<VideoInfo> getVideoFile(final List<VideoInfo> list, File file) { file.listFiles(new FileFilter() { @Override public boolean accept(File file) { String name = file.getName(); int i = name.indexOf('.');//文件出现“.”字符时算出它所在的位置(“12331.23”)那么i为5 if (i != -1) { name = name.substring(i);//把 i后面的字符求出(包括i) if (name.equalsIgnoreCase(".mp4") || name.equalsIgnoreCase(".3gp")//比较字符串是否一样,和equals类似,但是这个忽略大小写 || name.equalsIgnoreCase(".wmv") || name.equalsIgnoreCase(".ts") || name.equalsIgnoreCase(".rmvb") || name.equalsIgnoreCase(".mov") || name.equalsIgnoreCase(".m4v") || name.equalsIgnoreCase(".avi") || name.equalsIgnoreCase(".m3u8") || name.equalsIgnoreCase(".3gpp") || name.equalsIgnoreCase(".3gpp2") || name.equalsIgnoreCase(".mkv") || name.equalsIgnoreCase(".flv") || name.equalsIgnoreCase(".divx") || name.equalsIgnoreCase(".f4v") || name.equalsIgnoreCase(".rm") || name.equalsIgnoreCase(".asf") || name.equalsIgnoreCase(".ram") || name.equalsIgnoreCase(".mpg") || name.equalsIgnoreCase(".v8") || name.equalsIgnoreCase(".swf") || name.equalsIgnoreCase(".m2v") || name.equalsIgnoreCase(".asx") || name.equalsIgnoreCase(".ra") // || name.equalsIgnoreCase(".mp3")//搜索音乐文件 || name.equalsIgnoreCase(".ndivx") || name.equalsIgnoreCase(".xvid")) { VideoInfo video = new VideoInfo(); // file.getUsableSpace();//h获取当前分区的大小(可以算D盘大小) video.setDisplayName(file.getName()); video.setPath(file.getAbsolutePath()); video.setSize(getSizer(file.length())); //获取视频的时长 video.setTime(getTimer(file.getAbsolutePath())); Log.i("tga","name"+video.getDisplayName()+" "+video.getSize()); list.add(video); return true; } //判断是不是目录 } else if (file.isDirectory()) { getVideoFile(list, file); } return false; } }); return list; } /** * 把遍历到的路径和视频名以及时长显示到recyclerview上 */ private List<VideoInfo> filterVideo(List<VideoInfo> videoInfos){ List<VideoInfo> newVideos=new ArrayList<VideoInfo>(); for(VideoInfo videoInfo:videoInfos){ File f=new File(videoInfo.getPath()); if(f.exists()&&f.isFile()&&f.length()>10485760){ newVideos.add(videoInfo); Log.i("TGA","文件大小"+f.length()); }else { Log.i("TGA","文件太小或者不存在"); } } return newVideos; } } /* 将视频的时长转化为 xx:xx:xx的形式(获取的时间以毫秒为单位的一大串数字) */ private String getTimer(String address){ String rTime="0"; String rhour="0" , rminute="0" , rsecond="0"; try { MediaPlayer mediaPlayer=new MediaPlayer(); mediaPlayer.setDataSource(address); mediaPlayer.prepare(); int time = mediaPlayer.getDuration();//算出来的时间是以毫秒为单位的,我们显示的时间到秒为止 time=time/1000; int second=time%60; time=time/60; int minute = time % 60; int hour = time / 60; if(second>=10) rsecond = String.valueOf(second); else rsecond = "0"+ String.valueOf(second); if(minute>=10) rminute = String.valueOf(minute); else rminute = "0"+ String.valueOf(minute); if(hour>=10) rhour = String.valueOf(hour); else rhour = "0"+ String.valueOf(hour); } catch (IOException e){ } rTime=rhour+":"+rminute+":"+rsecond; return rTime; } /* 将视频的大小转化为 xMB XKB XB的形式(直接得到的大小是以B为单位的一大串数字) */ private String getSizer(long size){ String rsize="0"; if(size/1024==0){ rsize=String.valueOf(size)+"B"; } else { size=size/1024; if(size/1024==0){ rsize=String.valueOf(size)+"KB"; } else{ size=size/1024; if(size/1024==0){ rsize=String.valueOf(size)+"MB"; } else{ size=size/1024; if(size/1024==0){ rsize=String.valueOf(size)+"GB"; } } } } return rsize; } /*** * 根据播放路径设置缩略图 */ public Bitmap getVideo_Bitmap(String filePath) { Bitmap bitmap = null; MediaMetadataRetriever retriever = new MediaMetadataRetriever(); try { retriever.setDataSource(filePath); bitmap = retriever.getFrameAtTime(); } catch(IllegalArgumentException e) { e.printStackTrace(); } catch (RuntimeException e) { e.printStackTrace(); } finally { try { retriever.release(); } catch (RuntimeException e) { e.printStackTrace(); } } return bitmap; } public void init(List<VideoInfo> videoInfo){ for(VideoInfo a:videoInfo) { Video_recycler_been data = new Video_recycler_been(getVideo_Bitmap(a.getPath()), a.getDisplayName(), a.getTime(), a.getSize(),a.getPath()); video_recycler_beens.add(data); } progressDialog.cancel(); }
上面就是具体搜索全部的本地视频的代码,其中我写了一个VideoInfo的实体类,里面放了一些我需要的关于视频的信息,等等也一起贴出来。现在需要说明一下,直接获得视频的大小是以B为单位的一大串数据,那么我写了getSizer这个方法把格式转变了一下,代码有注释。同样的直接获取的视频的时间也是以毫秒为单位的一大串数字,我也同样写了方法去修改一下格式,代码里面有注释。下面给出我的实体类:
package list_been; /** * Created by admin on 2018/3/21. */ public class VideoInfo { private String Path; private String DisplayName; private String Size; private String Time; public String getPath() { return Path; } public void setPath(String path) { Path = path; } public String getDisplayName() { return DisplayName; } public void setDisplayName(String displayName) { DisplayName = displayName; } public String getSize() { return Size; } public void setSize(String size) { Size = size; } public String getTime() { return Time; } public void setTime(String time) { Time = time; } }
具体的加什么内容,读者可以自行添加。
到了现在,已经可以把本地视频的名字 大小 时长 路径输出了。接下来,我们还需要把视频的缩略图得到,下面开始,还是先把代码贴出来先:
/*** * 根据播放路径设置缩略图 */ public Bitmap getVideo_Bitmap(String filePath) { Bitmap bitmap = null; MediaMetadataRetriever retriever = new MediaMetadataRetriever(); try { retriever.setDataSource(filePath); bitmap = retriever.getFrameAtTime(); } catch(IllegalArgumentException e) { e.printStackTrace(); } catch (RuntimeException e) { e.printStackTrace(); } finally { try { retriever.release(); } catch (RuntimeException e) { e.printStackTrace(); } } return bitmap; }
这个是网上留传的根据视频路径得到缩略图的方法,我就直接用了,这里要注意一下,我没有把缩略图也写到实体类里面,因为最后你要把视频的全部信息放到recycler的item里面的,在着之前是靠arraylist来缓存数据的,如果你把bitmap也放进去,无疑会很大,最后OMM,所以每次要往item放信息的时候,调用一下getVideo_Bitmap()这个类就可以了;
接下来就是用recyclerview把视频的信息显示出来:
下面是item的布局:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="100dp"> <ImageView android:id="@+id/bitmap" android:layout_width="100dp" android:layout_height="0dp" app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="0dp" android:layout_marginLeft="0dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="8dp" /> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="50dp" android:text="TextView" android:textSize="20dp" android:textStyle="bold" app:layout_constraintLeft_toRightOf="@+id/bitmap" android:layout_marginLeft="8dp" app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="8dp" /> <TextView android:id="@+id/time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" android:textSize="16dp" app:layout_constraintLeft_toRightOf="@+id/bitmap" android:layout_marginLeft="8dp" android:layout_marginTop="16dp" app:layout_constraintTop_toBottomOf="@+id/name" /> <TextView android:id="@+id/size" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" android:textSize="16dp" app:layout_constraintLeft_toRightOf="@+id/time" android:layout_marginLeft="16dp" android:layout_marginTop="16dp" app:layout_constraintTop_toBottomOf="@+id/name" /> <TextView android:id="@+id/path" android:layout_width="0dp" android:layout_height="0dp" android:text="TextView" app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="8dp" android:layout_marginRight="8dp" app:layout_constraintRight_toRightOf="parent" /> </android.support.constraint.ConstraintLayout>
下面是实体类:
package list_been; import android.graphics.Bitmap; /** * Created by admin on 2018/3/23. */ public class Video_recycler_been { private Bitmap bitmap; private String name; private String time; private String size; private String path; public Video_recycler_been(Bitmap bitmap,String name,String time,String size,String path){ this.bitmap=bitmap; this.name=name; this.size=size; this.time=time; this.path=path; } public Bitmap getBitmap() { return bitmap; } public String getName() { return name; } public String getTime() { return time; } public String getSize() { return size; } public String getPath() { return path; } }
下面是适配器Adapter:
package com.example.admin.materialdesign; import android.provider.MediaStore; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import java.util.List; import list_been.Video_recycler_been; /** * Created by admin on 2018/3/23. */ public class Video_Adapter extends RecyclerView.Adapter<Video_Adapter.ViewHolder> { public interface itemOnclick{ void onclick(int position); } private itemOnclick myitemonclick; private List<Video_recycler_been> mvideo; public void setOnItemClickListener(itemOnclick onItemClickListener ){ this.myitemonclick=onItemClickListener; } static class ViewHolder extends RecyclerView.ViewHolder{ ImageView bitmap; TextView name; TextView size; TextView time; View video_view; public ViewHolder(View view){ super(view); bitmap=(ImageView)view.findViewById(R.id.bitmap); name=(TextView)view.findViewById(R.id.name); size=(TextView)view.findViewById(R.id.size); time=(TextView)view.findViewById(R.id.time); video_view=view; } } public Video_Adapter(List<Video_recycler_been> video){ mvideo=video; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent , int viewType){ View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.video_item,parent,false); final ViewHolder holder = new ViewHolder(view); return holder; } @Override public void onBindViewHolder(ViewHolder holder , final int position){ Video_recycler_been video_recycler_been=mvideo.get(position); holder.size.setText(video_recycler_been.getSize()); holder.bitmap.setImageBitmap(video_recycler_been.getBitmap()); holder.name.setText(video_recycler_been.getName()); holder.time.setText(video_recycler_been.getTime()); holder.video_view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { myitemonclick.onclick(position); } }); } @Override public int getItemCount(){ return mvideo.size(); } }
这里说明一下,recyclerview没有直接可以在主java文件调用的点击事件监听,所以自己写了一个接口;接口很简单,先定义接口
public interface itemOnclick{ void onclick(int position);
}
private itemOnclick myitemonclick;
这里就放了一个点击的方法(抽像的);定义一个全局变量 最后然后写一个类(供主java调用)
public void setOnItemClickListener(itemOnclick onItemClickListener ){ this.myitemonclick=onItemClickListener; }
这里放了你的接口,最后在
public void onBindViewHolder(ViewHolder holder , final int position){ Video_recycler_been video_recycler_been=mvideo.get(position); holder.size.setText(video_recycler_been.getSize()); holder.bitmap.setImageBitmap(video_recycler_been.getBitmap()); holder.name.setText(video_recycler_been.getName()); holder.time.setText(video_recycler_been.getTime()); holder.video_view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { myitemonclick.onclick(position); } }); }
这里把position传进去;(其实主要就是获得点击时的position)红色就是关键代码
点击了以后就跳到第二个界面去播放了,播放需要一个进度条,这里暂时偷个懒,先用了自带的进度条
MediaController mediaController = new MediaController(this); mediaController.setMediaPlayer(videoView); videoView.start(); videoView.setMediaController(mediaController);
至于视频播放和视频弹幕再我上一篇博客有介绍,需要的可以去看一下。