일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 안드로이드 카카오 지도
- 안드로이드광고
- component
- 다이나믹 링크
- 애드몹광고
- RecyclerView
- 안드로이드 라이브러리
- android daum map
- glide
- 파이어베이스
- 아키텍처
- HTTP
- ImageView
- 클린 아키텍처
- Android 애드몹
- 젯팩컴포즈
- 안드로이드
- Clean Architecture
- 안드로이드컴포즈
- 동적 링크
- android 지도
- 애드몹배너
- JetpackCompose
- dynamiclink
- Android
- Firebase
- android kakao map
- 컴포넌트
- thread
- 선언형UI
- Today
- Total
코딩스토리
[Android/안드로이드] ImageVideoView / url에 따라 이미지나 비디오를 하나의 뷰로 만들기 본문
인스타그램에서 ViewPager로 옆으로 스크롤하는부분인데 이미지가 나올 때 있고, 동영상이 나올 때가 있습니다. 이번 시간에는 하나의 뷰로 url의 확장자가 이미지형 확장자일 경우 이미지뷰를 보여주고, 비디오형 확장자일 경우는 비디오뷰를 보여줄 수 있는 이미지비디오뷰를 만들어보겠습니다.
비디오 뷰는 안드로이드에서 기본적으로 제공하는 비디오를 사용하지 않고 구글에서 만든 오픈소스 미디어 플레이 라이브러리인 ExoPlayer를 사용해 보겠습니다. ExoPlayer는 기존 비디오뷰보다 더욱 작고 유연하며 안정적이라 유튜브와 구글무비에서도 사용한답니다~
우선 ExoPlayer를 사용하기 위한 사용법에 대해 알아보겠습니다.
라이브러리 추가
build.gradle(Module: app)
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.example.imagevideoviewtest"
minSdkVersion 15
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
targetCompatibility = "8"
sourceCompatibility = "8"
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
// ExoPlayer
implementation 'com.google.android.exoplayer:exoplayer:2.9.6'
implementation 'com.google.android.exoplayer:exoplayer-core:2.9.6'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.9.6'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.9.6'
//Glide 이미지변환
implementation 'com.github.bumptech.glide:glide:4.9.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
}
위 에서 ExoPlayer를 사용하기 위해 라이브러리를 추가해주고, 이미지를 로드해주는 Glide 라이브러리를 추가해줍니다.
위 코드중에 아래와 같은 부분이 있습니다. ExoPlayer는 자바8을 사용하기 때문에 이를 사용할 수 있게 해주는 라이브러리를 추가해줘야합니다.
추가해주지 않을 경우
java.lang.BootstrapMethodError: Exception from call site #62 bootstrap method
오류가 나게됩니다..
compileOptions {
targetCompatibility = "8"
sourceCompatibility = "8"
}
ExoPlayerView를 사용하기 위해서는 미디어 플레이어 초기화시켜줘야하고, 미디어 소스도 초기화해주는 등 한번만 만들게되면 상관이 없는데 여러군데에서 사용할게 되면 이 코드를 똑같이 여러개 만들어줘야합니다.
저는 그게 싫어서 url만 호출하면 되게 ExoPlayVier를 사용할 수 있는 모듈을 따로 만들어놓았습니다.
CustomExoPlayerView 생성
CustomExoPlayerView.java
package com.example.imagevideoviewtest;
import android.content.Context;
import android.graphics.Color;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.ui.PlayerView;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.util.Util;
public class CustomExoPlayerView extends PlayerView {
SimpleExoPlayer player;
DataSource.Factory mediaDataSourceFactory;
DefaultTrackSelector trackSelector;
TrackGroupArray lastSeenTrackGroupArray;
AdaptiveTrackSelection.Factory videoTrackSelectionFactory;
public CustomExoPlayerView(Context context) {
super(context);
}
public CustomExoPlayerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomExoPlayerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void initializePlayer(String url) {
if (trackSelector != null) {
Log.i("DATA", "trankSelector : not null");
} else {
Log.i("DATA", "trankSelector : null");
}
trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
mediaDataSourceFactory = new DefaultDataSourceFactory(getContext(), Util.getUserAgent(getContext(), "mediaPlayerSample"));
ExtractorMediaSource mediaSource = new ExtractorMediaSource.Factory(mediaDataSourceFactory)
.createMediaSource(Uri.parse(url));
player = ExoPlayerFactory.newSimpleInstance(getContext(), trackSelector);
player.prepare(mediaSource, false, false);
player.setPlayWhenReady(true);
setShutterBackgroundColor(Color.TRANSPARENT);
setPlayer(player);
requestFocus();
lastSeenTrackGroupArray = null;
}
//현재 동영상의 시간
public int getCurrentPosition(){
return (int) player.getCurrentPosition();
}
//동영상이 실행되고있는지 확인
public boolean isPlaying(){
return player.getPlayWhenReady();
}
//동영상 정지
public void pause(){
player.setPlayWhenReady(false);
}
//동영상 재생
public void start(){
player.setPlayWhenReady(true);
}
//동영상 시간 설정
public void seekTo(int position){
player.seekTo(position);
}
@Override
public void onResume() {
super.onResume();
Log.i("DATADATA","onResume");
player.setPlayWhenReady(true);
}
@Override
public void onPause() {
super.onPause();
Log.i("DATADATA","onPause");
player.setPlayWhenReady(false);
}
//동영상 해제
public void releasePlayer() {
player.release();
trackSelector = null;
}
}
상세 기능(현재 동영상이 재생되는지, 동영상 정지, 동영상 재생, 동영상 시간 설정, 동영상 시간 가져오기)기능은 여기서 사용하지 않지만 호출하면 사용할 수 있게 만들어 놓았습니다. releasePlayer를 통해 Activity에서 빠져나가거나 종료를 했을 때 동영상을 해제해줘야합니다. 해제해주지 않으면 화면을 이동해도 계속 동영상이 재생됩니다..
ExoPlayerView를 쉽게 생성하는 커스텀뷰를 만들었지만 저희가 이번시간에 만들게 될 뷰는 하나의 뷰에서 이미지와 동영상을 구분해 보여주는 뷰를 만들 것이라 이 기능을 가진 CustomView를 생성해줍니다.
이미지/동영상 구분해 보여주는 ImageVideoView 생성
ImageVideoView.java
package com.example.imagevideoviewtest;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
public class ImageVideoView extends LinearLayout {
Context mContext;
CustomExoPlayerView customExoPlayerView;
ImageView imageView;
public ImageVideoView(Context context) {
super(context);
initView(context);
}
public ImageVideoView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public ImageVideoView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
private void initView(Context context) {
mContext = context;
setBackgroundColor(Color.BLACK);
}
//url이 비디오 형식일 경우 exoplayerview를 실행
//url이 이미지 형식일 경우 imageview load
public void setUrl(String url) {
if (isVideo(url)) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
customExoPlayerView = new CustomExoPlayerView(mContext);
customExoPlayerView.setLayoutParams(params);
addView(customExoPlayerView);
customExoPlayerView.initializePlayer(url);
} else {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
imageView = new ImageView(mContext);
imageView.setLayoutParams(params);
addView(imageView);
Glide.with(this).load(url).diskCacheStrategy(DiskCacheStrategy.AUTOMATIC).into(imageView);
}
}
//확장자가 비디오인지 이미지인지 확인
private Boolean isVideo(String path) {
String extension = getExtension(path);
if (extension.equals("mp4") || extension.equals("MP4") || extension.equals("MOV") || extension.equals("mov") || extension.equals("AVI") || extension.equals("avi") ||
extension.equals("MKV") || extension.equals("mkv") || extension.equals("WMV") || extension.equals("wmv") || extension.equals("TS") || extension.equals("ts") ||
extension.equals("TP") || extension.equals("tp") || extension.equals("FLV") || extension.equals("flv") || extension.equals("3GP") || extension.equals("3gp") ||
extension.equals("MPG") || extension.equals("mpg") || extension.equals("MPEG") || extension.equals("mpeg") || extension.equals("MPE") || extension.equals("mpe") ||
extension.equals("ASF") || extension.equals("asf") || extension.equals("ASX") || extension.equals("asx") || extension.equals("DAT") || extension.equals("dat") ||
extension.equals("RM") || extension.equals("rm")) {
return true;
} else {
return false;
}
}
//확장자 나누기
private String getExtension(String url) {
return url.substring(url.lastIndexOf(".") + 1, url.length());
}
//동영상 해제
public void releasePlayer() {
if(customExoPlayerView != null){
customExoPlayerView.releasePlayer();
}
}
}
호출할 떄 받아 온 url의 확장자를 가지고 비디오인지 이미지인지 분류를 해서 이미지일 경우 뷰에 이미지뷰를 넣어주고, 동영상일 경우 뷰에 아까만든 CustomExoPlayerView를 만들어줍니다.
호출 방법
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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="match_parent"
tools:context=".MainActivity">
<com.example.imagevideoviewtest.ImageVideoView
android:id="@+id/imageVideoView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java
package com.example.imagevideoviewtest;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
ImageVideoView imageVideoView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageVideoView = findViewById(R.id.imageVideoView);
imageVideoView.setUrl("이미지or비디오 url");
}
@Override
protected void onPause() {
super.onPause();
if(imageVideoView != null){
imageVideoView.releasePlayer();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(imageVideoView != null){
imageVideoView.releasePlayer();
}
}
@Override
protected void onStop() {
super.onStop();
if(imageVideoView != null){
imageVideoView.releasePlayer();
}
}
}
ImageVideoView에 아까 생성한 setUrl메소드를 통해 url을 넘겨주게 되면 뷰에서 알아서 이미지인지, 비디오인지 구분을 해 보여주게 됩니다.
아까 말했다싶이 Activity가 종료되었을 때 releasePlayer를 통해 동영상을 해제시켜줍니다.
아! 여기서 동영상이나 이미지를 인터넷에 있는 url을 가져왔을 경우에는 실행을 해도 화면이 안나올겁니다...
이유는 Android 9.0 Pie에서는 https를 사용하도록 강요합니다. 이전 글에서 보여준 방법을 사용하시면 정상적으로 이미지나 동영상을 재생할 수 있습니다.
2020/01/04 - [Android/유용한 기술] - [Android/안드로이드] Android OS 9 Pie버전에서 http사용하기
결과화면
위에 사진은 url을 동영상 형식으로 주었을 경우 나온 화면이고, 아래 화면은 이미지 형식으로 주었을 경우에 나온 화면입니다.
궁금하신점이나 제가 빠뜨린점이 있다면 댓글 남겨주세요~~
'Android > 유용한 기술' 카테고리의 다른 글
[Android/ 안드로이드] 브레이크포인트 (Break Point )한번에 모두 지우기 (0) | 2020.02.06 |
---|---|
[Android/안드로이드] Debug에서 SHA-1 값 알아내기 (1) | 2020.02.03 |
[Android/안드로이드] Android OS 9 Pie버전에서 http사용하기 (0) | 2020.01.04 |
[Android/안드로이드] 카카오톡 로그인 연동 (15) | 2020.01.03 |
[Android/안드로이드] 모서리 둥근 이미지뷰 만들기/RoundImageView (0) | 2019.12.30 |