一.github地址:https://github.com/lingchen1854/LCPlayerAPP.git
二.硬件调试:华为nove 2s
三.部分代码:
1.MainActivity.java
// 安卓6.0以上需要获取权限
package com.likego.lcplayerapp;
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.os.Bundle;
import android.util.Log;
import android.view.Window;
import android.view.WindowManager;
public class MainActivity extends Activity {
private String TAG = "MainActivity xmlc";
private String[] mPermissions = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE };
private int READ_EXTERNAL_STORAGE_CONSTANT = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate: ");
getPermissions();
}
private void getPermissions(){
int permission = ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.READ_EXTERNAL_STORAGE);
if (permission == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "onCreate: 表示已经授权,进入列表");
Intent startList = new Intent("com.likego.xmlc.Player.ListActivity");
startActivity(startList);
finish();
}else {
Log.d(TAG, "onCreate: 表示权限被否认或首次请求权限,当前申请权限,并监听申请结果");
ActivityCompat.requestPermissions(MainActivity.this,mPermissions,
READ_EXTERNAL_STORAGE_CONSTANT);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == READ_EXTERNAL_STORAGE_CONSTANT && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Log.d(TAG, "onRequestPermissionsResult: 监听到是当前申请的权限,且SDK的版本>=AndroidM(6.0)");
if (shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE)) {
Log.d(TAG, "权限被拒绝,进入设置打开权限");
AskForPermission();
}else {
Log.d(TAG, "已获得权限,打开列表");
Intent startList = new Intent("com.likego.xmlc.Player.ListActivity");
startActivity(startList);
finish();
}
}
}
private void AskForPermission() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("需要权限!");
builder.setNegativeButton("退出", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(MainActivity.this,mPermissions,
READ_EXTERNAL_STORAGE_CONSTANT);
}
});
builder.setPositiveButton("设置", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName())); // 根据包名打开对应的设置界面
startActivity(intent);
}
});
builder.create().show();
}
}
2.ListActivity.java
// 扫描内部存储获取列表
package com.likego.lcplayerapp;
import android.app.Activity;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaMetadataRetriever;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ProgressBar;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class ListActivity extends Activity {
private static final String TAG = "ListActivity xmlc";
private static HashMap<String,String> MediaHash;
private ProgressBar mProgressBar;
private Button mButtonAll;
private Button mButtonDownload;
private Button mButtonSdcard;
private static final int MSG_VISIBLE = 1;
private static final int MSG_GONE = 2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_list);
mProgressBar = findViewById(R.id.progressBarLarge);
mHandler.sendEmptyMessage(MSG_GONE);
mButtonAll = findViewById(R.id.all);
mButtonAll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new ScanSdcard("/storage/emulated/0/").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
mButtonAll.setVisibility(View.GONE);
mButtonDownload.setVisibility(View.GONE);
mButtonSdcard.setVisibility(View.GONE);
}
});
mButtonDownload = findViewById(R.id.dowload);
mButtonDownload.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new ScanSdcard("/storage/emulated/0/Download/").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
mButtonAll.setVisibility(View.GONE);
mButtonDownload.setVisibility(View.GONE);
mButtonSdcard.setVisibility(View.GONE);
}
});
mButtonSdcard = findViewById(R.id.sdcard);
mButtonSdcard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new ScanSdcard("/storage/external_storage/sdcard1").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
mButtonAll.setVisibility(View.GONE);
mButtonDownload.setVisibility(View.GONE);
mButtonSdcard.setVisibility(View.GONE);
}
});
}
private Handler mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message message) {
switch (message.what){
case MSG_VISIBLE:
mProgressBar.setVisibility(View.VISIBLE);
break;
case MSG_GONE:
mProgressBar.setVisibility(View.GONE);
break;
default:
break;
}
return false;
}
});
/***
* 根据播放路径设置缩略图
* @param filePath 视频资源的路径
* @return 返回缩略图的Bitmap对象
*/
public Bitmap getVideoThumbNail(String filePath) {
long startTime = System.currentTimeMillis();
Bitmap bitmap = null;
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
retriever.setDataSource(filePath);
bitmap = retriever.getFrameAtTime();//60*1000*1000
}
catch(IllegalArgumentException e) {
e.printStackTrace();
}
catch (RuntimeException e) {
e.printStackTrace();
}
finally {
try {
retriever.release();
}
catch (RuntimeException e) {
e.printStackTrace();
}
}
long endTime = System.currentTimeMillis();
long runTime = endTime - startTime;
if (bitmap != null){
// bitmap = Bitmap.createScaledBitmap(bitmap, 640, 360, true);
Log.d(TAG, filePath+" 时间 : "+ runTime + " ms "+""+bitmap.getWidth()+" * "+bitmap.getHeight());
return bitmap;
}else {
Resources res=getResources();
Bitmap nullBitmap = BitmapFactory.decodeResource(res, R.drawable.bitmap_null);
Log.d(TAG, filePath+" 时间 : "+ runTime + " ms "+""+nullBitmap.getWidth()+" * "+nullBitmap.getHeight());
return nullBitmap;
}
}
public class ScanSdcard extends AsyncTask<Void, Void, Void> {
private static final String TAG = "ScanSdcard xmlc";
private long mStartTime = System.currentTimeMillis();
private ArrayList MediaNameList;
private List<MediaInfo> MediaList = new ArrayList<MediaInfo>();
public ScanSdcard(String path) {
super();
scanSdcard(path);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.d(TAG, "----------onPreExecute: onCreate Scan Sdcard----------");
MediaNameList = new ArrayList();
MediaHash = new HashMap<>();
}
@Override
protected Void doInBackground(Void... voids) {
Log.d(TAG, "doInBackground: ->>>>>--");
mHandler.sendEmptyMessage(MSG_VISIBLE);
initMediaImage();
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Log.d(TAG, "onPostExecute: -----doInBackground over , You can update UI-----" +
"\n ----------视频文件数量 = "+MediaNameList.size());
if (MediaNameList.size() == 0){
mButtonAll.setVisibility(View.VISIBLE);
mButtonDownload.setVisibility(View.VISIBLE);
mButtonSdcard.setVisibility(View.VISIBLE);
}
long endTime = System.currentTimeMillis();
long runTime = endTime - mStartTime;
Log.d(TAG, "方法使用时间 : "+ runTime + " ms");
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
StaggeredGridLayoutManager layoutManager = new
StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
MediaAdapter adapter = new MediaAdapter(MediaList,ListActivity.this);
recyclerView.setAdapter(adapter);
}
private void scanSdcard(String path){
File sdcardFile = new File(path);
File[] sdcardFileList = sdcardFile.listFiles();
if (sdcardFileList == null) {
Log.d(TAG, "f is null");
return;
}
for (File f : sdcardFileList) {
if (f.isFile()){
if (f.getName().toLowerCase().endsWith(".mp4")
|| f.getName().toLowerCase().endsWith(".mkv")){
MediaNameList.add(f.getName());
MediaHash.put(f.getName(),f.getAbsolutePath());
Log.d(TAG, "scanSdcard: "+f.getName());
}
}else if (f.isDirectory()) {
scanSdcard(f.getPath());
Log.d(TAG, "scanSdcard: "+f.getName());
}
}
}
private void initMediaImage(){
mHandler.sendEmptyMessage(MSG_VISIBLE);
for (int i = 0; i < MediaNameList.size();i++){
Bitmap bitmap = getVideoThumbNail(MediaHash.get(MediaNameList.get(i)));
MediaInfo info = new MediaInfo(MediaNameList.get(i).toString(),
bitmap);
MediaList.add(info);
}
mHandler.sendEmptyMessage(MSG_GONE);
}
}
public static HashMap<String, String> getMediaHash() {
return MediaHash;
}
}
3.MediaAdapter.java
// 设置列表适配器
package com.likego.lcplayerapp;
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.support.annotation.NonNull;
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 java.util.HashMap;
import java.util.List;
public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.ViewHolder> {
private static final String TAG = "MediaAdapter xmlc";
private List<MediaInfo> mMediaInfos;
private Context mContext;
public MediaAdapter(List<MediaInfo> fruitList, Context context) {
mContext = context;
mMediaInfos = fruitList;
Log.d(TAG, "MediaAdapter: "+mMediaInfos.size());
}
public class ViewHolder extends RecyclerView.ViewHolder{
View mediaView;
ImageView mediaImage;
TextView mediaName;
public ViewHolder(View view) {
super(view);
mediaView = view;
mediaImage = (ImageView) view.findViewById(R.id.media_image);
mediaName = (TextView) view.findViewById(R.id.media_name);
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.media_item,
viewGroup, false);
final ViewHolder holder = new ViewHolder(view);
holder.mediaView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
MediaInfo mediaInfo = mMediaInfos.get(position);
Log.d(TAG, "onClick:--->>name "+mediaInfo.getMediaName());
HashMap<String,String> mediaHashMap = ListActivity.getMediaHash();
String path = mediaHashMap.get(mediaInfo.getMediaName());
Intent intent = new Intent(mContext, MediaPlayerActivity.class);
intent.putExtra("path",path);
mContext.startActivity(intent);
}
});
holder.mediaImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
MediaInfo mediaInfo = mMediaInfos.get(position);
Log.d(TAG, "onClick:--->>image "+mediaInfo.getMediaName());
HashMap<String,String> mediaHashMap = ListActivity.getMediaHash();
String path = mediaHashMap.get(mediaInfo.getMediaName());
Intent intent = new Intent(mContext, MediaPlayerActivity.class);
intent.putExtra("path",path);
mContext.startActivity(intent);
}
});
return holder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
MediaInfo mediaInfo = mMediaInfos.get(i);
viewHolder.mediaImage.setImageBitmap(mediaInfo.getMediaImage());
viewHolder.mediaName.setText(mediaInfo.getMediaName());
}
@Override
public int getItemCount() {
// Log.d(TAG, "getItemCount: "+mMediaInfos.size());
return mMediaInfos.size();
}
}
4.MediaInfo.java
package com.likego.lcplayerapp;
import android.graphics.Bitmap;
import android.util.Log;
public class MediaInfo {
private String mMediaName;
private Bitmap mMediaBitmap;
public MediaInfo(String name, Bitmap bitmap) {
this.mMediaName = name;
this.mMediaBitmap = bitmap;
}
public String getMediaName() {
return mMediaName;
}
public Bitmap getMediaImage() {
return mMediaBitmap;
}
}
5.MediaPlayerActivity.java
// 从列表获取播放路径并播放
package com.likego.lcplayerapp;
import android.app.Activity;
import android.content.Intent;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;
public class MediaPlayerActivity extends Activity {
private String TAG = "MediaPlayerActivity xmlc";
private MediaPlayer mMediaPlayer;
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_media_player);
mSurfaceView = findViewById(R.id.SurfaceView);
mSurfaceHolder = mSurfaceView.getHolder();
Log.d(TAG, "onCreate: "+mSurfaceHolder.toString());
mSurfaceHolder.addCallback(callback);
}
private SurfaceHolder.Callback callback = new SurfaceHolder.Callback(){
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
Intent intent = getIntent();
String path = intent.getStringExtra("path");
Log.d(TAG, "surfaceCreated: " + path);
Uri uri = Uri.parse(path);
mMediaPlayer = MediaPlayer.create(MediaPlayerActivity.this,uri);
mMediaPlayer.setDisplay(mSurfaceHolder);
// mMediaPlayer.prepareAsync();
mMediaPlayer.start();
mediaPlayerListener();
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
Log.d(TAG, "surfaceChanged: ");
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
Log.d(TAG, "surfaceDestroyed: ");
}
};
private void mediaPlayerListener(){
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
Log.d(TAG, "onCompletion: 播放结束");
if (mMediaPlayer != null){
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
}
}
});
mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
Log.e(TAG, "onError: 播放错误"+i+","+i1);
if (i == 1 && i1 == -1){
Log.d(TAG, "onError: 1");
}else if (i == 100 && i1 == 0){
Log.d(TAG, "onError: 错误代码(100,0),该视频路径对应的存储设备不存在,无法缓存");
}else if (i == -38 && i1 == 0){
Log.d(TAG, "onError: -38,0.播U盘1,切音乐,拔U盘1,切视频,空路径请求下一曲/突然拔U盘也会");
}else if (i == 1 && i1 == -2147483648){
Log.d(TAG, "onError: Play方法出错,reset,缓存");
}else if (i == 1 && i1 == -33554449){
Log.d(TAG, "onError: 拔U盘触发的");
}else if (i == 1 && i1 == -33554485){
Log.d(TAG, "onError: 不支持的文件格式");
}else {
Log.d(TAG, "onError: else");
}
return true;
}
});
}
@Override
protected void onPause() {
super.onPause();
if (mMediaPlayer != null){
mMediaPlayer.pause();
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
if (mMediaPlayer != null){
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mMediaPlayer != null){
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
}
}
}
四、小结
花了两天把这几个月学习的东西整合成这个项目,只是初版,并没有查找和解决BUG,还有许多可以优化的地方。还有重要的缺点,扫描列表和获取缩略图比较慢。