안드로이드 애셋(Asset) 사용하기. (How to use the Android Asset)

2017. 4. 26. 20:46


1. 안드로이드 애셋(Asset)

안드로이드 앱에서 사용되는 "파일"은 여러 경로를 통해 제공될 수 있습니다. 앱의 설정 내용을 저장하기 위해 앱 내에서 직접 파일을 만들 수도 있고, 인터넷으로 연결된 웹서버로부터 HTTP 요청을 통해 파일을 가져올 수도 있습니다. 이 외에도 앱에서 사용되는 파일을 제공하는 방법은 여러가지가 있는데, 여기서는, 미리 만들어 둔 XML 파일을, 앱을 릴리즈할 때 APK(Android Package Kit) 파일에 포함시킨 다음, 앱에서 사용할 수 있게 만드는 방법에 대해 살펴보도록 하겠습니다.


파일을 APK(Android Package Kit)에 포함시켜 앱에서 사용할 수 있도록 만든 것을 안드로이드 애셋(Asset)이라고 합니다. 에셋(Asset)의 사전적 의미가 "자산"이라는 것을 떠올려보면, 앱이 릴리즈 되는 시점에, 앱 자신이 온전히 사용할 수 있는 파일들을 앱의 "자산", 즉, 애셋(Asset)이라고 할 수 있는 것이죠.


안드로이드 애셋(Asset)의 파일을 사용하는 과정은 크게 세 단계로 나뉩니다. 첫 번째는 프로젝트에 애셋(Asset) 폴더를 추가하는 것이고, 두 번째는 추가된 애셋(Asset) 폴더에 파일을 포함시키는 것입니다. 그런 다음 마지막으로, AssetManager 클래스를 사용하면, 앱 실행 시, 에셋 폴더에 포함된 파일을 읽을 수 있습니다.

안드로이드 애셋(Asset) 사용 과정


1.1 안드로이드 애셋(Asset) 폴더 만들기.

미리 만들어놓은 파일을 안드로이드 애셋(Asset)에 추가하려면, 안드로이드 애셋을 위한 폴더에 파일을 복사하기만 하면 됩니다. 그러면 추가적인 작업을 하지 않아도, 앱 빌드 시 애셋 폴더 전체가 자동으로 APK(Android Package Kit)에 포함됩니다.


기본적으로 안드로이드 애셋(Asset) 파일들이 저장되는 폴더의 경로는 "src/main/assets/"입니다. 그런데 안드로이드 스튜디오에서 생성된 프로젝트의 내용을 보면 있어야 할 "assets" 폴더가 보이지 않습니다. 안드로이드 스튜디오에서는 "assets" 폴더를 기본적으로 만들지 않기 때문인데요, 그래서 개발자가 "assets" 폴더를 직접 추가해야 합니다.


그렇다고 탐색기에서 직접 폴더를 생성해야 하는 것은 아니고, 안드로이드 스튜디오 메뉴를 통해 애셋 폴더를 추가할 수 있습니다. 애셋 폴더를 추가하려면 프로젝트 뷰 화면에서 마우스 오른쪽 버튼을 누른 다음, New - Folder - Assets Folder 메뉴를 선택하면 됩니다.

Assets Folder 추가 메뉴


애셋(Asset)이 저장될 폴더를 지정하는 화면이 나타나면, 기본 설정인 "main"을 선택한 상태로 "Finish" 버튼을 선택합니다.

Assets Folder 추가


그러면 앱 프로젝트에 "assets" 폴더가 추가된 것을 확인할 수 있습니다.

추가된 Assets 폴더



참고로, 에셋 폴더를 추가할 때 기본 경로인 "src/main/assets/"만 사용할 수 있는 것은 아닙니다. 즉, 애셋 폴더의 이름을 개발자가 직접 지정할 수 있죠. "애셋 폴더 추가 대화상자"에서 "Change Folder Location" 체크박스를 선택하면 됩니다. 그러면 아래와 같이 폴더 경로를 지정할 수 있는 화면으로 바뀝니다.

애셋 폴더 직접 입력


이렇게 애셋 폴더를 직접 지정할 수 있는 것은, 폴더 경로에 대한 정보가 하나의 고정된 값이 아니라 프로젝트 설정에서 관리되기 때문인데요, "build.gradle" 파일에 그 경로가 기록되어 있습니다.

build.gradle의 애셋 폴더 정보


1.2 안드로이드 애셋(Asset) 폴더에 파일 추가하기.

