개요
MediaPlayer 라이브러리를 사용하여 사용자의 녹음 폴더에 있는 녹음파일을 재생하는 기능을 구현해보겠다.
1. Layout 구성
<activity_main.xml>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:orientation="vertical"
android:gravity="center">
<Button
android:id="@+id/btn_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="녹음 목록"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</LinearLayout>
녹음 목록을 띄우는 버튼과 녹음 목록 리스트를 구성한다.
<listview.xml>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/record"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/record_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"/>
</LinearLayout>
</LinearLayout>
녹음 목록을 리스트로 표현하기 위한 xml이다.
2. Manifest 권한 추가
<AndroidManifest.xml>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
매니페스트에 외부저장소에 접근할 수 있는 권한을 추가한다.
- 외부저장소: 휴대폰 기기에 파일들을 저장하는 곳(사진, 동영상, 파일 등)
- 내부저장소: 앱 내에 데이터를 저장하는 곳
3. 어댑터 정의
<MyAdapter.java>
public View getView(int i, View view, ViewGroup viewGroup) {
View mView = mLayoutInflater.inflate(R.layout.listview, null);
TextView record_name = mView.findViewById(R.id.record_name);
record_name.setText(sample.get(i).getRecord_name());
return mView;
}
리스트를 나타내기 위한 어댑터 정의 후 리스트뷰 띄우기
4. 리스트 항목 정의
<SampleData.java>
public class SampleData {
private String record_name;
public SampleData(String record_name){
this.record_name = record_name;
}
public String getRecord_name(){
return this.record_name;
}
}
리스트뷰에 띄울 항목들 정의 (현재 파일 이름만 띄우도록 해놨음)
5. 변수 선언
<MainActivity.java>
// Layout
Button btn_list;
// List
ArrayList<SampleData> dataArrayList;
private MyAdapter myAdapter;
// MediaPlayer
private MediaPlayer mediaPlayer;
private int stateMediaPlayer;
private final int STATE_NOTSTARTER = 0;
private final int STATE_PLAYING = 1;
private final int STATE_PAUSING = 2;
private static String folderName = "Call";
folderName
: 통화 녹음파일이 저장되는 폴더 (다른 파일 띄울 시 경로 수정 필요)
6. 권한 요청
<MainActivity.java>
private void requestPermission(){
if (Build.VERSION.SDK_INT >= 23 && ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(
this,
new String[] {Manifest.permission.READ_EXTERNAL_STORAGE}, 0
);
}
}
외부저장소 접근은 위험권한이기 때문에 권한 요청이 필요하다.
7. 리스트뷰 띄우기
<MainActivity.java>
@RequiresApi(api = Build.VERSION_CODES.N)
private void showRecordList(){
dataArrayList = new ArrayList<SampleData>();
myAdapter = new MyAdapter(MainActivity.this, dataArrayList);
List<String> fileList = getRecordList();
if(fileList.size() != 0){
for (int i=0; i<5; i++){
String file = fileList.get(i);
dataArrayList.add(new SampleData(file));
}
} else{
dataArrayList.add(0, new SampleData("녹음파일이 없습니다."));
}
myAdapter.notifyDataSetChanged();
}
경로에 파일이 없을 경우 예외처리
8. 녹음 파일 가져오기
<MainActivity.java>
@RequiresApi(api = Build.VERSION_CODES.N)
private List<String> getRecordList(){
File filepath = Environment.getExternalStorageDirectory();
String path = filepath.getPath(); // /storage/emulated/0
File directory = new File(path+"/"+folderName);
File[] files = directory.listFiles();
Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed());
List<String> filesNameList = new ArrayList<>();
for (int i=0; i<files.length; i++){
Log.d(TAG, files[i].getName());
filesNameList.add(files[i].getName());
}
return filesNameList;
}
- 마지막 수정날짜로 정렬 후 녹음 목록 가져오기
- 정렬하는 부분은 안드로이드N부터 함수 사용 가능
- 버전이 낮은 경우 다른 정렬 코드 작성 필요
9. 리스트 클릭 시 녹음파일 재생
<MainActivity.java>
ListView listView = findViewById(R.id.listView);
listView.setAdapter(myAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
String fileName = myAdapter.getItem(i).getRecord_name();
initMediaPlayer(fileName);
switch (stateMediaPlayer) {
case STATE_NOTSTARTER:
mediaPlayer.start();
stateMediaPlayer = STATE_PLAYING;
Toast.makeText(MainActivity.this, "재생", Toast.LENGTH_SHORT).show();
break;
case STATE_PLAYING:
mediaPlayer.pause();
stateMediaPlayer = STATE_PAUSING;
break;
case STATE_PAUSING:
mediaPlayer.start();
stateMediaPlayer = STATE_PLAYING;
break;
}
}
});
리스트 클릭 시 해당 녹음파일을 재생한다.
10. 미디어 플레이어 초기화
<MainActivity.java>
private void initMediaPlayer(String fileName){
File filepath = Environment.getExternalStorageDirectory();
String path = filepath.getPath(); // /storage/emulated/0
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(path+"/"+folderName+"/"+fileName);
mediaPlayer.prepare();
stateMediaPlayer = STATE_NOTSTARTER;
} catch (IOException e) {
e.printStackTrace();
}
}
재생시킬 파일을 가져와 셋팅한다.
11. 결과
12. 전체 코드
<activity_main.xml>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:orientation="vertical"
android:gravity="center">
<Button
android:id="@+id/btn_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="녹음 목록"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</LinearLayout>
<listview.xml>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/record"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/record_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"/>
</LinearLayout>
</LinearLayout>
<AndroidManifest.xml>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.playrecordedfile">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.PlayRecordedFile">
<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<MyAdapter.java>
package com.example.playrecordedfile;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.ArrayList;
public class MyAdapter extends BaseAdapter {
Context mContext = null;
LayoutInflater mLayoutInflater = null;
ArrayList<SampleData> sample;
public MyAdapter(Context context, ArrayList<SampleData> data){
mContext = context;
sample = data;
mLayoutInflater = LayoutInflater.from(mContext);
}
@Override
public int getCount() {
return sample.size();
}
@Override
public SampleData getItem(int i) {
return sample.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
View mView = mLayoutInflater.inflate(R.layout.listview, null);
TextView record_name = mView.findViewById(R.id.record_name);
record_name.setText(sample.get(i).getRecord_name());
return mView;
}
}
<SampleData.java>
package com.example.playrecordedfile;
public class SampleData {
private String record_name;
public SampleData(String record_name){
this.record_name = record_name;
}
public String getRecord_name(){
return this.record_name;
}
}
<MainActivity.java>
package com.example.playrecordedfile;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainTag";
// Layout
Button btn_list;
// List
ArrayList<SampleData> dataArrayList;
private MyAdapter myAdapter;
// MediaPlayer
private MediaPlayer mediaPlayer;
private int stateMediaPlayer;
private final int STATE_NOTSTARTER = 0;
private final int STATE_PLAYING = 1;
private final int STATE_PAUSING = 2;
private static String folderName = "Call";
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestPermission();
btn_list = findViewById(R.id.btn_list);
btn_list.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showRecordList();
ListView listView = findViewById(R.id.listView);
listView.setAdapter(myAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
String fileName = myAdapter.getItem(i).getRecord_name();
initMediaPlayer(fileName);
switch (stateMediaPlayer) {
case STATE_NOTSTARTER:
mediaPlayer.start();
stateMediaPlayer = STATE_PLAYING;
Toast.makeText(MainActivity.this, "재생", Toast.LENGTH_SHORT).show();
break;
case STATE_PLAYING:
mediaPlayer.pause();
stateMediaPlayer = STATE_PAUSING;
break;
case STATE_PAUSING:
mediaPlayer.start();
stateMediaPlayer = STATE_PLAYING;
break;
}
}
});
}
});
}
private void initMediaPlayer(String fileName){
File filepath = Environment.getExternalStorageDirectory();
String path = filepath.getPath(); // /storage/emulated/0
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(path+"/"+folderName+"/"+fileName);
mediaPlayer.prepare();
stateMediaPlayer = STATE_NOTSTARTER;
} catch (IOException e) {
e.printStackTrace();
}
}
@RequiresApi(api = Build.VERSION_CODES.N)
private void showRecordList(){
dataArrayList = new ArrayList<SampleData>();
myAdapter = new MyAdapter(MainActivity.this, dataArrayList);
List<String> fileList = getRecordList();
if(fileList.size() != 0){
for (int i=0; i<5; i++){
String file = fileList.get(i);
dataArrayList.add(new SampleData(file));
}
} else{
dataArrayList.add(0, new SampleData("녹음파일이 없습니다."));
}
myAdapter.notifyDataSetChanged();
}
@RequiresApi(api = Build.VERSION_CODES.N)
private List<String> getRecordList(){
File filepath = Environment.getExternalStorageDirectory();
String path = filepath.getPath(); // /storage/emulated/0
File directory = new File(path+"/"+folderName);
File[] files = directory.listFiles();
Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed());
List<String> filesNameList = new ArrayList<>();
for (int i=0; i<files.length; i++){
Log.d(TAG, files[i].getName());
filesNameList.add(files[i].getName());
}
return filesNameList;
}
private void requestPermission(){
if (Build.VERSION.SDK_INT >= 23 && ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(
this,
new String[] {Manifest.permission.READ_EXTERNAL_STORAGE}, 0
);
}
}
}
마무리
통화 녹음 목록을 가져와서 해당 녹음 파일을 재생하는 기능을 구현해봤다.
통화 녹음이 아닌 다른 음성 파일을 가져와서 재생하려면 경로를 수정해야한다.
GitHub - jaemin-Yoo/PlayRecordedFile: This is a project that imports and plays the files in the call recording list.
This is a project that imports and plays the files in the call recording list. - GitHub - jaemin-Yoo/PlayRecordedFile: This is a project that imports and plays the files in the call recording list.
github.com
'개발 > Java & Android' 카테고리의 다른 글
[Java & Android] 안드로이드 소켓 통신 오디오 파일 전송 (0) | 2021.11.02 |
---|---|
[Java & Android] Android 지속적인 음성인식 기능 구현 (SpeechRecognizer) (0) | 2021.10.28 |
[Java & Android] Android SpeechRecognizer API 구현하기 (음성을 텍스트로 변환 - STT변환) (0) | 2021.10.27 |
[Java & Android] 포그라운드 서비스 (Foreground Service) (0) | 2021.10.26 |