-
파일탐색기 샘플안드로이드(스튜디오)/막 써 2018. 11. 28. 20:19반응형
본 샘플은 상위 폴더(fileexplorer_ic_dir_open), 하위 폴더(fileexplorer_ic_dir_close), 파일(fileexplorer_ic_file) 총 3가지의 이미지 파일이 필요합니다.
이미지 파일은 따로 준비해서 설정하여 사용하시면 됩니다.
FileExplorer_Sample_Activity.java
package com.abyser.activity;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
import com.abyser.R;
/**
* 파일탐색기 샘플 액티비티.
*/
public class FileExplorer_Sample_Activity extends Activity implements AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener {
/**
* 로그 태그
*/
private static final String LOG_TAG = FileExplorer_Sample_Activity.class.getSimpleName();
//////////////
// 레이아웃 //
//////////////
private TextView tv_current_path;
private ListView lv_file_explorer;
private FileExplorer_Sample_Adapter mAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fileexplorer);
initValue();
initLayout();
}
@Override
protected void onResume() {
super.onResume();
mAdapter.refresh();
}
/**
* 초기 값 설정.
*/
private void initValue() {
}
/**
* 초기 레이아웃 설정.
*/
private void initLayout() {
tv_current_path = (TextView)findViewById(R.id.fileexplorer_tv_current_path);
lv_file_explorer = (ListView)findViewById(R.id.fileexplorer_lv_file_explorer);
mAdapter = new FileExplorer_Sample_Adapter(this, "/storage/emulated/0/Android/data");
tv_current_path.setText(mAdapter.getCurrentPath());
lv_file_explorer.setAdapter(mAdapter);
lv_file_explorer.setOnItemClickListener(this);
lv_file_explorer.setOnItemLongClickListener(this);
}
/////////////////////////////////////
// AdapterView.OnItemClickListener //
/////////////////////////////////////
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mAdapter.click(position);
tv_current_path.setText(mAdapter.getCurrentPath());
}
/////////////////////////////////////////
// AdapterView.OnItemLongClickListener //
/////////////////////////////////////////
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
mAdapter.longClick(position);
return true;
}
}FileExplorer_Sample_Adapter.java
package com.abyser.activity;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Environment;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import com.abyser.R;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
/**
* 파일탐색기 리스트를 보여 줄 어뎁터.
* {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} 또는
* {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} 권한 필요.
* @author abyser
*/
public class FileExplorer_Sample_Adapter extends BaseAdapter {
/**
* 로그 태그
*/
private static final String LOG_TAG = FileExplorer_Sample_Adapter.class.getSimpleName();
/**
* {@link Context}
*/
private Context mContext;
/**
* 리스트 아이템
*/
private ArrayList<File> mList;
/**
* 최상위 경로
*/
private String mRootFolderPath;
/**
* 내부 저장소 경로
*/
private String mInternalStoragePath;
/**
* 현재 경로
*/
private String mCurrentPath;
/**
* 생성자.
* @param context {@link Context}
*/
public FileExplorer_Sample_Adapter(Context context) {
this(context, null);
}
/**
* 생성자.
* @param context {@link Context}
* @param rootFolderPath 최상위 경로
*/
public FileExplorer_Sample_Adapter(Context context, String rootFolderPath) {
this.mContext = context;
this.mList = new ArrayList<File>();
this.mRootFolderPath = rootFolderPath;
this.mInternalStoragePath = null;
this.mCurrentPath = null;
init();
}
/**
* 초기 파일 리스트 설정.
*/
private void init(){
try {
mInternalStoragePath = getStoragePath(false);
} catch (Exception e) {
e.printStackTrace();
mInternalStoragePath = null;
}
File rootFolder = null;
if(mRootFolderPath == null || mRootFolderPath.length() <= 0){
if(mInternalStoragePath == null || mInternalStoragePath.length() <= 0){
rootFolder = null;
mRootFolderPath = null;
}else{
File storageFolder = new File(mInternalStoragePath);
rootFolder = storageFolder.getParentFile().getParentFile();
mRootFolderPath = rootFolder.getPath();
}
}else{
rootFolder = new File(mRootFolderPath);
if(!rootFolder.exists()){
rootFolder = null;
mRootFolderPath = null;
}
}
if(rootFolder == null){
mList = new ArrayList<File>();
mCurrentPath = "Unknown";
}else{
mList = new ArrayList<File>(Arrays.asList(rootFolder.listFiles()));
mCurrentPath = rootFolder.getPath();
}
}
/**
* 저장소 경로 반환.
* @param isGetExternalPath 외부 저장소 반환 여부
* @return 저장소 경로
*/
private String getStoragePath(boolean isGetExternalPath) throws IOException {
String storagePath = "";
String internalPath = "";
String externalPath = "";
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
// /storage/저장소명/Android/data/패키지명 형식의 File 리스트 가져오기
File[] packageDirs = this.mContext.getExternalFilesDirs("");
// 우리나라는 드물지만 2개 이상의 저장소를 가진 디바이스가 있어
// 해당 디바이스는 따로 처리가 필요 할것으로 판단되어 오류 처리 함.
if (packageDirs.length > 2) {
throw new IOException("Can not find path. Cause device has more than 2 storage.");
}
for (int i = 0; i < packageDirs.length; i++) {
File packageDir = packageDirs[i];
if (packageDir != null) {
String tmpPackagePath = packageDir.getPath();
String tmpStoragePath = tmpPackagePath.substring(0, tmpPackagePath.indexOf("/Android"));
if (tmpStoragePath.toLowerCase().contains("emulated")) {
internalPath = tmpStoragePath;
} else {
externalPath = tmpStoragePath;
}
}
}
if(isGetExternalPath){
if(externalPath != null && externalPath.length() > 0){
storagePath = externalPath;
}else{
throw new IOException("Can not find path. Cause find storage path is null.");
}
}else{
if(internalPath != null && internalPath.length() > 0){
storagePath = internalPath;
}else{
throw new IOException("Can not find path. Cause find storage path is null.");
}
}
}else{
try {
internalPath = Environment.getExternalStorageDirectory().getPath();
File root = new File("/mnt");
File[] rootDir = root.listFiles();
for (File dir : rootDir) {
if (dir.canWrite()) {
String tmpPath = dir.getPath();
if (tmpPath.contains("legacy")){
continue;
}
if (!internalPath.equals(tmpPath)) {
externalPath = tmpPath;
break;
}
}
}
} catch (Exception e) {
throw new IOException("Can not find path. Cause " + e.getMessage());
}
if(isGetExternalPath){
if(externalPath != null && externalPath.length() > 0){
storagePath = externalPath;
}else{
throw new IOException("Can not find path. Cause find storage path is null.");
}
}else{
if(internalPath != null && internalPath.length() > 0){
storagePath = internalPath;
}else{
throw new IOException("Can not find path. Cause find storage path is null.");
}
}
}
return storagePath;
}
/**
* 토스트 보여주기.
* @param msg 보여줄 메세지
* @param isShowShort 짧게 보여줄지 여부
*/
public void showToast(String msg, boolean isShowShort){
Toast.makeText(this.mContext, msg, (isShowShort ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG)).show();
}
/**
* 파일 확장자 반환.
* @param file 파일 확장자를 포함한 파일
* @return null : 파일이 null일 경우, 파일 확장자 : 정상 반환
*/
public String getFileExtension(String file) {
if(file == null){
return null;
}
return file.substring(file.lastIndexOf(".") + 1);
}
/**
* 파일 확장자를 제외한 파일명 반환.
* @param file 파일 확장자를 포함한 파일
* @return null : 파일이 null일 경우, 파일명 : 정상 반환
*/
public static String getFileName(String file) {
if(file == null){
return null;
}
String fileName = file.substring(0, file.lastIndexOf("."));
return fileName.substring(fileName.lastIndexOf("/") + 1);
}
@Override
public int getCount() {
return mList.size();
}
@Override
public File getItem(int position) {
return mList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final int tmp_position = position;
if (convertView == null) {
convertView = ((Activity)mContext).getLayoutInflater().inflate(R.layout.item_fileexplorer, null);
}
ImageView iv_ic = (ImageView)convertView.findViewById(R.id.fileexplorer_list_item_iv_icon);
TextView tv_name = (TextView)convertView.findViewById(R.id.fileexplorer_list_item_tv_name);
File f = mList.get(tmp_position);
if("...".equals(f.getName())){
iv_ic.setImageResource(R.drawable.fileexplorer_ic_dir_open);
tv_name.setText("...");
return convertView;
}else{
if(f.isDirectory()){
iv_ic.setImageResource(R.drawable.fileexplorer_ic_dir_close);
}else{
iv_ic.setImageResource(R.drawable.fileexplorer_ic_file);
}
}
tv_name.setText(f.getName());
return convertView;
}
/**
* 현재 파일 리스트가 보여지고 있는 경로 반환.
* @return 현재 파일 리스트가 보여지고 있는 경로
*/
public String getCurrentPath(){
return this.mCurrentPath;
}
/**
* 현재 경로를 기준으로 파일 리스트 갱신.
*/
public void refresh(){
File currentPath = new File(mCurrentPath);
if(mRootFolderPath.equals(mCurrentPath)){
mList = new ArrayList<File>(Arrays.asList(currentPath.listFiles()));
}else{
File[] tmpFileList = currentPath.listFiles();
File[] fileList = new File[tmpFileList.length + 1];
fileList[0] = new File(mCurrentPath + "/...");
int size = 1;
for (File data : tmpFileList) {
fileList[size++] = data;
}
mList = new ArrayList<File>(Arrays.asList(fileList));
}
notifyDataSetChanged();
}
/**
* 파일 클릭 이벤트.
* @param position 클릭한 파일 포지션
*/
public void click(int position){
if(isClickFolder(mList.get(position))){
clickFolder(position);
}else{
clickFile(position);
}
}
/**
* 파일 롱클릭 이벤트.
* @param position 롱클릭한 파일 포지션
*/
public void longClick(int position){
final File longClickFile = mList.get(position);
if("...".equals(longClickFile.getName())){
return;
}
boolean isLongClickFolder = false;
if(isLongClickFolder(longClickFile)){
isLongClickFolder = true;
}else{
isLongClickFolder = false;
}
final boolean finalIsLongClickFolder = isLongClickFolder;
AlertDialog.Builder builder = new AlertDialog.Builder(this.mContext);
builder.setCancelable(false);
builder.setTitle((finalIsLongClickFolder ? "폴더" : "파일") + " 삭제");
builder.setMessage("선택한 " + (finalIsLongClickFolder ? "폴더를" : "파일을 ") + "삭제하시겠습니까?");
builder.setPositiveButton("삭제", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if(finalIsLongClickFolder){
deleteFolder(longClickFile);
}else{
deleteFile(longClickFile);
}
}
});
builder.setNegativeButton("취소", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.create();
builder.show();
}
/**
* 클릭한 파일이 폴더인지 여부 반환.
* @param clickFile 클릭한 파일
* @return true : 클릭한 파일이 폴더임, false : 클릭한 파일이 파일임
*/
private boolean isClickFolder(File clickFile){
if("...".equals(clickFile.getName()) || clickFile.isDirectory()){
return true;
}
return false;
}
/**
* 폴더 클릭 이벤트.
* @param position 클릭한 폴더 포지션
*/
private void clickFolder(int position){
File f = null;
File[] fileList = null;
if(isClickInFolder(mList.get(position))){
f = mList.get(position);
if(mInternalStoragePath.equals((f.getPath() + "/0"))){
f = new File(mInternalStoragePath);
}
File[] tmpFileList = f.listFiles();
if(tmpFileList == null){
showToast("파일 접근 권한이 없습니다.", true);
return;
}
fileList = new File[tmpFileList.length + 1];
fileList[0] = new File(f.getPath() + "/...");
int size = 1;
for (File data : tmpFileList) {
fileList[size++] = data;
}
}else{
f = new File(mCurrentPath);
if(mInternalStoragePath.equals(f.getPath())){
f = f.getParentFile().getParentFile();
}else{
f = f.getParentFile();
}
File[] tmpFileList = f.listFiles();
if(mRootFolderPath.equals(f.getPath())){
fileList = tmpFileList;
}else{
fileList = new File[tmpFileList.length + 1];
fileList[0] = new File(f.getPath() + "/...");
int size = 1;
for (File data : tmpFileList) {
fileList[size++] = data;
}
}
}
mCurrentPath = fileList[0].getParent();
refreshFileList(fileList);
}
/**
* 클릭한 폴더 파일이 하위 폴더인지 여부 반환.
* @param clickFile 클릭한 폴더 파일
* @return true : 클릭한 폴더 파일이 하위 폴더임, false : 클릭한 폴더 파일이 상위 가기 폴더임
*/
private boolean isClickInFolder(File clickFile){
return (!"...".equals(clickFile.getName()));
}
/**
* 파일 리스트 갱신.
* @param fileList
*/
private void refreshFileList(File[] fileList){
mList = new ArrayList<File>(Arrays.asList(fileList));
notifyDataSetChanged();
}
/**
* 파일 클릭 이벤트.
* @param position 클릭한 파일 포지션
*/
private void clickFile(int position) {
File f = mList.get(position);
if (isClickTxtFile(f)) {
showTxtFile(f);
} else if(isClickPngFile(f)){
showPngFile(f);
} else {
showToast("보기를 지원하지 않는 파일 형식입니다.", true);
}
}
/**
* txt 확장자의 파일 클릭 여부 반환.
* @param clickFile 클릭한 파일
* @return true : 클릭한 파일이 txt 확장자의 파일임, false : 클릭한 파일이 txt 확장자의 파일이 아님
*/
private boolean isClickTxtFile(File clickFile){
return ("txt".equals(getFileExtension(clickFile.getName())));
}
/**
* png 확장자의 파일 클릭 여부 반환.
* @param clickFile 클릭한 파일
* @return true : 클릭한 파일이 png 확장자의 파일임, false : 클릭한 파일이 png 확장자의 파일이 아님
*/
private boolean isClickPngFile(File clickFile){
return ("png".equals(getFileExtension(clickFile.getName())));
}
/**
* txt 확장자의 파일 보여주기.
* @param txtFile 프로퍼티 파일
*/
private void showTxtFile(final File txtFile){
final ProgressDialog loadingDialog = new ProgressDialog(mContext);
loadingDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
loadingDialog.setMessage("파일을 읽는 중 입니다.");
AsyncTask<Void, Void, String> async = new AsyncTask<Void, Void, String>() {
@Override
protected void onPreExecute() {
super.onPreExecute();
loadingDialog.show();
}
@Override
protected String doInBackground(Void... voids) {
StringBuilder result = new StringBuilder();
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(txtFile));
String readLine = "";
while(((readLine = br.readLine()) != null)){
result.append(readLine + "\n");
}
}catch (Exception e){
e.printStackTrace();
}finally {
try{
br.close();
}catch (Exception e){
// ignore
}
}
return result.toString();
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
loadingDialog.dismiss();
View v = getShowView(false);
((TextView)v.findViewById(R.id.fileexplorer_show_tv_text)).setText(result);
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setCancelable(false);
builder.setTitle(txtFile.getName() + " 파일 보기");
builder.setView(v);
builder.setPositiveButton("닫기", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.create();
builder.show();
}
};
async.execute();
}
/**
* png 확장자의 파일 보여주기.
* @param pngFile png 확장자의 파일
*/
private void showPngFile(File pngFile){
View v = getShowView(true);
((ImageView)v.findViewById(R.id.fileexplorer_show_iv_image)).setImageBitmap(getPngToBitmap(pngFile));
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setCancelable(false);
builder.setTitle(pngFile.getName() + " 파일 보기");
builder.setView(v);
builder.setPositiveButton("닫기", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.create();
builder.show();
}
/**
* png 확장자의 파일을 {@link Bitmap}으로 만들어 반환.
* @param pngFile png 확장자의 파일
* @return {@link Bitmap}
*/
private Bitmap getPngToBitmap(File pngFile){
return BitmapFactory.decodeFile(pngFile.getPath());
}
/**
* 텍스트 파일, 또는 이미지 파일 클릭시 사용 될 커스텀 뷰 반환.
* @param isShowImage 이미지를 보여주는지 여부
* @return {@link View}
*/
private View getShowView(boolean isShowImage){
View v = ((Activity)mContext).getLayoutInflater().inflate(R.layout.item_fileexplorer_show, null);
if(isShowImage){
((ImageView)v.findViewById(R.id.fileexplorer_show_iv_image)).setVisibility(View.VISIBLE);
}else{
((ScrollView)v.findViewById(R.id.fileexplorer_show_sv_text)).setVisibility(View.VISIBLE);
}
return v;
}
/**
* 롱클릭한 파일이 폴더인지 여부 반환.
* @param longClickFile 롱클릭한 파일
* @return true : 롱클릭한 파일이 폴더임, false : 롱클릭한 파일이 파일임
*/
private boolean isLongClickFolder(File longClickFile){
return longClickFile.isDirectory();
}
/**
* 폴더 지우기.
* @param longClickFile 롱클릭한 파일
*/
private void deleteFolder(File longClickFile){
delete(longClickFile);
}
/**
* 파일 지우기.
* @param longClickFile 롱클릭한 파일
*/
private void deleteFile(File longClickFile){
delete(longClickFile);
}
/**
* 파일 지우기.
* @param longClickFile
*/
private void delete(final File longClickFile){
final ProgressDialog deleteProgressDialog = new ProgressDialog(mContext);
deleteProgressDialog.setCancelable(false);
deleteProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
deleteProgressDialog.setTitle((longClickFile.isDirectory() ? "폴더" : "파일") + " 삭제");
deleteProgressDialog.setMessage((longClickFile.isDirectory() ? "폴더를" : "파일을") + " 삭제 중 입니다.\n잠시만 기다려 주시기 바랍니다.");
AsyncTask<Void, Void, Void> asyncDelete = new AsyncTask<Void, Void, Void>(){
@Override
protected void onPreExecute() {
super.onPreExecute();
deleteProgressDialog.show();
}
@Override
protected Void doInBackground(Void... aVoid) {
longClickFile.delete();
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
refresh();
deleteProgressDialog.dismiss();
showToast("삭제를 완료하였습니다.", false);
}
};
asyncDelete.execute();
}
}activity_fileexplorer.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:background="#000000"
android:orientation="vertical">
<TextView
android:id="@+id/fileexplorer_tv_current_path"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:gravity="center_vertical"
android:maxLines="1"
android:text="현재 경로"
android:textColor="#ffffff" />
<!-- 파일 탐색기 리스트 -->
<ListView
android:id="@+id/fileexplorer_lv_file_explorer"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="8" />
</LinearLayout>Item_fileexplorer.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="wrap_content"
android:descendantFocusability="blocksDescendants"
android:orientation="horizontal"
android:paddingBottom="10dp"
android:paddingTop="10dp" >
<ImageView
android:id="@+id/fileexplorer_list_item_iv_icon"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/fileexplorer_ic_file"/>
<TextView
android:id="@+id/fileexplorer_list_item_tv_name"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="5dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:text="파일명"
android:textColor="#ffffff"
android:textSize="16dp" />
</LinearLayout>Item_fileexplorer_show.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="15dp">
<ImageView
android:id="@+id/fileexplorer_show_iv_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"
android:visibility="gone"/>
<ScrollView
android:id="@+id/fileexplorer_show_sv_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/fileexplorer_show_tv_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="text"
android:textSize="16dp" />
</LinearLayout>
</ScrollView>
</RelativeLayout>반응형'안드로이드(스튜디오) > 막 써' 카테고리의 다른 글
APK 파일 설치 요청 메서드 (0) 2019.09.17 텍스트 파일 읽기, 쓰기 메서드 (0) 2019.08.30 파일 복사 붙여넣기 메소드 (0) 2018.10.24 LocationManager 샘플(추가 정의 필요) (2) 2018.09.30 권한 요청 샘플(런타임 권한 요청 X) (0) 2018.08.14