Computer >> 컴퓨터 >  >> 프로그래밍 >> Android

안드로이드에서 런타임 권한으로 외부 저장소의 txt 파일을 읽는 방법

이 예제는 안드로이드에서 런타임 권한(Runtime Permission)을 활용해 외부 저장소(External Storage)에 있는 txt 파일을 읽어오는 방법을 보여줍니다. 미리 외부 저장소에 'text'라는 폴더를 만들고 그 안에 sample.txt 파일을 생성해 두었다고 가정합니다.

1단계 – 새 프로젝트 생성

Android Studio를 실행하고 File ⇒ New Project로 이동한 후, 필요한 모든 세부 정보를 입력하여 새 프로젝트를 생성합니다.

2단계 – 레이아웃 작성

res/layout/activity_main.xml에 아래 코드를 추가합니다.

<?xml version = "1.0" encoding = "utf-8"?>
<LinearLayout xmlns:android = "https://schemas.android.com/apk/res/android"
   xmlns:tools = "https://schemas.android.com/tools"
   android:layout_width = "match_parent"
   android:layout_height = "match_parent"
   tools:context = ".MainActivity"
   android:orientation = "vertical">
   <Button
      android:id = "@+id/read"
      android:text = "read"
      android:layout_width = "wrap_content"
      android:layout_height = "wrap_content" />
   <TextView
      android:id = "@+id/output"
      android:layout_width = "wrap_content"
      android:textSize = "25sp"
      android:layout_height = "wrap_content" />
</LinearLayout>

위 코드에는 ButtonTextView가 포함되어 있습니다. 사용자가 버튼을 클릭하면 외부 저장소에서 데이터를 가져와 TextView에 표시하는 구조입니다.

3단계 – 메인 액티비티 코드 작성

src/MainActivity.java에 다음 코드를 추가합니다.

package com.example.andy.myapplication;

import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;

public class MainActivity extends AppCompatActivity {
   private static final int PERMISSION_REQUEST_CODE = 100;
   Button read;
   TextView output;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      output = findViewById(R.id.output);
      read = findViewById(R.id.read);
      read.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
            String state = Environment.getExternalStorageState();
            if (Environment.MEDIA_MOUNTED.equals(state)) {
               if (Build.VERSION.SDK_INT >= 23) {
                  if (checkPermission()) {
                     File sdcard = Environment.getExternalStorageDirectory();
                     File dir = new File(sdcard.getAbsolutePath() + "/text/");
                     if(dir.exists()) {
                        File file = new File(dir, "sample.txt");
                        FileOutputStream os = null;
                        StringBuilder text = new StringBuilder();
                        try {
                           BufferedReader br = new BufferedReader(new FileReader(file));
                           String line;
                           while ((line = br.readLine()) != null) {
                              text.append(line);
                              text.append('\n');
                           }
                           br.close();
                        } catch (IOException e) {
                           //You'll need to add proper error handling here
                        }
                        output.setText(text);
                     }
                  } else {
                     requestPermission(); // Code for permission
                  }
               } else {
                  File sdcard = Environment.getExternalStorageDirectory();
                  File dir = new File(sdcard.getAbsolutePath() + "/text/");
                  if(dir.exists()) {
                     File file = new File(dir, "sample.txt");
                     FileOutputStream os = null;
                     StringBuilder text = new StringBuilder();
                     try {
                        BufferedReader br = new BufferedReader(new FileReader(file));
                        String line;
                        while ((line = br.readLine()) != null) {
                           text.append(line);
                           text.append('\n');
                        }
                        br.close();
                     } catch (IOException e) {
                        //You'll need to add proper error handling here
                     }
                     output.setText(text);
                  }
               }
            }
         }
      });
   }

   private boolean checkPermission() {
      int result = ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.READ_EXTERNAL_STORAGE);
      if (result == PackageManager.PERMISSION_GRANTED) {
         return true;
      } else {
         return false;
      }
   }
   private void requestPermission() {
      if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, android.Manifest.permission.READ_EXTERNAL_STORAGE)) {
         Toast.makeText(MainActivity.this, "Write External Storage permission allows us to read files. Please allow this permission in App Settings.", Toast.LENGTH_LONG).show();
      } else {
         ActivityCompat.requestPermissions(MainActivity.this, new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
      }
   }

   @Override
   public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
      switch (requestCode) {
         case PERMISSION_REQUEST_CODE:
         if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Log.e("value", "Permission Granted, Now you can use local drive .");
         } else {
            Log.e("value", "Permission Denied, You cannot use local drive .");
         }
         break;
      }
   }
}

코드 동작 방식

  • checkPermission(): READ_EXTERNAL_STORAGE 권한이 이미 부여되었는지 확인합니다.
  • requestPermission(): 권한이 없을 경우 사용자에게 권한 요청 다이얼로그를 표시합니다.
  • onRequestPermissionsResult(): 사용자의 권한 승인 여부에 따라 결과를 로그로 출력합니다.

또한 안드로이드 6.0(API 23) 이상에서는 런타임에 권한을 요청해야 하며, 그 이전 버전에서는 매니페스트에 선언만 하면 되므로 코드에서 SDK 버전을 분기 처리하고 있습니다.

4단계 – 매니페스트 설정

manifest.xml에 아래 코드를 추가합니다.

<?xml version = "1.0" encoding = "utf-8"?>
<manifest xmlns:android = "https://schemas.android.com/apk/res/android"
   package = "com.example.andy.myapplication">
   <uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE"/>
   <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/AppTheme">
      <activity android:name = ".MainActivity">
         <intent-filter>
            <action android:name = "android.intent.action.MAIN" />
            <category android:name = "android.intent.category.LAUNCHER" />
         </intent-filter>
      </activity>
   </application>
</manifest>

앱 실행 및 결과 확인

이제 애플리케이션을 실행해 보겠습니다. 실제 안드로이드 기기가 컴퓨터에 연결되어 있다고 가정합니다. Android Studio에서 프로젝트의 액티비티 파일 중 하나를 연 뒤 툴바의 Run 아이콘을 클릭하고, 실행 옵션에서 자신의 모바일 기기를 선택하세요. 그러면 모바일 기기에 아래와 같은 기본 화면이 나타납니다.

안드로이드에서 런타임 권한으로 외부 저장소의 txt 파일을 읽는 방법

위 화면에서 read 버튼을 클릭하면 sample.txt 파일의 내용이 아래와 같이 화면에 표시됩니다.

안드로이드에서 런타임 권한으로 외부 저장소의 txt 파일을 읽는 방법

참고 사항

안드로이드 10(API 29)부터 도입된 범위 지정 저장소(Scoped Storage) 정책에 따라, 최신 OS 버전을 대상으로 하는 앱이라면 MANAGE_EXTERNAL_STORAGE 권한이나 Storage Access Framework(SAF), MediaStore API 등을 함께 고려하는 것이 좋습니다. 또한 대용량 파일을 읽을 때는 UI 스레드 차단을 방지하기 위해 백그라운드 스레드나 코루틴을 활용하는 것이 바람직합니다.