File.listFiles() is returning null in android 11

Viewed 2596

I was creating an application to test whether File.listFiles() method is working or not. To check this I made an application and I used it there but this returning null in place of an array. This is my full code please help and I have granted all permissions for android 11

MainActivity.java

package com.rajkumarcreations.file;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.widget.TextView;
import android.widget.Toast;

import org.w3c.dom.Text;

import java.io.File;

import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.os.Build.VERSION.SDK_INT;

public class MainActivity extends AppCompatActivity {
TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.btn);
        if(!checkPermission()){
            requestPermission();
        }else{
            File file = new File(Environment.getExternalStorageDirectory()+"/Download/");
            File[] allfiles = null;
            allfiles = file.listFiles();
            if(file.exists()){
                tv.setText("Exist");
            }
            if(allfiles!=null){
                Toast.makeText(this, "length is "+allfiles.length, Toast.LENGTH_SHORT).show();
            }else{
                Toast.makeText(this, "Array is null", Toast.LENGTH_SHORT).show();
            }
        }
    }

    private boolean checkPermission() {
        if (SDK_INT >= Build.VERSION_CODES.R) {
            return Environment.isExternalStorageManager();
        } else {
            int write = ContextCompat.checkSelfPermission(MainActivity.this, WRITE_EXTERNAL_STORAGE);
            int read = ContextCompat.checkSelfPermission(MainActivity.this, READ_EXTERNAL_STORAGE);
            return write == PackageManager.PERMISSION_GRANTED && read == PackageManager.PERMISSION_GRANTED;
        }
    }

    private void requestPermission() {
        if (SDK_INT >= Build.VERSION_CODES.R) {
            try {
                Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
                intent.addCategory("android.intent.category.DEFAULT");
                intent.setData(Uri.parse(String.format("package:%s",new Object[]{getApplicationContext().getPackageName()})));
                startActivityForResult(intent, 2000);
            } catch (Exception e) {
                Intent intent = new Intent();
                intent.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
                startActivityForResult(intent, 2000);
            }
        } else {
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{WRITE_EXTERNAL_STORAGE,READ_EXTERNAL_STORAGE}, 333);
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 2000) {
            if (SDK_INT >= Build.VERSION_CODES.R) {
                if (Environment.isExternalStorageManager()) {

                    Toast.makeText(this, "Allow permissions granted", Toast.LENGTH_SHORT).show();

                } else {
                    Toast.makeText(this, "Allow permission for storage access!", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode,permissions,grantResults);
        if (requestCode==333){
            if (grantResults.length > 0) {
                boolean WRITE_EXTERNAL_STORAGE = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                boolean READ_EXTERNAL_STORAGE = grantResults[1] == PackageManager.PERMISSION_GRANTED;
                if (READ_EXTERNAL_STORAGE && WRITE_EXTERNAL_STORAGE) {

                    Toast.makeText(this, "All permissions granted", Toast.LENGTH_SHORT).show();

                } else {
                    Toast.makeText(this, "Allow permission for storage access!", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
}

Manifest File

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.rajkumarcreations.file">
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.MANAGE_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:requestLegacyExternalStorage="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>

XML File

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:id="@+id/btn"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
3 Answers

According to your requirement you were trying to access list of files under a directory by using listfiles() method. And want check it is working or not. But this returning null.

First, Declare the MANAGE_EXTERNAL_STORAGE permission in the manifest.

// For 30 and after
<uses-permission
    android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
    tools:ignore="ScopedStorage" />

// For before 30
<uses-permission
    android:name="android.permission.READ_EXTERNAL_STORAGE"
    tools:node="merge" />
<uses-permission
    android:name="android.permission.STORAGE"
    tools:node="merge" />

// For 30 and after

Second, Use the ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION intent action to direct users to a system settings page where they can enable the following option for your app: Allow access to manage all files.

Write the code on your onCreate Method:

if (Build.VERSION.SDK_INT < 30) {
    if (!checkBefore30()) {
        requestBefore30();
    } else { 
      // User granted file permission, Access your file
      readFiles();
    }
  } else if (Build.VERSION.SDK_INT >= 30) {
    check30AndAfter();
  } else {
    // User already has file access permission
    readFiles();
}

Write those methods on your Activity:

private boolean checkBefore30() {
     return ContextCompat.checkSelfPermission(YourActivity.this,
         Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
}


private void requestBefore30() {
   if(ActivityCompat.shouldShowRequestPermissionRationale(YourActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE)) {
                    Toast.makeText(LoginActivity.this, "Storage permission required. Please allow this permission", Toast.LENGTH_LONG).show();
                    ActivityCompat.requestPermissions(YourActivity.this, 
                            new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, 100);
                } else {
                    ActivityCompat.requestPermissions(YourActivity.this, 
                            new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, 100);
   }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    switch (requestCode) {
        case 100:
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission for storage access successful!
                // Read your files now
            } else {
                // Allow permission for storage access!
            }
            break;
    }
}


@RequiresApi(api = Build.VERSION_CODES.R)
private void check30AndAfter() {
    if (!Environment.isExternalStorageManager()) {
        try {
            Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
            intent.addCategory("android.intent.category.DEFAULT");
            intent.setData(Uri.parse(String.format("package:%s", getApplicationContext().getPackageName())));
            startActivityForResult(intent, 200);
        } catch (Exception e) {
            Intent intent = new Intent();
            intent.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
            startActivityForResult(intent, 200);
        }
    }
}

@RequiresApi(api = Build.VERSION_CODES.R)
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 200) {
        if (30 >= Build.VERSION_CODES.R) {
            if (Environment.isExternalStorageManager()) {
                // Permission for storage access successful!
                // Read your files now
            } else {
                // Allow permission for storage access!
            }
        }
    }
}


private void readFiles() {
        File file;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString());
        } else {
            file = new File(Environment.getExternalStorageDirectory().toString() + "/Download/");
        }
        File[] files= null;
        files= file.listFiles();
        if (file.exists()) {
            //  files exist
        }
        if (allfiles != null) {
            Toast.makeText(this, " file length is" + files.length, Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "No files", Toast.LENGTH_SHORT).show();
        }
    }

Hopefully your problem will be solved.

Try with the following code it's working.

 //Add below permission in your manifest file
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />


//Add below attribute in manifest application tag
 android:requestLegacyExternalStorage="true"

//Activity code, ask file read/write runtime permission
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main2);
    requestForPermission();
    getFile();
}

