Android 원본 리소스 파일 사용 상세 정보

배경지식 소개는 다른 플랫폼의 응용 프로그램과 마찬가지로 안드로이드의 응용 프로그램도 각종 자원을 사용한다. 예를 들어 그림, 문자열 등은 원본의 해당 폴더 밑에 넣는다. 예를 들어/res/drawable,/res/xml,/res/values/,/res/layout,/assets 등이다.Android도 개발자가 UI와 관련된 레이아웃과 요소를 XML 자원으로 실현하도록 지원하고 장려한다.요약하면 Android에서 지원하는 리소스는 다음과 같습니다. • 색상 값/res/values는 resources를 Root로 하는 XML 파일입니다.정의 형식은 value • 문자열/res/values 리소스를 루트로 하는 XML 파일 value • 그림/res/drawable 직접 넣기,9 Patch를 지원하여 자유롭게 늘릴 수 있습니다. • 그림의 색/res/values는 리소스를 루트로 하는 XML 파일입니다.정의 형식은 value • 단위 자원/res/values 리소스를 루트로 하는 XML 파일 value • 메뉴/res/menu를 루트로 하는 XML 파일 • 레이아웃/res/layout 이것이 바로GUI의 레이아웃과 요소•스타일과 테마/res/values는resources를 루트로 하는 XML 파일value•애니메이션/res/anim은 두 가지가 있다. 하나는 프레임 애니메이션(frame animation), 즉 연속적으로 그림을 애니메이션-list를 루트로 하는 XML 파일로 바꾸는 것이다.또 하나는 모션 트윈(tweened animation)이다. API에 있는 Animation과 AnimationSet에 대응하는translate,scale,rotate,alpha 네 가지가 있는데 set을 루트로 정의하면 이 set은 AnimationSet에 해당하고 다음 디렉터리에 해당한다. •/res/anim은 애니메이션 •/res/drawable를 저장하거나 그림과 같은 자원인 shape를 저장한다.또는 selector •/res/menu 저장 Menu •/res/values 저장 수식성 자원: 문자열, 색깔, 단위,스타일과 테마 •/res/layout 저장 UI 레이아웃과 요소 •/res/raw 저장 실행 시 사용하고 싶은 원본 파일 •/assets 저장 실행 시 사용하고 싶은 원본 파일은 원본 파일 디렉터리/res/raw 및/assets를 제외한 다른 자원은 컴파일할 때 제3자 소프트웨어 aapt에 의해 처리됩니다.하나는 그림과 XML 파일을 처리하는 것이다. 예를 들어 XML을 2진법으로 컴파일하는 것이다.또한 처리의 목적은 R.java 파일을 생성하는 것입니다. 이 파일은 자원에 접근할 때 반드시 사용해야 합니다./res 디렉터리 아래의 모든 파일은 R.java 파일에 비추어 정수 Id 형식으로 표시되고 같은 유형의 자원은 내부 클래스로 봉인됩니다. R.java 파일은 다음과 같습니다

/* AUTO-GENERATED FILE.  DO NOT MODIFY.
 *
 * This class was automatically generated by the
 * aapt tool from the resource data it found.  It
 * should not be modified by hand.
 */
