Android
 Computer >> コンピューター >  >> プログラミング >> Android

【Android】ランタイム権限を使ってSDカードのファイル一覧を表示する方法

はじめに

この記事では、Androidアプリでランタイム権限(実行時パーミッション)を取得したうえで、SDカード(外部ストレージ)内のファイル一覧を取得して画面に表示する方法を解説します。

ステップ1:新規プロジェクトの作成

Android Studioを起動し、「File」→「New Project」を選択して新しいプロジェクトを作成します。必要な項目をすべて入力し、プロジェクトのセットアップを完了させてください。

ステップ2:レイアウトファイル(activity_main.xml)の編集

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" />
   <ListView
      android:id = "@+id/list"
      android:layout_width = "match_parent"
      android:layout_height = "wrap_content"></ListView>
</LinearLayout>

上記のレイアウトでは、ファイル一覧を表示するための「ListView」と、ストレージの読み取りを開始するための「Button」を縦方向に配置しています。ボタンがクリックされると外部ストレージからデータを取得し、その結果がListViewに反映される仕組みです。

ステップ3:MainActivity.java の実装

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.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

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

public class MainActivity extends AppCompatActivity {
    private static final int PERMISSION_REQUEST_CODE = 100;
    Button read;
    ArrayList<String> myList;
    ListView listview;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        listview = findViewById(R.id.list);
        read = findViewById(R.id.read);
        myList = new ArrayList<>();
        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 dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/");
                            if (dir.exists()) {
                                Log.d("path", dir.toString());
                                File list[] = dir.listFiles();
                                for (int i = 0; i < list.length; i++) {
                                    myList.add(list[i].getName());
                                }
                                ArrayAdapter arrayAdapter = new ArrayAdapter(MainActivity.this, android.R.layout.simple_list_item_1, myList);
                                listview.setAdapter(arrayAdapter);
                            }
                        } else {
                            requestPermission(); // 権限をリクエスト
                        }
                    } else {
                        File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/");
                        if (dir.exists()) {
                            Log.d("path", dir.toString());
                            File list[] = dir.listFiles();
                            for (int i = 0; i < list.length; i++) {
                                myList.add(list[i].getName());
                            }
                            ArrayAdapter arrayAdapter = new ArrayAdapter(MainActivity.this, android.R.layout.simple_list_item_1, myList);
                            listview.setAdapter(arrayAdapter);
                        }
                    }
                }
            }
        });
    }
    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, "ストレージへのアクセス権限がないとファイルを読み取れません。アプリ設定で権限を許可してください。", 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 権限がすでに許可されているかどうかを確認します。
  • 権限リクエスト:API 23(Android 6.0)以降では実行時にユーザーへ権限を要求する必要があるため、未許可の場合は requestPermission() を呼び出します。
  • ファイル一覧の取得:Environment.getExternalStorageDirectory() で外部ストレージのルートディレクトリを取得し、listFiles() の結果から各ファイル名をArrayListへ順に格納します。
  • 結果の表示:ArrayAdapter を使用して、取得したファイル名の一覧をListViewに表示します。

ステップ4:AndroidManifest.xml への権限宣言

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>

外部ストレージへアクセスするために、READ_EXTERNAL_STORAGE と WRITE_EXTERNAL_STORAGE の2つのパーミッションを宣言しています。

アプリの実行と動作確認

それではアプリを実行してみましょう。ここでは、実際のAndroid端末をPCに接続しているものとします。Android Studioでプロジェクト内のアクティビティファイルを開き、ツールバーの「Run」アイコンをクリックしてください。実行デバイスとして自分の端末を選択すると、端末に以下のような初期画面が表示されます。

【Android】ランタイム権限を使ってSDカードのファイル一覧を表示する方法

この画面で「read」ボタンをタップすると、権限の許可後に外部ストレージ直下のファイル一覧が次のように表示されます。

【Android】ランタイム権限を使ってSDカードのファイル一覧を表示する方法

補足:新しいAndroidバージョンでの注意点

Android 10(API 29)以降ではスコープドストレージが導入され、従来のように外部ストレージ全体へ自由にアクセスすることが制限されています。Android 11以降で広範なファイルアクセスが必要な場合は、MANAGE_EXTERNAL_STORAGE 権限の利用や、MediaStore API・Storage Access Framework の活用を検討してください。また、サンプルコードで使われている android.support ライブラリはすでに非推奨となっているため、新規開発では AndroidX(androidx.appcompat など)への移行が推奨されます。

  1. 【保存版】Androidの内部ストレージからSDカードへファイルを転送する方法

    すべてのAndroidスマートフォンには内部ストレージの容量に限りがあり、使い続けるうちに徐々に一杯になっていきます。2年以上同じスマホを使っているなら、すでに「ストレージ容量不足」に悩まされている可能性も高いでしょう。これは、時間が経つにつれてアプリ自体のサイズや、それに関連するデータが占める領域が大きくなるためです。古いスマホでは、新しいアプリやゲームのストレージ要件についていくのが難しくなります。さらに、写真や動画といった個人メディアファイルも大量の容量を消費します。そこで本記事では、Androidの内部ストレージからSDカードへファイルを転送する方法をご紹介します。 前述のとおり、

  2. Androidの内部ストレージからSDカードへファイルを移動する方法|移動してはいけないファイルも解説

    銀行取引からショッピングまで、あらゆることがスマートフォンで完結するようになった今、Androidスマホは日常のほぼすべてのタスクをこなす万能ツールとなっています。SNSの利用はもちろん、ネットショッピング、請求書の支払い、チャージ、音楽のストリーミング再生、さらには金融取引まで、スマホ一台で対応可能です。しかし一方で、実行するタスクごと、ダウンロードする画像ごと、保存する動画ごと、そしてファイル共有アプリでやり取りするメディアファイルごとに、スマホの容量は少しずつ圧迫されていきます。空き容量が減るだけでなく、ジャンクファイルやキャッシュも蓄積され、内部ストレージはさらに膨らんでいくのです。