private void getFile() {
    File file;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString());
    } else {
        file = new File(Environment.getExternalStorageDirectory().toString() + "/Download/");
    }
    File[] allfiles = null;
    allfiles = file.listFiles();
    if (file.exists()) {
        tv.setText("Exist");
    }
    if (allfiles != null) {
        Toast.makeText(this, "length is " + allfiles.length, Toast.LENGTH_SHORT).show();
    } else {
        Toast.makeText(this, "Array is null", Toast.LENGTH_SHORT).show();
    }
}

private void requestForPermission() {
    ActivityCompat.requestPermissions(
            this,
            new String[]{
                    android.Manifest.permission.READ_EXTERNAL_STORAGE,
                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE
            },
            101
    );
}


@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case 101:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                getFile();
            } else {
                //not granted
            }
            break;
        default:
            break;
    }
}
}

Add this to AndroidManifest.xml,

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

This permission allow you to read files; if you don't use this permission then listFiles() and list() will both throw NullPointerException.

And here is an example of showing all files in /storage/emulated/0/Download:

String dir = "/storage/emulated/0/Download/";
File f = new File(dir);
String[] files = f.list();
for(int i=0; i<files.length; i++){
    Log.d("tag", files[i]);
}

For those who are working on android SDK>23, you need to grant the permissions by code,

boolean grantedAll = ContextCompat.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
if (!grantedAll) {
     ActivityCompat.requestPermissions(thisActivity,
            new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
            REQUEST_PERMISSIONS);
   }

If you still have the problem it is because you have set Target API 29 or higher. Then add this property in your application tag of AndroidManifest.xml file and it will work.

android:requestLegacyExternalStorage="true"

According to Google app compatibility features for data storage:

Before your app is fully compatible with scoped storage, you can temporarily opt out by using one of the following methods:

  • Target Android 9 (API level 28) or lower.

  • If you target Android 10 (API level 29) or higher, set the value of requestLegacyExternalStorage to true in your app's manifest file:

    <manifest ... >
    <!-- This attribute is "false" by default on apps targeting
         Android 10 or higher. -->
        <application android:requestLegacyExternalStorage="true" ... >
            ...
        </application>
    </manifest>
    

To test how an app targeting Android 9 or lower behaves when using scoped storage, you can opt in to the behavior by setting the value of requestLegacyExternalStorage to false.

Related