상세 컨텐츠

본문 제목

파일 탐색기 클래스 - FileList

RyuLib/RyuLib for Android

by ryujt 2010. 12. 18. 20:03

본문



안드로이드에서는 기본으로 제공하는 Delphi의 TOpenDialog 라이브러리가 없습니다.  따라서, 스스로 만들어서 해결해야 하는데, 검색된 소스나 방법들이 제 마음에 들지 않아 아래와 같이 만들어 봤습니다.  (급조한 것이기 때문에 아직 부족한 점이 많습니다.)

일단 지정된 Path 안에 있는 폴더와 파일의 목록을 보여주는 FileList 클래스를 만들어 봤습니다.  그리고, 사용법은 [소스 1]과 같습니다.

[소스 1]  
package app.main;

import android.app.Activity;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.TextView;

public class Main extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        FileList _FileList = new FileList(this);
        _FileList.setOnPathChangedListener(_OnPathChanged);
        _FileList.setOnFileSelected(_OnFileSelected);
        
        LinearLayout layout = (LinearLayout) findViewById(R.id.LinearLayout01);
        layout.addView(_FileList);
        
        _FileList.setPath("/");
        _FileList.setFocusable(true);
        _FileList.setFocusableInTouchMode(true);       
        
    }
    
    private OnPathChangedListener _OnPathChanged = new OnPathChangedListener() {
		@Override
		public void onChanged(String path) {
			((TextView) findViewById(R.id.TextView01)).setText(path);
		}
	};
    
    private OnFileSelectedListener _OnFileSelected = new OnFileSelectedListener() {
		@Override
		public void onSelected(String path, String fileName) {
			// TODO
		}
	};
    
}

15: FileList 클래스는 ListView를 상속받아서 확장하였습니다.  layout.xml을 통해서 사용 할 수도 있지만, 쉽게 코드를 읽을 수 있도록 동적 생성하였습니다.

FileList는 두 종류의 이벤트를 지원하고 있습니다.  

OnPathChangedListener는 표시하고 있는 폴더가 변경되면 해당 폴더의 전체 Path를 알려줍니다.  28-33: 라인은 OnPathChangedListener 인터페이스의 멤버 메소드를 구현 한 것 입니다.

OnFileSelected는 파일을 선택 했을 경우, 선택된 파일과 파일이 속해있는 폴더의 전체 Path를 알려줍니다.  35-40: 라인은 OnFileSelected 인터페이스의 멤버 메소드를 구현 한 것 입니다.

22: FileList의 setPath(String path) 메소드는 지정된 경로(path) 안에 있는 폴더와 파일 목록을 표시 합니다.

32: TextView를 통해서 경로(path)명이 변경 될 때마다 표시하고 있습니다.

38: 라인에는 파일이 선택되었을 경우 실행하고자 하는 코드를 작성하시면 됩니다.

아래의 FileList 클래스의 소스는 [소스 2]와 같습니다.

[소스 2]
package app.main;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class FileList extends ListView {

	public FileList(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		
		init(context);
	}

	public FileList(Context context, AttributeSet attrs) {
		super(context, attrs);

		init(context);
	}

	public FileList(Context context) {
		super(context);

		init(context);
	}
	
	private void init(Context context) {
		_Context = context;
                setOnItemClickListener(_OnItemClick);
	}
	
	private Context _Context = null;
	private ArrayList<String> _List = new ArrayList<String>();
	private ArrayList<String> _FolderList = new ArrayList<String>();
	private ArrayList<String> _FileList = new ArrayList<String>();
	private ArrayAdapter<String> _Adapter = null; 
	
	// Property 
	private String _Path = "";
	
	// Event
	private OnPathChangedListener _OnPathChangedListener = null;
	private OnFileSelectedListener _OnFileSelectedListener = null;
	
	private boolean openPath(String path) {
		_FolderList.clear();
		_FileList.clear();
		
        File file = new File(path);
        File[] files = file.listFiles();
        if (files == null) return false;
        
        for (int i=0; i<files.length; i++) {
        	if (files[i].isDirectory()) {
        		_FolderList.add("<" + files[i].getName() + ">");
        	} else {
        		_FileList.add(files[i].getName());
        	}
        }
        
        Collections.sort(_FolderList);
        Collections.sort(_FileList);
        
        _FolderList.add(0, "<..>");
        
        return true;
	}
	
	private void updateAdapter() {
		_List.clear();
		_List.addAll(_FolderList);
		_List.addAll(_FileList);
        
		_Adapter = new ArrayAdapter<String>(_Context, android.R.layout.simple_list_item_1, _List);
		setAdapter(_Adapter);
	}

	public void setPath(String value) {
		if (value.length() == 0) {
			value = "/";
		} else {
			String lastChar = value.substring(value.length()-1, value.length());
			if (lastChar.matches("/") == false) value = value + "/"; 
		}
		
		if (openPath(value)) {
			_Path = value;
			updateAdapter();	        
			if (_OnPathChangedListener != null) _OnPathChangedListener.onChanged(value);
		}
	}

	public String getPath() {
		return _Path;
	}
	
	public void setOnPathChangedListener(OnPathChangedListener value) {
		_OnPathChangedListener = value;
	}

	public OnPathChangedListener getOnPathChangedListener() {
		return _OnPathChangedListener;
	}

	public void setOnFileSelected(OnFileSelectedListener value) {
		_OnFileSelectedListener = value;
	}

	public OnFileSelectedListener getOnFileSelected() {
		return _OnFileSelectedListener;
	}
	
	public String DelteRight(String value, String border) {
		String list[] = value.split(border);

		String result = "";
		
		for (int i=0; i<list.length; i++) {
			result = result + list[i] + border; 
		}
		
		return result;
	}
	
	private String delteLastFolder(String value) {
		String list[] = value.split("/");

		String result = "";
		
		for (int i=0; i<list.length-1; i++) {
			result = result + list[i] + "/"; 
		}
		
		return result;
	}
	
	private String getRealPathName(String newPath) {
		String path = newPath.substring(1, newPath.length()-1);
		
		if (path.matches("..")) {
			return delteLastFolder(_Path);
		} else {
			return _Path + path + "/";
		}
	}

	private AdapterView.OnItemClickListener _OnItemClick = new AdapterView.OnItemClickListener() {
		@Override
		public void onItemClick(AdapterView<?> arg0, View arg1, int position,
				long id) {
			String fileName = getItemAtPosition(position).toString();
			if (fileName.matches("<.*>")) {
				setPath(getRealPathName(fileName));
			} else {
				if (_OnFileSelectedListener != null) _OnFileSelectedListener.onSelected(_Path, fileName);
			}
		}
	};

}

제가 지금 작성하는 어플리케이션의 경우에는 파일을 선택하는 것은 중요한 요소는 아니기 때문에 위에 있는 정도면 충분하여 우선은 여기까지만 작성 해 봅니다.  추후, 다른 용도가 생기면 개선하여 다시 올리도록 하겠습니다.

마지막으로 위의 예제에서 사용된 layout/main.xml은 아래와 같습니다.

[소스 3]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:id="@+id/LinearLayout01"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    
<TextView 
    android:text="@+id/TextView01" 
    android:id="@+id/TextView01" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content"
    >
</TextView>

</LinearLayout>

첨부파일에 전체 소스가 있습니다.  위에서 설명하지 않은 인터페이스의 경우에는 첨부파일을 참고하시기 바랍니다.

관련글 더보기