java 选取本地视频相册,然后转换为recycleView展示出来,具体的实现逻辑需要的时候再捋清楚,MVP方式实现
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 选取本地视频相册,然后转换为recycleView展示出来,具体的实现逻辑需要的时候再捋清楚,MVP方式实现相关的知识,希望对你有一定的参考价值。
/**
* 从本地的视频相册选取视频
* Created by hsp on 2017/7/12.
*/
public class VideoAlbumActivity extends AbstractMvpActivity<VideoAlbumPresenter> implements VideoAlbumContract.View {
// ===========================================================
// Constants
// ===========================================================
public static final int NUM_COLUMNS = 3;//每一行放三个视频
// ===========================================================
// Fields
// ===========================================================
private RecyclerView mRecyclerView;
private VideoAdapter mVideoAdapter;
private View mEmptyContentView;
// ===========================================================
// Override Methods
// ===========================================================
@Override
protected void onCreate(Bundle savedInstanceState) {
//super.onCreate执行三步,初始化view :initViews(),把view赋值给presenter,调用presenter的加载数据的方法,在把数据显示在view上
super.onCreate(savedInstanceState);
//发一下广播更新本地视频相册
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
final Intent scanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
final Uri contentUri = Uri.parse("file://" + Environment.getExternalStorageDirectory());
scanIntent.setData(contentUri);
sendBroadcast(scanIntent);
} else {
final Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory()));
sendBroadcast(intent);
}
initEventAndData();
}
@Override
protected VideoAlbumPresenter onLoadPresenter() {
return new VideoAlbumPresenter();
}
/**
* 初始化控件,这里主要是初始化展现视频列表的recyclerView和本地视频为空的时候的tipView
*/
@Override
protected void initViews(Bundle savedInstanceState) {
setContentView(R.layout.musv_video_album_activity);
mEmptyContentView = findViewById(R.id.framework_content_empty_rlayout);
mRecyclerView = (RecyclerView) findViewById(R.id.musv_show_video_rv);
mRecyclerView.setLayoutManager(new GridLayoutManager(this, NUM_COLUMNS));//每行展示三张图片
mRecyclerView.addItemDecoration(new VideoAlbumActivity.SpaceItemDecoration(DeviceUtils.dip2px(0)));
}
/**
* 初始化控件的一些事件和其他数据
*/
@Override
protected void initEventAndData() {
//初始化导航栏右部叉的点击事件
TopActionBar topActionBar = (TopActionBar) findViewById(R.id.musv_toolbar_tab);
topActionBar.setRightOnClickLinstener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
/**
* recyclerView的数据更新了提醒刷新
*/
@Override
public void showLocalVideoList(ArrayList<VideoEntity> LocalVideoList) {
updateRecyclerView(LocalVideoList);
}
@Override
public void showDialog() {
showProgressDialog();
}
@Override
public void closeDialog() {
dismissProgressDialog();
}
/**
* 本地视频为空的时候显示提示信息
*/
@Override
public void showEmptyContent() {
mEmptyContentView.setVisibility(View.VISIBLE);
}
// ===========================================================
// Define Methods
// ===========================================================
/**
* 通知更新recycleView
*/
private void updateRecyclerView(final ArrayList<VideoEntity> LocalVideoList) {
if (null == mVideoAdapter) {
mVideoAdapter = new VideoAdapter(LocalVideoList);
mRecyclerView.setAdapter(mVideoAdapter);
mVideoAdapter.setOnRecyclerViewItemListener(new OnRecyclerViewItemListener() {
@Override
public void onItemClick(View v, int position) {
// Toast.makeText(VideoAlbumActivity.this, "我要跳到视频裁剪页面了", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(VideoAlbumActivity.this, VideoCropActivity.class);
intent.putExtra(VideoCropActivity.VIDEO_PATH, LocalVideoList.get(position).getPath());
startActivity(intent);
}
});
} else {
mVideoAdapter.notifyDataSetChanged();
}
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
/**
* 控制recycle view 的item的间距
*/
private class SpaceItemDecoration extends RecyclerView.ItemDecoration {
int mSpace;//间距
private SpaceItemDecoration(int space) {
this.mSpace = space;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view); // item position
int column = position % NUM_COLUMNS; // item column
outRect.left = mSpace - column * mSpace / NUM_COLUMNS; // spacing - column * ((1f / spanCount) * spacing)
outRect.right = (column + 1) * mSpace / NUM_COLUMNS; // (column + 1) * ((1f / spanCount) * spacing)
if (position < NUM_COLUMNS) { // top edge
outRect.top = mSpace;
}
outRect.bottom = mSpace; // item bottom
}
}
/**
* recyclerView的适配器
*/
private class VideoAdapter extends RecyclerView.Adapter<VideoAlbumActivity.VideoAdapter.ViewHolder> {
private List<VideoEntity> mData;
private int imageHeight = getScreenWidth() / NUM_COLUMNS;//每张图片的宽和高都是屏幕横的NUM_COLUMNS分之一
private OnRecyclerViewItemListener mListener;//设置点击事件的监听
private void setOnRecyclerViewItemListener(OnRecyclerViewItemListener l) {
mListener = l;
}
VideoAdapter(List<VideoEntity> data) {
this.mData = data;
}
@Override
public VideoAlbumActivity.VideoAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(VideoAlbumActivity.this).inflate(R.layout.musv_video_album_list_item, parent, false);
view.getLayoutParams().height = imageHeight;
return new VideoAlbumActivity.VideoAdapter.ViewHolder(view);
}
@Override
public void onBindViewHolder(final VideoAlbumActivity.VideoAdapter.ViewHolder holder, final int position) {
final VideoEntity mediaModel = mData.get(position);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mListener != null) {
mListener.onItemClick(holder.itemView, holder.getAdapterPosition());
}
}
});
holder.tvDuration.setText(NumberUtils.getMinAndSec(mediaModel.getDuration()));
String mediaPath = "file://" + mediaModel.getPath();
//设置加载的时候的一些选项
DisplayImageOptions options = new DisplayImageOptions.Builder().memoryCacheExtraOptions(imageHeight, imageHeight)
.diskCacheExtraOptions(imageHeight, imageHeight).cacheImageMultipleSizesInDiskCache().compressQuality(75)
.cacheInMemory(true).cacheOnDisk(true).build();
//加载图片
ImageLoaderUtils.displayImage(mediaPath, holder.mThumb, options);
}
@Override
public int getItemCount() {
return null == mData ? 0 : mData.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
ImageView mThumb;
TextView tvDuration;
ViewHolder(View view) {
super(view);
mThumb = (ImageView) view.findViewById(R.id.musv_video_thumb_iv);
tvDuration = (TextView) view.findViewById(R.id.musv_time_tv);
}
}
}
/**
* recycle View的监听接口
*/
interface OnRecyclerViewItemListener {
void onItemClick(View v, int position);
}
// ===========================================================
// Getter & Setter
// ===========================================================
}
/**
* 获取本地视频相册的所有视频
* Created by hsp on 2017/7/11.
*/
public class VideoProvider {
private static final String TAG = "VideoProvider";
private static final String SUPPORT_FORMAT = "('video/mp4','video/3gp')";//支持的格式
/**
* 获取video
*
* @param context 上下文
* @return 返回满足支持格式的所有的video
*/
public static ArrayList<VideoEntity> getVideos(Context context) {
ArrayList<VideoEntity> list = null;
Cursor cursor = null;
try {
list = new ArrayList<>();
Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String selection = MediaStore.Video.Media.MIME_TYPE + " in " + SUPPORT_FORMAT;//视频在我们支持的格式里面
String sortOrder = MediaStore.Video.Media._ID + " DESC";//按照mediaID降序排序
cursor = context.getContentResolver().query(uri, null, selection, null, sortOrder);
if (null == cursor) {
return null;
}
VideoEntity info;
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID));
String title = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.TITLE));
String album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.ALBUM));
String artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.ARTIST));
String displayName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME));
String mimeType = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.MIME_TYPE));
String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA));
long duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION));
long size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE));
if (isZ9WithMovVideo(path)) {
continue;
}
info = new VideoEntity(id, title, album, artist, displayName, mimeType, path, size, duration);
list.add(info);
}
} catch (Throwable e) {
Log.d(TAG, "getVideos: get video error");
} finally {
if (cursor != null) {
cursor.close();
}
}
return list;
}
private static String mDeviceName = null;
// 努比亚Z9不支持mov格式,单机屏蔽
private static boolean isZ9WithMovVideo(String path) {
try {
if (!TextUtils.isEmpty(path) && (path.endsWith(".mov") || path.endsWith(".MOV"))) {
if (TextUtils.isEmpty(mDeviceName)) {
mDeviceName = Build.MODEL;//获取手机型号
}
if (!TextUtils.isEmpty(mDeviceName) && mDeviceName.equals("NX511J")) {
return true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
/**
* 本地视频相册的presenter,获取本地视频筛选后把视频列表给对应的view
* Created by hsp on 2017/7/12.
*/
public class VideoAlbumPresenter extends AbstractPresenter<VideoAlbumContract.View, VideoAlbumContract.Model>
implements VideoAlbumContract.Presenter {
/**
* 手机上所有满足长度的视频
*/
private List<VideoEntity> mVerifyVideoList = new ArrayList<>();
/**
* 手机上所有的的视频
*/
private List<VideoEntity> mVideoList = new ArrayList<>();
public VideoAlbumPresenter() {
mModel = new VideoAlbumModel();
}
@Override
public void subscribe() {
loadLocalVideoList();
}
@Override
public void loadLocalVideoList() {
new VideoAlbumPresenter.LoadVideoTask().execute();
mVideoList = mModel.getVideos((Context) mView);
verifyVideoList();
if (mVerifyVideoList == null || mVerifyVideoList.size() == 0) {
mView.showEmptyContent();
} else {
mView.showLocalVideoList((ArrayList<VideoEntity>) mVerifyVideoList);
}
}
/**
* 把视频长度小于5秒或者大于10分钟的筛选掉
*/
private static boolean verifyVideo(VideoEntity mediaModel) {
if (mediaModel.getDuration() < 5000) {//至少要5秒
return false;
} else if (mediaModel.getDuration() > 10 * 60 * 1000) {
//不能大于10分钟
return false;
}
return true;
}
/**
* 获取在我们支持的长度范围内的视频list
*/
private void verifyVideoList() {
mVerifyVideoList.clear();
for (int i = 0; i < mVideoList.size(); i++) {
if (verifyVideo(mVideoList.get(i))) {
mVerifyVideoList.add(mVideoList.get(i));
}
}
}
/**
* LoadVideoTask:使用asyncTask 去获取所有的视频实体VideoEntity的相关信息的列表
*/
private class LoadVideoTask extends AsyncTask<String, Void, ArrayList<VideoEntity>> {
@Override
protected void onPreExecute() {
super.onPreExecute();
mView.showDialog();
}
@Override
protected ArrayList<VideoEntity> doInBackground(String... strings) {
return VideoProvider.getVideos((Context) mView);
}
@Override
protected void onPostExecute(ArrayList<VideoEntity> videoEntities) {
super.onPostExecute(videoEntities);
mVideoList.clear();
if (videoEntities != null) {
if (videoEntities.size() > 0) {
mVideoList.addAll(videoEntities);
}
}
mView.closeDialog();
}
}
}
//列表的item用这个,以便于能够在右下角显示时间
<?xml version="1.0" encoding="utf-8"?>
<com.meitu.overseamv.musicvideo.app.videoalbum.view.RatioRelativeLayout 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="match_parent"
android:background="@color/musv_video_album_dark_black"
app:ratioHeight="1"
app:ratioWidth="1"
app:standard="w">
<ImageView
android:id="@+id/musv_video_thumb_iv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/musv_time_tv"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="@drawable/musv_video_album_duration_bg"
android:gravity="right|bottom"
android:paddingBottom="5dp"
android:paddingRight="5dp"
android:shadowColor="@color/framework_color_black"
android:shadowDx="2"
android:shadowDy="2"
android:textColor="@color/framework_color_white"
android:textSize="13sp"
tools:text="1:02" />
<FrameLayout
android:id="@+id/fl_video_checked"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/framework_color_black50"
android:visibility="gone">
</FrameLayout>
</com.meitu.overseamv.musicvideo.app.videoalbum.view.RatioRelativeLayout>
/**
* 自定义view,让时间透明的显示在视频的右下角
* Created by hsp on 2017/7/11.
*/
public class RatioRelativeLayout extends RelativeLayout {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
private int mRatioWidth = -1;
private int mRatioHeight = -1;
private String mRatioStandard = "w";
private boolean mIsWidthHeightEvenNumber = false;
public RatioRelativeLayout(Context context) {
super(context);
}
public RatioRelativeLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RatioRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a =
context.getTheme().obtainStyledAttributes(attrs, R.styleable.Musv_Video_Album_RatioRelativeLayout, defStyleAttr, 0);
mRatioWidth = a.getInteger(R.styleable.Musv_Video_Album_RatioRelativeLayout_ratioWidth, -1);
mRatioHeight = a.getInteger(R.styleable.Musv_Video_Album_RatioRelativeLayout_ratioHeight, -1);
mRatioStandard = a.getString(R.styleable.Musv_Video_Album_RatioRelativeLayout_standard);
mIsWidthHeightEvenNumber = a.getBoolean(R.styleable.Musv_Video_Album_RatioRelativeLayout_isWidthHeightEvenNumber, false);
a.recycle();
}
// ===========================================================
// Override Methods
// ===========================================================
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec));
// Children are just made to fill our space.
if (mRatioStandard.length() > 0 && mRatioWidth != -1 && mRatioHeight != -1) {
int width = 0, height = 0;
if (mRatioStandard.equals("w")) {// 以宽为标准
width = getMeasuredWidth();
height = width * mRatioHeight / mRatioWidth;
} else if (mRatioStandard.equals("h")) {// 以高为标准
height = getMeasuredHeight();
width = height * mRatioWidth / mRatioHeight;
}
if (mIsWidthHeightEvenNumber) {
if (width % 2 != 0) {
width++;
}
if (height % 2 != 0) {
height++;
}
}
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
// ===========================================================
// Define Methods
// ===========================================================
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
// ===========================================================
// Getter & Setter
// ===========================================================
}
以上是关于java 选取本地视频相册,然后转换为recycleView展示出来,具体的实现逻辑需要的时候再捋清楚,MVP方式实现的主要内容,如果未能解决你的问题,请参考以下文章
android从相册选取图片裁剪,裁剪的时候图片变为黑色的,怎么解决???