- 效果
- 引入
//图片加载
api 'com.github.bumptech.glide:glide:4.11.0'
api 'jp.wasabeef:glide-transformations:4.0.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
//camera相机使用
api 'androidx.camera:camera-core:1.0.0-alpha04'
api 'androidx.camera:camera-camera2:1.0.0-alpha04'
api 'androidx.camera:camera-view:1.0.0-alpha01'
api 'androidx.camera:camera-extensions:1.0.0-alpha01'
//gesture imageview 图片预览
api 'com.github.chrisbanes:PhotoView:2.3.0@aar'
//视频播放组件
api 'com.google.android.exoplayer:exoplayer-core:2.10.4'
api 'com.google.android.exoplayer:exoplayer-dash:2.10.4'
api 'com.google.android.exoplayer:exoplayer-ui:2.10.4'
- 权限
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
主进入页面
- xml
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
tools:context="test.camerax.study.MainCaptureActivity">
<com.google.android.exoplayer2.ui.PlayerView
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"
app:buffered_color="#008577"
app:resize_mode="fixed_width"
app:show_buffering="when_playing"
app:surface_type="texture_view"
app:use_controller="true" />
<com.github.chrisbanes.photoview.PhotoView
android:id="@+id/photo_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginTop="90dp"
android:layout_marginBottom="60dp"
android:scaleType="fitCenter"
android:visibility="gone" />
<TextView
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="前去体验CameraX"
android:textAllCaps="true"
android:textColor="#ff0000"
android:textSize="20dp"
android:textStyle="bold" />
</FrameLayout>
</layout>
- activity
public class MainCaptureActivity extends AppCompatActivity {
private ActivityMainCaptureBinding mPreviewBinding;
public static final String RESULT_FILE_PATH = "file_path";
public static final String RESULT_FILE_WIDTH = "file_width";
public static final String RESULT_FILE_HEIGHT = "file_height";
public static final String RESULT_FILE_TYPE = "file_type";
private String previewUrl;
private boolean isVideo;
private int mWidth;
private int mHeight;
private static final String[] PERMISSIONS = new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO};
private ArrayList<String> deniedPermission = new ArrayList<>();
private static final int PERMISSION_CODE = 1000;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPreviewBinding = DataBindingUtil.setContentView(this, R.layout.activity_main_capture);
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
mPreviewBinding.tvContent.setOnClickListener(v -> {
ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_CODE);
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_CODE) {
deniedPermission.clear();
for (int i = 0; i < permissions.length; i++) {
String permission = permissions[i];
int result = grantResults[i];
if (result != PackageManager.PERMISSION_GRANTED) {
deniedPermission.add(permission);
}
}
if (deniedPermission.isEmpty()) {
CaptureActivity.startActivityForResult(this);
if (player != null) {
player.setPlayWhenReady(false);
player.stop(true);
player.release();
}
} else {
new AlertDialog.Builder(this)
.setMessage("必须的权限没有得到授权,功能将无法使用 请重新授权!")
.setNegativeButton("不", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
MainCaptureActivity.this.finish();
}
})
.setPositiveButton("好的", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String[] denied = new String[deniedPermission.size()];
ActivityCompat.requestPermissions(MainCaptureActivity.this, deniedPermission.toArray(denied), PERMISSION_CODE);
}
}).create().show();
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CaptureActivity.REQ_CAPTURE && resultCode == RESULT_OK) {
previewUrl = data.getStringExtra(RESULT_FILE_PATH);
isVideo = data.getBooleanExtra(RESULT_FILE_TYPE, false);
mWidth = data.getIntExtra(RESULT_FILE_WIDTH, 1080);
mHeight = data.getIntExtra(RESULT_FILE_HEIGHT, 1920);
StringBuffer stringBuffer = new StringBuffer();
if (isVideo) {
stringBuffer.append("恭喜你录制视频成功;");
previewVideo(previewUrl);
} else {
stringBuffer.append("恭喜你拍照成功;");
previewImage(previewUrl);
}
stringBuffer.append("宽度:" + mWidth + ",高度:" + mHeight);
mPreviewBinding.tvContent.setText(stringBuffer);
}
}
private SimpleExoPlayer player;
private void previewVideo(String previewUrl) {
mPreviewBinding.playerView.setVisibility(View.VISIBLE);
mPreviewBinding.photoView.setVisibility(View.GONE);
player = ExoPlayerFactory.newSimpleInstance(this, new DefaultRenderersFactory(this), new DefaultTrackSelector(), new DefaultLoadControl());
Uri uri = null;
File file = new File(previewUrl);
if (file.exists()) {
DataSpec dataSpec = new DataSpec(Uri.fromFile(file));
FileDataSource fileDataSource = new FileDataSource();
try {
fileDataSource.open(dataSpec);
uri = fileDataSource.getUri();
} catch (FileDataSource.FileDataSourceException e) {
e.printStackTrace();
}
} else {
uri = Uri.parse(previewUrl);
}
ProgressiveMediaSource.Factory factory = new ProgressiveMediaSource.Factory(new DefaultDataSourceFactory(this, Util.getUserAgent(this, getPackageName())));
ProgressiveMediaSource mediaSource = factory.createMediaSource(uri);
player.prepare(mediaSource);
player.setPlayWhenReady(true);
mPreviewBinding.playerView.setPlayer(player);
}
private void previewImage(String previewUrl) {
mPreviewBinding.photoView.setVisibility(View.VISIBLE);
mPreviewBinding.playerView.setVisibility(View.GONE);
Glide.with(this).load(previewUrl).into(mPreviewBinding.photoView);
}
@Override
protected void onPause() {
super.onPause();
if (player != null) {
player.setPlayWhenReady(false);
}
}
@Override
protected void onResume() {
super.onResume();
if (player != null) {
player.setPlayWhenReady(true);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (player != null) {
player.setPlayWhenReady(false);
player.stop(true);
player.release();
}
}
}
拍照页面
- 自定义按钮
/**
* 拍照使用
*/
public class RecordView extends View implements View.OnLongClickListener, View.OnClickListener {
private static final int PROGRESS_INTERVAL = 100;
private final Paint fillPaint;
private final Paint progressPaint;
private int progressMaxValue;
private final int radius;
private final int progressWidth;
private final int progressColor;
private final int fillColor;
private final int maxDuration;
private int progressValue;
private boolean isRecording;
private long startRecordTime;
private onRecordListener mListener;
public RecordView(Context context) {
this(context, null);
}
public RecordView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public RecordView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public RecordView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RecordView, defStyleAttr, defStyleRes);
radius = typedArray.getDimensionPixelOffset(R.styleable.RecordView_radius, 0);
progressWidth = typedArray.getDimensionPixelOffset(R.styleable.RecordView_progress_width, PixUtils.dp2px(3));
progressColor = typedArray.getColor(R.styleable.RecordView_progress_color, Color.RED);
fillColor = typedArray.getColor(R.styleable.RecordView_fill_color, Color.WHITE);
maxDuration = typedArray.getInteger(R.styleable.RecordView_duration, 10);
setMaxDuration(maxDuration);
typedArray.recycle();
fillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
fillPaint.setColor(fillColor);
fillPaint.setStyle(Paint.Style.FILL);
progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
progressPaint.setColor(progressColor);
progressPaint.setStyle(Paint.Style.STROKE);
progressPaint.setStrokeWidth(progressWidth);
Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
progressValue++;
postInvalidate();
if (progressValue <= progressMaxValue) {
sendEmptyMessageDelayed(0, PROGRESS_INTERVAL);
} else {
finishRecord();
}
}
};
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
isRecording = true;
startRecordTime = System.currentTimeMillis();
handler.sendEmptyMessage(0);
} else if (event.getAction() == MotionEvent.ACTION_UP) {
long now = System.currentTimeMillis();
if (now - startRecordTime > ViewConfiguration.getLongPressTimeout()) {
finishRecord();
}
handler.removeCallbacksAndMessages(null);
isRecording = false;
startRecordTime = 0;
progressValue = 0;
postInvalidate();
}
return false;
}
});
setOnClickListener(this);
setOnLongClickListener(this);
}
private void finishRecord() {
if (mListener != null) {
mListener.onFinish();
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
if (isRecording) {
canvas.drawCircle(width / 2, height / 2, width / 2, fillPaint);
int left = progressWidth / 2;
int top = progressWidth / 2;
int right = width - progressWidth / 2;
int bottom = height - progressWidth / 2;
float sweepAngle = (progressValue * 1.0f / progressMaxValue) * 360;
canvas.drawArc(left, top, right, bottom, -90, sweepAngle, false, progressPaint);
} else {
canvas.drawCircle(width / 2, height / 2, radius, fillPaint);
}
}
public void setMaxDuration(int maxDuration) {
this.progressMaxValue = maxDuration * 1000 / PROGRESS_INTERVAL;
}
public void setOnRecordListener(onRecordListener listener) {
mListener = listener;
}
@Override
public boolean onLongClick(View v) {
if (mListener != null) {
mListener.onLongClick();
}
return true;
}
@Override
public void onClick(View v) {
if (mListener != null) {
mListener.onClick();
}
}
public interface onRecordListener {
void onClick();
void onLongClick();
void onFinish();
}
}
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RecordView">
<attr name="progress_color" format="color"></attr>
<attr name="progress_width" format="dimension"></attr>
<attr name="fill_color" format="color"></attr>
<attr name="radius" format="dimension"></attr>
<attr name="duration" format="integer"></attr>
</declare-styleable>
</resources>
- 拍照xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextureView
android:id="@+id/texture_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/capture_tips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="200dp"
android:text="轻触拍照,长按摄像"
android:textColor="#ffffff" />
<cn.yumakeji.lib_common.view.RecordView
android:id="@+id/record_view"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="60dp"
app:duration="10"
app:fill_color="#ffffff"
app:progress_color="@color/colorAccent"
app:progress_width="4dp"
app:radius="40dp" />
</FrameLayout>
</layout>
- CaptureActivity
import cn.yumakeji.jetpackroomstudy.R;
import cn.yumakeji.jetpackroomstudy.databinding.ActivityCaptureBinding;
import cn.yumakeji.lib_common.view.RecordView;
public class CaptureActivity extends AppCompatActivity {
public static final int REQ_CAPTURE = 10001;
private ActivityCaptureBinding mBinding;
private Preview preview;
private ImageCapture imageCapture;
private VideoCapture videoCapture;
private TextureView textureView;
private String outputFilePath;
public static void startActivityForResult(Activity activity) {
Intent intent = new Intent(activity, CaptureActivity.class);
activity.startActivityForResult(intent, REQ_CAPTURE);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_capture);
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
bindCameraX();
initListener();
}
/**
* 前后摄像头
*/
private CameraX.LensFacing mLensFacing = CameraX.LensFacing.BACK;
/**
* 旋转角度
*/
private int rotation = Surface.ROTATION_0;
/**
* 分辨率
*/
private Size resolution = new Size(1280, 720);
/**
* 宽高比
*/
private Rational rational = new Rational(9, 16);
/**
* 初始化配置
*/
@SuppressLint("RestrictedApi")
private void bindCameraX() {
//查询一下当前要使用的设备摄像头(比如后置摄像头)是否存在
boolean hasAvailableCameraId = false;
try {
hasAvailableCameraId = CameraX.hasCameraWithLensFacing(mLensFacing);
} catch (CameraInfoUnavailableException e) {
e.printStackTrace();
}
if (!hasAvailableCameraId) {
Toast.makeText(this, "无可用的设备cameraId!,请检查设备的相机是否被占用", Toast.LENGTH_LONG).show();
finish();
return;
}
//查询一下是否存在可用的cameraId.形式如:后置:"0",前置:"1"
String cameraIdForLensFacing = null;
try {
cameraIdForLensFacing = CameraX.getCameraFactory().cameraIdForLensFacing(mLensFacing);
} catch (CameraInfoUnavailableException e) {
e.printStackTrace();
}
if (TextUtils.isEmpty(cameraIdForLensFacing)) {
Toast.makeText(this, "无可用的设备cameraId!,请检查设备的相机是否被占用", Toast.LENGTH_LONG).show();
finish();
return;
}
/**
* 预览功能
*/
preview = new Preview(new PreviewConfig.Builder()
//前后摄像头
.setLensFacing(mLensFacing)
//旋转角度
.setTargetRotation(rotation)
//分辨率
.setTargetResolution(resolution)
//宽高比
.setTargetAspectRatio(rational)
.build());
/**
* 拍照
*/
imageCapture = new ImageCapture(new ImageCaptureConfig.Builder()
//宽高比
.setTargetAspectRatio(rational)
//分辨率
.setTargetResolution(resolution)
//前后摄像头
.setLensFacing(mLensFacing)
//ImageCapture.CaptureMode.MIN_LATENCY:快速合成
//ImageCapture.CaptureMode.MAX_QUALITY:原图
.setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
//旋转角度
.setTargetRotation(rotation).build());
/**
* 视频
*/
videoCapture = new VideoCapture(new VideoCaptureConfig.Builder()
.setTargetRotation(rotation)
.setLensFacing(mLensFacing)
.setTargetResolution(resolution)
.setTargetAspectRatio(rational)
//视频帧率
.setVideoFrameRate(25)
//bit率
.setBitRate(3 * 1024 * 1024).build());
//视频流回调
preview.setOnPreviewOutputUpdateListener(new Preview.OnPreviewOutputUpdateListener() {
@Override
public void onUpdated(Preview.PreviewOutput output) {
textureView = mBinding.textureView;
ViewGroup parent = (ViewGroup) textureView.getParent();
//先removeView后addView才被渲染上来
parent.removeView(textureView);
parent.addView(textureView, 0);
textureView.setSurfaceTexture(output.getSurfaceTexture());
}
});
//上面配置的都是我们期望的分辨率
List<UseCase> newUseList = new ArrayList<>();
newUseList.add(preview);
newUseList.add(imageCapture);
newUseList.add(videoCapture);
//下面我们要查询一下 当前设备它所支持的分辨率有哪些,然后再更新一下 所配置的几个usecase
Map<UseCase, Size> resolutions = CameraX.getSurfaceManager()
.getSuggestedResolutions(cameraIdForLensFacing, null, newUseList);
Iterator<Map.Entry<UseCase, Size>> iterator = resolutions.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<UseCase, Size> next = iterator.next();
UseCase useCase = next.getKey();
Size value = next.getValue();
Map<String, Size> update = new HashMap<>();
update.put(cameraIdForLensFacing, value);
useCase.updateSuggestedResolution(update);
}
CameraX.bindToLifecycle(this, preview, imageCapture, videoCapture);
}
private boolean takingPicture;
/**
* 拍照操作
*/
private void initListener() {
mBinding.recordView.setOnRecordListener(new RecordView.onRecordListener() {
@Override
public void onClick() {
takingPicture = true;
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
System.currentTimeMillis() + ".jpeg");
mBinding.captureTips.setVisibility(View.INVISIBLE);
imageCapture.takePicture(file, new ImageCapture.OnImageSavedListener() {
@Override
public void onImageSaved(@NonNull File file) {
onFileSaved(file);
}
@SuppressLint("RestrictedApi")
@Override
public void onError(@NonNull ImageCapture.UseCaseError useCaseError, @NonNull String message, @Nullable Throwable cause) {
ArchTaskExecutor.getMainThreadExecutor().execute(() -> {
Toast.makeText(CaptureActivity.this, message, Toast.LENGTH_SHORT).show();
});
}
});
}
@SuppressLint("RestrictedApi")
@Override
public void onLongClick() {
takingPicture = false;
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
System.currentTimeMillis() + ".mp4");
videoCapture.startRecording(file, new VideoCapture.OnVideoSavedListener() {
@Override
public void onVideoSaved(File file) {
onFileSaved(file);
}
@Override
public void onError(VideoCapture.UseCaseError useCaseError, String message, @Nullable Throwable cause) {
ArchTaskExecutor.getMainThreadExecutor().execute(() -> {
Toast.makeText(CaptureActivity.this, message, Toast.LENGTH_SHORT).show();
});
}
});
}
@SuppressLint("RestrictedApi")
@Override
public void onFinish() {
videoCapture.stopRecording();
}
});
}
/**
* 获得视频、图片去预览
*
* @param file
*/
private void onFileSaved(File file) {
outputFilePath = file.getAbsolutePath();
String mimeType = takingPicture ? "image/jpeg" : "video/mp4";
MediaScannerConnection.scanFile(this, new String[]{outputFilePath}, new String[]{mimeType}, null);
PreviewActivity.startActivityForResult(this, outputFilePath, !takingPicture, "完成");
}
public static final String RESULT_FILE_PATH = "file_path";
public static final String RESULT_FILE_WIDTH = "file_width";
public static final String RESULT_FILE_HEIGHT = "file_height";
public static final String RESULT_FILE_TYPE = "file_type";
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PreviewActivity.REQ_PREVIEW && resultCode == RESULT_OK) {
Intent intent = new Intent();
intent.putExtra(RESULT_FILE_PATH, outputFilePath);
//当设备处于竖屏情况时,宽高的值 需要互换,横屏不需要
intent.putExtra(RESULT_FILE_WIDTH, resolution.getHeight());
intent.putExtra(RESULT_FILE_HEIGHT, resolution.getWidth());
intent.putExtra(RESULT_FILE_TYPE, !takingPicture);
setResult(RESULT_OK, intent);
finish();
}
}
@Override
public void onDetachedFromWindow() {
CameraX.unbindAll();
super.onDetachedFromWindow();
}
}
预览页面
- xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
android:orientation="vertical">
<com.google.android.exoplayer2.ui.PlayerView
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"
app:buffered_color="#008577"
app:resize_mode="fixed_width"
app:show_buffering="when_playing"
app:surface_type="texture_view"
app:use_controller="false" />
<com.github.chrisbanes.photoview.PhotoView
android:id="@+id/photo_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginTop="90dp"
android:layout_marginBottom="60dp"
android:scaleType="fitCenter"
android:visibility="gone" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/action_close"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp"
app:srcCompat="@mipmap/icon_close"
app:tint="#ffffff" />
<com.google.android.material.button.MaterialButton
android:id="@+id/action_ok"
android:layout_width="60dp"
android:layout_height="30dp"
android:layout_gravity="right|top"
android:layout_marginTop="16dp"
android:layout_marginRight="16dp"
android:gravity="center"
android:text="完成"
app:backgroundTint="#008577"
app:cornerRadius="5dp"/>
</FrameLayout>
</layout>
- PreviewActivity
public class PreviewActivity extends AppCompatActivity implements View.OnClickListener {
public static final int REQ_PREVIEW = 1000;
public static final String KEY_PREVIEW_URL = "preview_url";
public static final String KEY_PREVIEW_VIDEO = "preview_video";
public static final String KEY_PREVIEW_BTNTEXT = "preview_btntext";
private ActivityPreviewBinding mPreviewBinding;
private SimpleExoPlayer player;
public static void startActivityForResult(Activity activity, String previewUrl, boolean isVideo, String btnText) {
Intent intent = new Intent(activity, PreviewActivity.class);
intent.putExtra(KEY_PREVIEW_URL, previewUrl);
intent.putExtra(KEY_PREVIEW_VIDEO, isVideo);
intent.putExtra(KEY_PREVIEW_BTNTEXT, btnText);
activity.startActivityForResult(intent, REQ_PREVIEW);
activity.overridePendingTransition(0, 0);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPreviewBinding = DataBindingUtil.setContentView(this, R.layout.activity_preview);
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
String previewUrl = getIntent().getStringExtra(KEY_PREVIEW_URL);
boolean isVideo = getIntent().getBooleanExtra(KEY_PREVIEW_VIDEO, false);
String btnText = getIntent().getStringExtra(KEY_PREVIEW_BTNTEXT);
if (TextUtils.isEmpty(btnText)) {
mPreviewBinding.actionOk.setVisibility(View.GONE);
} else {
mPreviewBinding.actionOk.setVisibility(View.VISIBLE);
mPreviewBinding.actionOk.setText(btnText);
mPreviewBinding.actionOk.setOnClickListener(this);
}
mPreviewBinding.actionClose.setOnClickListener(this);
if (isVideo) {
previewVideo(previewUrl);
} else {
previewImage(previewUrl);
}
}
/**
* 预览图片
*
* @param previewUrl
*/
private void previewImage(String previewUrl) {
mPreviewBinding.photoView.setVisibility(View.VISIBLE);
Glide.with(this).load(previewUrl).into(mPreviewBinding.photoView);
}
/**
* 预览视频
*
* @param previewUrl
*/
private void previewVideo(String previewUrl) {
mPreviewBinding.playerView.setVisibility(View.VISIBLE);
player = ExoPlayerFactory.newSimpleInstance(this, new DefaultRenderersFactory(this), new DefaultTrackSelector(), new DefaultLoadControl());
Uri uri = null;
File file = new File(previewUrl);
if (file.exists()) {
DataSpec dataSpec = new DataSpec(Uri.fromFile(file));
FileDataSource fileDataSource = new FileDataSource();
try {
fileDataSource.open(dataSpec);
uri = fileDataSource.getUri();
} catch (FileDataSource.FileDataSourceException e) {
e.printStackTrace();
}
} else {
uri = Uri.parse(previewUrl);
}
ProgressiveMediaSource.Factory factory = new ProgressiveMediaSource.Factory(new DefaultDataSourceFactory(this, Util.getUserAgent(this, getPackageName())));
ProgressiveMediaSource mediaSource = factory.createMediaSource(uri);
player.prepare(mediaSource);
player.setPlayWhenReady(true);
mPreviewBinding.playerView.setPlayer(player);
}
@Override
protected void onPause() {
super.onPause();
if (player != null) {
player.setPlayWhenReady(false);
}
}
@Override
protected void onResume() {
super.onResume();
if (player != null) {
player.setPlayWhenReady(true);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (player != null) {
player.setPlayWhenReady(false);
player.stop(true);
player.release();
}
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.action_close) {
finish();
} else if (v.getId() == R.id.action_ok) {
setResult(RESULT_OK, new Intent());
finish();
}
}
}
oss上传下载文件
//aliyun oss
api 'com.aliyun.dpa:oss-android-sdk:+'
/**
* 阿里云oss 文件上传
*/
public class FileUploadManager {
private static OSSClient oss = null;
private static final String ALIYUN_BUCKET_URL = "https://******.oss-cn-hangzhou.aliyuncs.com/";
private static final String BUCKET_NAME = "******";
private static final String END_POINT = "http://oss-cn-******.aliyuncs.com";
private static final String AUTH_SERVER_URL = "http://******:7080/";
static {
OSSCredentialProvider credentialProvider = new OSSAuthCredentialsProvider(AUTH_SERVER_URL);
//该配置类如果不设置,会有默认配置,具体可看该类
ClientConfiguration conf = new ClientConfiguration();
conf.setConnectionTimeout(15 * 1000); // 连接超时,默认15秒
conf.setSocketTimeout(15 * 1000); // socket超时,默认15秒
conf.setMaxConcurrentRequest(5); // 最大并发请求数,默认5个
conf.setMaxErrorRetry(2); // 失败后最大重试次数,默认2次
OSSLog.disableLog(); //这个开启会支持写入手机sd卡中的一份日志文件位置在SDCard_path\OSSLog\logs.csv
oss = new OSSClient(AppGlobals.getApplication(), END_POINT, credentialProvider, conf);
}
//同步
public static String upload(byte[] bytes) throws ClientException, ServiceException {
String objectKey = String.valueOf(System.currentTimeMillis());
PutObjectRequest request = new PutObjectRequest(BUCKET_NAME, objectKey, bytes);
PutObjectResult result = oss.putObject(request);
if (result.getStatusCode() == 200) {
return ALIYUN_BUCKET_URL + objectKey;
} else {
return null;
}
}
//异步
public static void upload(byte[] bytes, UploadCallback callback) {
String objectKey = String.valueOf(System.currentTimeMillis());
PutObjectRequest request = new PutObjectRequest(BUCKET_NAME, objectKey, bytes);
upload(request, callback);
}
//同步
public static String upload(String filePath) {
String objectKey = filePath.substring(filePath.lastIndexOf("/") + 1);
PutObjectRequest request = new PutObjectRequest(BUCKET_NAME, objectKey, filePath);
PutObjectResult result = null;
try {
result = oss.putObject(request);
} catch (ClientException e) {
e.printStackTrace();
} catch (ServiceException e) {
e.printStackTrace();
}
if (result != null && result.getStatusCode() == 200) {
return ALIYUN_BUCKET_URL + objectKey;
} else {
return null;
}
}
//异步
public static void upload(String filePath, UploadCallback callback) {
String objectKey = filePath.substring(filePath.lastIndexOf("/") + 1);
PutObjectRequest request = new PutObjectRequest(BUCKET_NAME, objectKey, filePath);
upload(request, callback);
}
private static void upload(final PutObjectRequest put, final UploadCallback callback) {
put.setProgressCallback(new OSSProgressCallback<PutObjectRequest>() {
@Override
public void onProgress(PutObjectRequest request, long currentSize, long totalSize) {
Log.e("PutObject", "currentSize: " + currentSize + " totalSize: " + totalSize);
}
});
OSSAsyncTask task = oss.asyncPutObject(put, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
@Override
public void onSuccess(PutObjectRequest request, PutObjectResult result) {
String eTag = result.getETag();
String serverCallbackReturnBody = result.getServerCallbackReturnBody();
Log.e("PutObject", "UploadSuccess" + eTag + "--" + serverCallbackReturnBody);
if (callback != null && result.getStatusCode() == 200) {
callback.onUpload(ALIYUN_BUCKET_URL + put.getObjectKey());
}
}
@Override
public void onFailure(PutObjectRequest request, ClientException clientExcepion, ServiceException serviceException) {
printError(clientExcepion, serviceException);
if (callback != null) {
callback.onError(serviceException.getRawMessage());
}
}
});
}
public void download(String url, final String filePath, final DownloadCallback callback) {
// 构造下载文件请求
GetObjectRequest get = new GetObjectRequest(BUCKET_NAME, url);
OSSAsyncTask task = oss.asyncGetObject(get, new OSSCompletedCallback<GetObjectRequest, GetObjectResult>() {
@Override
public void onSuccess(GetObjectRequest request, GetObjectResult result) {
Log.d("Content-Length", "" + result.getContentLength());
//FileUtil.SaveFile(filePath, result.getObjectContent());
if (callback != null) {
callback.onDownloadSuccess(filePath);
}
}
@Override
public void onFailure(GetObjectRequest request, ClientException clientExcepion, ServiceException serviceException) {
// 请求异常
printError(clientExcepion, serviceException);
if (callback != null) {
callback.onError(serviceException.getRawMessage());
}
}
});
}
private static void printError(ClientException clientExcepion, ServiceException serviceException) {
// 请求异常
if (clientExcepion != null) {
// 本地异常如网络异常等
clientExcepion.printStackTrace();
}
if (serviceException != null) {
// 服务异常
Log.e("ErrorCode", serviceException.getErrorCode());
Log.e("RequestId", serviceException.getRequestId());
Log.e("HostId", serviceException.getHostId());
Log.e("RawMessage", serviceException.getRawMessage());
}
}
public interface UploadCallback {
void onUpload(String result);
void onError(String error);
}
public interface DownloadCallback {
void onDownloadSuccess(String fileUrl);
void onError(String error);
}
}