文末附源码:
先看最终实现的效果吧:
csdn限制图片大小不得超过5M,所以图片看着有点糊
关于本文中将要讲到的实现,我觉得可以先单拎出来一些内容:
(1)Android 获取系统相册所有的图片以及视频资源
工具类:MediaHelper.java
public class MediaHelper {
private static final String[] MEDIA_COLUMNS = {
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DATA,
MediaStore.Images.Media.DATE_ADDED,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.SIZE,
MediaStore.Images.Media.MIME_TYPE,
MediaStore.Images.Media.ORIENTATION,
MediaStore.Video.VideoColumns.DURATION
};
public static List<MediaItem> getMediaList(Context context) {
List<MediaItem> mediaList = new ArrayList<>();
ContentResolver contentResolver = context.getContentResolver();
String sortOrder = MediaStore.Images.Media.DATE_ADDED + " DESC";
// Get images
Cursor imageCursor = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
MEDIA_COLUMNS, null, null, sortOrder);
if (imageCursor != null && imageCursor.moveToFirst()) {
do {
MediaItem item = new MediaItem();
item.setId(imageCursor.getLong(imageCursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)));
item.setFilePath(imageCursor.getString(imageCursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)));
item.setDisplayName(imageCursor.getString(imageCursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME)));
item.setSize(imageCursor.getLong(imageCursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE)));
item.setMimeType(imageCursor.getString(imageCursor.getColumnIndexOrThrow(MediaStore.Images.Media.MIME_TYPE)));
item.setOrientation(imageCursor.getInt(imageCursor.getColumnIndexOrThrow(MediaStore.Images.Media.ORIENTATION)));
mediaList.add(item);
} while (imageCursor.moveToNext());
imageCursor.close();
}
// Get videos
Cursor videoCursor = contentResolver.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
MEDIA_COLUMNS, null, null, sortOrder);
if (videoCursor != null && videoCursor.moveToFirst()) {
do {
MediaItem item = new MediaItem();
item.setId(videoCursor.getLong(videoCursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)));
item.setFilePath(videoCursor.getString(videoCursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)));
item.setDisplayName(videoCursor.getString(videoCursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME)));
item.setSize(videoCursor.getLong(videoCursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE)));
item.setMimeType(videoCursor.getString(videoCursor.getColumnIndexOrThrow(MediaStore.Images.Media.MIME_TYPE)));
item.setDuration(videoCursor.getLong(videoCursor.getColumnIndexOrThrow(MediaStore.Video.VideoColumns.DURATION)));
mediaList.add(item);
} while (videoCursor.moveToNext());
videoCursor.close();
}
return mediaList;
}
}
实体类:MediaItem.java
public class MediaItem implements Serializable {
private long id;
private String filePath;
private String displayName;
private long size;
private String mimeType;
private int orientation;
private long duration;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public String getMimeType() {
return mimeType;
}
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
public int getOrientation() {
return orientation;
}
public void setOrientation(int orientation) {
this.orientation = orientation;
}
public long getDuration() {
return duration;
}
public void setDuration(long duration) {
this.duration = duration;
}
@Override
public String toString() {
return "MediaItem{" +
"id=" + id +
", filePath='" + filePath + '\'' +
", displayName='" + displayName + '\'' +
", size=" + size +
", mimeType='" + mimeType + '\'' +
", orientation=" + orientation +
", duration=" + duration +
'}';
}
}
实际调用就很简单了,直接获取列表即可
private List<MediaItem> mediaList;
mediaList = MediaHelper.getMediaList(this);
for (MediaItem item : mediaList) {
Log.d("MediaHelper", "id: " + item.getId() + ", info: " + item.toString());
}
(2)利用Viewpagger2+fragment实现分页滑动效果,这部分可以参考这一篇博客
上面两步,基本上就实现了获取所有的数据,并且也把具体的UI框架搭起来了,那么接下来就是要分别判断媒体类型,来做不同的展示了,图片,就是普通的展示,视频,就是播放。
(3)图片展示
引用三方库:
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
<com.github.chrisbanes.photoview.PhotoView
android:id="@+id/photoView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
binding.photoView.setImageURI(Uri.parse(mediaItem.getFilePath()));
(4)视频播放控制
引用aar,如图(文件可从demo中获取)
初始化
binding.videoView.setZOrderOnTop(false);
initMediaPlayer();
private void initMediaPlayer() {
if (mMediaPlayer == null) {
mMediaPlayer = new IjkMediaPlayer();
mMediaPlayer.setOnPreparedListener(this);
try {
// 使用本地视频
mMediaPlayer.setDataSource(getActivity(), Uri.parse(mediaItem.getFilePath()));
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getActivity(), "视频无法正常打开,请重新尝试", Toast.LENGTH_SHORT).show();
}
mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0);
}
}
使用:
实现视频播放相关接口
implements SurfaceHolder.Callback, IMediaPlayer.OnPreparedListener
重写方法
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
mMediaPlayer.setDisplay(holder);
try {
// 使用prepareAsync,防止阻塞主线程
mMediaPlayer.prepareAsync();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {
}
@Override
public void onPrepared(IMediaPlayer mp) {
binding.videoView.setAspectRatio(mp.getVideoWidth(), mp.getVideoHeight());
}
生命周期调用
@Override
public void onStart() {
super.onStart();
binding.videoView.getHolder().addCallback(this);
binding.videoView.setOnClickListener(v -> {
if (NoDoubleClick.isDoubleClick()) {
return;
}
if (isPlaying) {
isPlaying = false;
mMediaPlayer.pause();
Toast.makeText(getActivity(), "停止播放!", Toast.LENGTH_SHORT).show();
} else {
isPlaying = true;
mMediaPlayer.start();
Toast.makeText(getActivity(), "开始播放!", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onStop() {
super.onStop();
binding.videoView.getHolder().removeCallback(this);
releaseMediaPlayer();
}
private void releaseMediaPlayer() {
if (mMediaPlayer != null) {
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer = null;
}
}
其实,至此,走完(1)(2)(3)这三部分,基本上就完成了本文中完成的效果了,笔者在写demo的时候也基本上是遵循此顺序完成的。