애셋(Asset) 폴더를 만들고나면, 다음 할 일은 애셋(Asset) 폴더에 파일을 추가하는 것입니다. 미리 만들어진 파일을 추가하는 방법은 프로젝트의 Drawable 리소스 폴더에 이미지 파일을 넣는 방법과 같습니다.
즉, 탐색기에서 복사할 파일을 선택하고 Ctrl + C를 누른 다음, 프로젝트의 "assets" 폴더 아이콘을 선택하고 Ctrl + V를 누르면 됩니다.


만약, 텍스트 파일을 직접 작성하여 추가하는 경우라면, "assets" 폴더에서 마우스 오른쪽 버튼을 누른 다음, New - File을 선택하여 파일을 추가하고 파일의 내용을 직접 작성할 수 있습니다.

Assets 폴더에 파일 추가하기


여기까지가 애셋(Asset) 폴더에 파일을 추가하는 과정이며, 추가된 파일은 앱을 빌드하면 자동으로 APK 파일에 포함됩니다.

1.3 안드로이드 애셋(Asset)으로부터 파일 읽기.

자, 그럼 이제 마지막 과정으로 프로젝트의 애셋(Asset) 폴더에 추가된 파일을 여는 방법을 설명하겠습니다.


일반적으로 안드로이드에서 파일을 다룰 때는 파일이 저장된 경로명을 사용하여 직접 파일에 접근합니다. [안드로이드 바이너리(binary) 파일 입출력 2]에서 설명했듯이, 파일의 절대 경로명("/data/user/0/[PACKAGE-NAME]/files/" + "FILENAME") 또는 Context의 getFilesDir() 함수와의 조합(getFilesDir() + "FILENAME")을 통해 파일 스트림을 열 수 있습니다.


하지만 애셋(Asset) 폴더에 들어 있는 파일은 경로를 통해 직접 접근할 수 없습니다. 대신, AssetManager 클래스를 통해서 폴더에 저장된 파일을 열 수 있습니다.


앱에서 AssetManager 클래스 객체 참조를 획득하는 방법은 Context의 getResources() 함수를 통해 Resources 클래스 객체의 참조를 획득한 다음, Resources의 getAssets() 함수를 호출하는 것입니다.

Context.getResource()와 Resources의 getAssets()


그리고 AssetManager 객체의 참조를 획득하고 나면, AssetManager의 open() 함수를 사용하여 파일 입력 스트림을 열 수 있습니다.


아래는 AssetManager 클래스 객체를 가져온 다음, 애셋 폴더에 저장된 "FILE"의 스트림을 여는 예제 코드입니다.

    AssetManager를 사용하여 애셋(Asset) 파일 열기.
    AssetManager am = getResources().getAssets() ;
    InputStream is = null ;

    try {
        is = am.open("FILE") ;

        // TODO : use is(InputStream).

    } catch (Exception e) {
        e.printStackTrace() ;
    }

    if (is != null) {
        try {
            is.close() ;
        } catch (Exception e) {
            e.printStackTrace() ;
        }
    }

2. 안드로이드 애셋(Asset) 사용하기

아주 간단한 앱 작성 예제를 통해 안드로이드 애셋(Asset)에 저장된 파일을 읽는 구체적인 방법을 알아보겠습니다.


예제를 통해 만들어지는 앱의 기능은 매우 간단합니다. 앱 시작 시, 애셋(Asset) 폴더에 저장된 텍스트 파일을 읽은 다음, 화면에 배치된 텍스트뷰에 표시하는 기능만 갖추고 있습니다.


2.1 안드로이드 애셋에 파일 추가

가장 먼저 할 일은 안드로이드 애셋에 텍스트 파일을 추가하는 것입니다. 앞서 설명한대로 애셋(Asset) 폴더를 추가하고, 텍스트 파일을 작성합니다.

[STEP-1] 안드로이드 애셋(Asset) 폴더 추가 및 텍스트 파일 작성.

안드로이드 애셋(Asset) 폴더 및 텍스트 파일 추가 과정


예제에서 사용되는 텍스트 파일(file.txt)의 내용은 아래와 같습니다.

This is a Example of the Android Asset.
the Asset folder can be accessed by AssetManager.
AssetManager allows you to open and read raw files.

2.2 MainActivity 레이아웃 작성

다음, MainActivity의 레이아웃 리소스 XML 파일을 작성합니다.

[STEP-2] "activity_main.xml" - MainActivity의 레이아웃 구성.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.ppottasoft.assetexample.MainActivity"
    tools:showIn="@layout/activity_main">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/text1"
        android:text=""
        android:textSize="20sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

2.3 앱 시작 시, 애셋(Asset) 파일 읽어서 화면에 표시하기.