package com.android.explorer;
public final class R {
    public static final class attr {
    }
    public static final class drawable {
        public static final int icon=0x7f020000;
    }
    public static final class id {
        public static final int action=0x7f060004;
        public static final int description_panel=0x7f060001;
        public static final int fileinfo=0x7f060003;
        public static final int filename=0x7f060002;
        public static final int linearlayout_test_1=0x7f060005;
        public static final int linearlayout_test_2=0x7f060006;
        public static final int linearlayout_test_3=0x7f060007;
        public static final int thumbnail=0x7f060000;
    }
    public static final class layout {
        public static final int fileant_list_item=0x7f030000;
        public static final int linearlayout_test=0x7f030001;
    }
    public static final class raw {
        public static final int androidmanifest=0x7f040000;
    }
    public static final class string {
        public static final int app_name=0x7f050001;
        public static final int hello=0x7f050000;
    }
}
이 R.java에서/res에서 자원을 정의하거나 제공할 때의 주의사항을 볼 수 있습니다. 1.같은 형식이나 같은 폴더 아래의 자원은 같은 파일 이름을 사용할 수 없습니다. 즉, 파일 확장자로 다른 파일을 구별할 수 없습니다. R.java에는 자원의 파일 이름만 보존하고 확장자를 상관하지 않기 때문에 두 개의 그림이 있으면 하나는 icon입니다.png 또 하나는 아이콘입니다.jpg, 그럼 R.java에 R.drawable만 있을 거예요.icon.다른 하나는 접근할 수 없습니다.2. 리소스 파일의 이름은 Java 변수의 명명 규칙에 부합되어야 하며 대문자가 있을 수 없습니다.'[a-z][0-9]._'일 뿐입니다.그렇지 않으면 컴파일 오류가 발생할 수 있습니다. R.java의 변수 Id는 자원의 파일과 일일이 대응해야 하기 때문입니다. 즉, 자원 파일 이름을 Id의 변수 이름으로 사용해야 하기 때문에 반드시 자바 변수의 명칭 규칙에 부합해야 합니다. 또한 대문자가 있을 수 없습니다.3. SDK가 지원하는 폴더를 제외하고는 하위 폴더가 있을 수 없습니다. 컴파일 오류는 없지만 하위 폴더는 완전히 무시됩니다.만약에/res/layout 아래에 하위 Folder activity(/res/layout/acitivity/를 만들면 생성된 R.java에서 activity와 그 안의 내용을 볼 수 없습니다. 4. 자원 파일의 크기에 제한이 있습니다. 단일 파일이 1M보다 크지 않도록 하는 것이 좋습니다. 이것은 SDK 문서 설명의 제한이지만 구체적으로 저는 시험을 하지 않았습니다(2.2 버전 이후 10M까지 지원된다고 하는데 사실인지 가짜인지 모르겠습니다).모든/res 아래의 자원은 Resources()를 통해 액세스할 수 있으며 Id를 제공합니다.원본 자원을 사용하면 대부분의 자원을 컴파일할 때 파일 내용을 특수하게 처리하여 Apk가 실행할 때 접근할 수 있도록 합니다.실행할 때 처리되지 않은 원시 자원을 사용하려면 자원 파일을/res/raw와/assets 디렉터리 아래에 놓을 수 있습니다. 이 두 디렉터리의 주요 차이점은 다음과 같습니다. 1./res/raw의 파일은 R.java에 비칩니다./res/raw의 파일은 aapt에서 2진법으로 처리되지 않지만, 그 파일은 R.java에 비칩니다. 자원 Id 형식으로 접근하기 쉽습니다. 2.하위 디렉터리 구조는 위에서 말한 바와 같이/res/raw에는 하위 디렉터리가 있을 수 있지만 프로그램이 실행될 때 접근할 수 없습니다./res 아래의 모든 비법 하위 디렉터리는 R.java에서 볼 수 없기 때문입니다.그리고 이 하위 디렉터리와 파일들은 Apk에 컴파일되지 않습니다. Apk 파일을 압축한 후에도/res/raw 아래에서 찾을 수 없습니다.한편,/assets는 하위 디렉터리를 허용하고 접근할 수 있으며 Apk로 포장됩니다. Apk를 풀면 이 파일들은 원본 패키지와 같습니다.3. 접근 방식/res/raw 아래 파일 (하위 폴더는 접근할 수 없습니다) 의 접근 방식은 Resources를 통과하고 자원을 제공해야 하는 Id입니다

InputStream in = Context.getResources().openRawResource(R.id.filename);
그래서 왜 하위 폴더에 접근할 수 없습니까? Id가 없기 때문입니다./assets는 AssetManager를 통해 액세스해야 합니다.다음은/assets 아래의 자원 파일에 접근하는 방법을 중점적으로 설명합니다.AssetManager를 통해/assets 아래의 원본 자원 파일에 접근합니다. 1.파일을 읽는 방법은 AssetManager를 사용합니다.open(String filename)을 사용하여 파일을 열 수 있습니다. 이것은 다시 불러오는 방법입니다. 그리고 다른 매개 변수는 열기 모드를 설정할 수 있습니다. 문서에 있는 filename은/assets에 대한 경로입니다. 예를 들어:

InputStream in = mAssetManager.open("hello.txt"); // '/assets/hello.txt'
InputStream in2 = mAssetManager.open("config/ui.txt"); // '/assets/config/ui.txt'
2. 폴더 처리 -/assets를 훑어보면/assets 아래의 파일에 접근하려면 파일 이름과/assets에 대한 경로를 알아야 합니다.그래서 그 밑에 뭐가 있는지 미리 알지 못하면 어떻게 해야 하나요?그러면 그 아래의 모든 파일을 열거한 다음에 우리가 필요로 하는 것을 선택해야 합니다. 그래서 새로운 질문이 왔습니다. 어떻게/assets 아래의 모든 파일을 열거합니까?AssetManager는/assets의 다음 경로 아래를 나열하는 방법을 제공합니다

public finalString[]list(String path)
Since: API Level 1
Return a String array of all the assets at the given path.
Parameters
path  A relative path within the assets, i.e., "docs/home.html".
Returns
•String[] Array of strings, one for each asset. These file names are relative to 'path'. You can open the file by concatenating 'path' and a name in the returned string (via File) and passing that to open().
사실 이 문서에 문제가 있습니다.list()는 폴더 아래의 파일을 열거하기 때문에 문서의'docs/home.html'가 아닌 폴더 경로로 전송해야 합니다.또 하나의 가장 큰 문제는 루트 디렉터리/assets 아래의 내용을 어떻게 열거하는가이다. 루트 디렉터리 아래의 것을 알아야 상대적인 하위 디렉터리로 물건을 찾을 수 있기 때문에 이것은 반드시 가장 먼저 해결해야 할 문제이다.사실 문서는 이 방법이 도대체 어떻게 사용되는지, 즉 이 String 매개 변수가 도대체 어떻게 전달되는지 잘 알지 못한다.루트 디렉터리가/assets라고 생각하여 다음과 같이 시도했습니다

mAssetManager.list(".");  // returns array size is 0
mAssetManager.list("/");  // returns [AndroidManifest.xml, META-INF, assets, classes.dex, res, resources.arsc] // don't worry, u can see these files though, no way to access them
mAssetManager.list("/assets");  // returns array size is 0
//Google , :
mAssetManager.list("");  // returns stuff in /assets
그리고 열거된 하위 항목에 따라 모든 파일을 찾을 때까지 하위 파일을 반복합니다.흔히 볼 수 있는 문제 1.리소스 파일은 InputStream 방식으로만 가져올 수 있습니다. 파일을 조작하려면 어떻게 해야 하고, 파일 Uri를 사용하려면 어떻게 해야 합니까?API만으로는 안 됩니다. InputStream만 줍니다. 즉, 읽기 전용입니다.실행 가능한 방법은 파일을 읽고 임시 파일에 쓴 다음 임시 파일에 원하는 파일을 조작하는 것이다.내부 저장소나 외부 저장소에 Context가 제공하는 인터페이스로 파일을 만들 수 있습니다. 자세한 내용은 참고하십시오<Android 개발 노트: 데이터 저장 방식 상세 설명> .Java 소인은 Java 자체의 능력을 사용하려고 할 수 있습니다:

File File.createTempFile(String prefix, String suffix); 
File File.createTempFile(String prefix, String suffix, File path); 
이것도 가능하지만 안드로이드 시스템의 특성을 고려해야 한다. 즉, 쓴 경로에 권한이 있는지 여부다.예를 들어 첫 번째 방법에 대해'java.io.tmpdir'를 사용했는데 이것은 안드로이드에서'/sdcard'이기 때문에 SD카드가 없을 때 이 방법은 반드시 이상을 던진다.2. 모든 자원 파일은 읽기만 하고 실행할 때 변경할 수 없습니다. 프로그램이 실행될 때 Apk 동적 해석을 메모리에 불러오기 때문입니다. 즉, Apk는 변하지 않습니다. 변경할 수 없습니다.3. 모든 자원 폴더/res와/assets도 읽기 전용입니다. 위에서 말한 바와 같이 Apk는 컴파일한 후에 다시 바꿀 수 없습니다.실례 아래는 하나의 실례입니다./assets 아래의 모든 폴더와 파일을 귀속적으로 훑어볼 수 있습니다

package com.android.explorer;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.MimeTypeMap;
import android.widget.BaseAdapter;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
/*
 * Explore all stuff in /assets and perform actions specified by users.
 */
public class FileAntActivity extends ListActivity {
    private static final String TAG = "FileAntActivity";
    private AssetManager mAssetManager;
    private static final String EXTRA_CURRENT_DIRECTORY = "current_directory";
    private static final String EXTRA_PARENT = "parent_directory";
    public static final String FILEANT_VIEW = "com.android.fileant.VIEW";
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent intent = getIntent();
        String current = null;
        String parent = null;
        if (intent != null && intent.hasExtra(EXTRA_CURRENT_DIRECTORY)) {
            current = intent.getStringExtra(EXTRA_CURRENT_DIRECTORY);
        }
        if (current == null) {
            current = "";
        }
        if (intent != null && intent.hasExtra(EXTRA_PARENT)) {
            parent = intent.getStringExtra(EXTRA_PARENT);
        }
        if (parent == null) {
            parent = "";
        }
        mAssetManager = getAssets();
        if (TextUtils.isEmpty(parent)) {
            setTitle("/assets");
        } else {
            setTitle(parent);
        }
        try {
            // List all the stuff in /assets
            if (!TextUtils.isEmpty(parent)) {
                current = parent + File.separator + current;
            }
            Log.e(TAG, "current: '" + current + "'");
            String[] stuff = mAssetManager.list(current);
            setListAdapter(new FileAntAdapter(this, stuff, current));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private class FileAntAdapter extends BaseAdapter {
        private Context mContext;
        private String[] mEntries;
        private String mParentDirectory;

        public FileAntAdapter(Context context, String[] data, String parent) {
            mContext = context;
            this.mEntries = data;
            mParentDirectory = parent;
        }

        public int getCount() {
            return mEntries.length;
        }
        public Object getItem(int position) {
            return mEntries[position];
        }
        public long getItemId(int position) {
            return (long) position;
        }
        public View getView(final int position, View item, ViewGroup parent) {
            LayoutInflater factory = LayoutInflater.from(mContext);
            if (item == null) {
                item = factory.inflate(R.layout.fileant_list_item, null);
                TextView filename = (TextView) item.findViewById(R.id.filename);
                TextView fileinfo = (TextView) item.findViewById(R.id.fileinfo);
                ImageButton action = (ImageButton) item.findViewById(R.id.action);
                final String entry = mEntries[position];
                filename.setText(entry);
                boolean isDir = isDirectory(entry);
                if (isDir) {
                    fileinfo.setText("Click to view folder");
                    action.setVisibility(View.GONE);
                    item.setClickable(true);
                    item.setOnClickListener(new View.OnClickListener() {
                        public void onClick(View view) {
                            Intent intent = new Intent(FILEANT_VIEW);
                            intent.putExtra(EXTRA_CURRENT_DIRECTORY, entry);
                            intent.putExtra(EXTRA_PARENT, mParentDirectory);
                            startActivity(intent);
                        }
                    });
                } else {
                    final String type =
                        MimeTypeMap.getSingleton().getMimeTypeFromExtension(getExtension(entry));
                    fileinfo.setText(type);
                    item.setClickable(false);
                    action.setOnClickListener(new View.OnClickListener() {
                        public void onClick(View view) {
                             String filepath = entry;
                             if (!TextUtils.isEmpty(mParentDirectory)) {
                                 filepath = mParentDirectory + File.separator + filepath;
                             }
                             BufferedInputStream in = new BufferedInputStream(mManager.open(filepath));
                             // Do whatever you like with this input stream
                        }
                    });
                }
            }
            return item;
        }
     }

    /**
     * Test Whether an entry is a file or directory based on the rule:
     * File: has extension *.*, or starts with ".", which is a hidden files in Unix/Linux,
     * otherwise, it is a directory
     * @param filename
     * @return
     */
    private boolean isDirectory(String filename) {
        return !(filename.startsWith(".") || (filename.lastIndexOf(".") != -1));
    }

    private String getExtension(String filename) {
        int index = filename.lastIndexOf(".");
        if (index == -1) {
            return "";
        }
        return filename.substring(index + 1, filename.length()).toLowerCase();
    }
}

좋은 웹페이지 즐겨찾기