이제 MainActivity의 onCreate() 함수에서 애셋(Asset) 폴더에 저장된 파일을 여는 코드를 작성합니다. 그리고 파일의 내용은 화면의 텍스트뷰에 표시합니다.

[STEP-3] "MainActivity.java" - onCreate() 함수에서 애셋(Asset) 폴더의 파일 읽기
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // 코드 계속 ...

        AssetManager am = getResources().getAssets() ;
        InputStream is = null ;
        byte buf[] = new byte[1024] ;
        String text = "" ;

        try {
            is = am.open("file.txt") ;

            if (is.read(buf) > 0) {
                text = new String(buf) ;
            }

            TextView textView = (TextView) findViewById(R.id.text1) ;
            textView.setText(text) ;

            is.close() ;
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (is != null) {
            try {
                is.close() ;
            } catch (Exception e) {
                e.printStackTrace() ;
            }
        }
    }
}

3. 예제 실행 화면

예제를 실행하면 아래 그림과 같이, 애셋(Asset) 폴더에 추가한 텍스트 파일의 내용이 화면에 표시된 것을 확인할 수 있습니다.

Asset 예제 실행 화면


4. 안드로이드 애셋(Asset) 사용 시 주의 사항.

4.1 애셋(Asset) 폴더는 읽기 전용.

안드로이드 애셋(Asset)에 추가된 파일은 읽기만 가능(Read Only)합니다. 그래서 애셋(Asset)에 포함된 파일을 기반으로 내용을 수정 또는 추가하려면, 해당 파일을 읽기/쓰기가 모두 가능한 폴더로 옮긴 다음 파일을 다루어야 합니다.

    AssetManager am = getResources().getAssets() ;
    InputStream is = null ;
    FileOutputStream fos = null ;
    byte buf[] = new byte[1024] ;

    try {
        is = am.open("txt/file.txt") ;
        fos = new FileOutputStream(getFilesDir() + "file.txt") ;

        while (is.read(buf) > 0) {
            fos.write(buf) ;
        }

        fos.close() ;
        is.close() ;

    } catch (Exception e) {
        e.printStackTrace();
    }

4.2 텍스트 파일 읽기.

앞에서 AssetManager 사용법을 통해 확인했듯이, 애셋(Asset)에 포함된 파일은 바이너리(binary) 스트림으로만 열 수 있습니다. open() 함수의 리턴 타입이 InputStream인 것을 보면 알 수 있죠. 그래서 예제에서는 읽어들인 바이너리(binary) 데이터를 텍스트(text) 데이터로 바꾸기 위해, 바이트(byte) 버퍼를 String 타입으로 직접 바꾸는 코드를 작성했습니다. 그런데 매번 String 타입으로의 변환없이, 스트림 자체를 BufferedReader로 처리하는 방법이 있습니다. 아래 코드처럼 말이죠.

        AssetManager am = getResources().getAssets() ;
        InputStream is = null ;
        byte buf[] = new byte[1024] ;
        String text = "" ;

        try {
            is = am.open("file.txt") ;
            
            BufferedReader bufrd = new BufferedReader(new InputStreamReader(is)) ;

            // TODO : use bufrd
        } ...

4.3 애셋(Asset) 폴더에 하위 디렉토리 추가하기.

안드로이드 애셋(Asset)에 파일을 넣을 때, 파일의 갯수가 적으면, 보통 모든 파일을 애셋(Asset)의 루트 디렉토리(src/main/assets/)에 넣어 사용합니다. 그리고 파일을 참조할 때, 추가된 파일의 이름만으로 open() 함수를 호출하죠.

Asset 루트에 저장된 파일 열기


그런데 애셋(Asset)에 포함시킬 파일의 갯수가 많아지고 파일의 종류가 다양해지면, 애셋(Asset) 루트 디렉토리에만 모든 파일을 저장하는 것이 파일 관리를 어렵게 만들 수 있습니다.


이 때, 애셋(Asset)의 루트 디렉토리에 하위 디렉토리를 추가하면 파일을 효율적으로 관리할 수 있습니다. 그리고 하위 디렉토리에 추가된 파일은 하위 디렉토리 이름을 포함한 경로를 사용하여 열 수 있습니다.

Asset 하위 디렉토리 파일 열기


하위 디렉토리를 추가하는 방법은, 디렉토리를 추가하고자 하는 곳에서 마우스 오른쪽 버튼을 누른 다음, 팝업 메뉴의 New - Directory를 선택하면 됩니다.

Asset 하위 디렉토리 추가 방법


5. 참고.

.END.


ANDROID 프로그래밍/FILE