I have an application published on the Play Store (Google Play). For months now, I have been receiving an error in my console. First of all, here is the relevant code from my application:
MainActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//more code
//get storage directories
rutasTemp = getStorageDirectoriesWithoutNull(this);
int indexTemp = 0;
for (String s : rutasTemp) {
if (!(s.contains("usb"))) {
indexTemp++;
}
}
if (externalMemoryAvailable(this)) {
rutas = new String[indexTemp];
indexTemp = 0;
for (String s : rutasTemp) {
if (!(s.contains("usb"))) {
rutas[indexTemp] = s;
indexTemp++;
}
}
for (int i=0; i<rutas.length; i++) {
if (rutas[i].contains("emulated")) {
String temp = rutas[0];
rutas[0] = rutas[i];
rutas[i] = temp;
}
}
} else {
rutas = new String[1];
rutas[0] = Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/";
}
//more code
carpetasPreferences = getSharedPreferences(SHARED_CARPETAS, Context.MODE_PRIVATE);
}
private void prepararPlayer(int desdeDonde) {
//more code
Map<String, ?> carpetasMap = carpetasPreferences.getAll();
String[] carpetasArray = null;
carpetasArray = new String[carpetasMap.size()];
int indice = 0;
for (Map.Entry<String, ?> asno: carpetasMap.entrySet()) {
carpetasArray[indice] = asno.getValue().toString() + "/";
indice++;
}
if (carpetasMap.size() == 0) {
if (notClickedOnce) {
carpetasArray = new String[rutas.length];
//button pressed first time
carpetasArray[0] = Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/Music/";
if (rutas.length > 1) {
carpetasArray[1] = rutas[1];
}
}
}
if (desdeDonde == 0) {
if (sharedPreferences.contains(LIST_OF_FILES)) {
nombresArchivo = sharedPreferences.getStringSet(LIST_OF_FILES, new HashSet<String>());
} else {
buscarArchivos = new BuscarArchivos(this, carpetasArray, nombresArchivo, desdeDonde);
buscarArchivos.execute();
}
} else {
buscarArchivos = new BuscarArchivos(this, carpetasArray, nombresArchivo, desdeDonde);
buscarArchivos.execute();
}
//more code
}
private static class BuscarArchivos extends AsyncTask<Void, Void, String> {
WeakReference<MainActivity> activityReference;
String[] carpetasArray;
Set<String> nombArch;
int desdeDonde;
BuscarArchivos(MainActivity activity, String[] carpetasArray, Set<String> nombresArchivo,
int desdeDonde) {
this.activityReference = new WeakReference<>(activity);
this.carpetasArray = carpetasArray;
this.nombArch = nombresArchivo;
this.desdeDonde = desdeDonde;
}
@Override
protected String doInBackground(Void... voids) {
try {
for (String asn : carpetasArray) {
activityReference.get().listAllFiles(asn, nombArch);
}
activityReference.get().sharedPreferencesEditor
.putStringSet(activityReference.get()
.LIST_OF_FILES, nombArch);
activityReference.get().sharedPreferencesEditor.apply();
} catch (Exception e) {
Writer writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer));
return writer.toString();
}
return "final";
}
//rest of the code of BuscarArchivos
}
public void listAllFiles(String rutaAdentro, Set<String> archivos) {
File file = new File(rutaAdentro);
File[] files = file.listFiles();
if (files != null) {
for (File asno : files) {
if (asno.isFile()) {
archivos.add(asno.getName());
} else if (asno.isDirectory()) {
listAllFiles(asno.getAbsolutePath(), archivos);
}
}
}
}
private String[] getStorageDirectoriesWithoutNull(Context context) {
String[] allDirectories = StorageUtil
.getStorageDirectories(context);
ArrayList<String> directoriesList = new ArrayList<>();
for (String directory : allDirectories) {
if (directory != null) {
directoriesList.add(directory);
}
}
return directoriesList.toArray(new String[0]);
}
I'm using the library StorageUtil by hendrawd (https://github.com/hendrawd/StorageUtil) in the getStorageDirectoriesWithoutNull
method.
The following is the adapter used in the activity in which a select music folders:
Adapter
public Adaptador(Context contextInside, int layoutIdInside, ArrayList<HashMap<String,
String>> listaInside, String rutaInside) {
//more code
carpetasPreferences = getContext().getSharedPreferences(SHARED_CARPETAS, Context.MODE_PRIVATE);
carpetasPreferencesEditor = carpetasPreferences.edit();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//more code
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if (b) {
carpetasPreferencesEditor.putString(elemento.get(PATH), elemento.get(PATH));
carpetasPreferencesEditor.apply();
} else {
if (carpetasPreferences.contains(elemento.get(PATH))) {
carpetasPreferencesEditor.remove(elemento.get(PATH));
carpetasPreferencesEditor.apply();
}
}
if (carpetasPreferences.contains(ruta)) {
carpetasPreferencesEditor.remove(ruta);
carpetasPreferencesEditor.apply();
}
}
});
//rest of the code
}
I hope I've included all the relevant code. If I've forgotten something, I'd appreciate it if you let me know.
I'm having the following error in my google play console:
java.lang.NullPointerException
at java.io.File.<init>(File.java:283)
at gym.timer.app.MainActivity.listAllFiles(MainActivity.java:3093)
at gym.timer.app.MainActivity$BuscarArchivos.doInBackground(MainActivity.java:3133)
at gym.timer.app.MainActivity$BuscarArchivos.doInBackground(MainActivity.java:3118)
at android.os.AsyncTask$3.call(AsyncTask.java:394)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:305)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
As you can see, I'm having a NullPointerException in the line: File[] files = file.listFiles();
.
The application works well on almost all devices, but I am experiencing errors on a few devices, specifically/only on Samsung A series devices. Below, I list the models of the devices:
error SM-A217M sdk 31
error SM-A127M sdk 30
error SM-A305G sdk 30
error SM-A505G sdk 30
error SM-A307G sdk 30
error SM-A505G sdk 30
error SM-A105M sdk 30
error SM-A307G sdk 29
error SM-A305G sdk 30
error SM-A217F sdk 30
error SM-A127M sdk 33
I hope someone can help me. Thank you.
I bought a smartphone, specifically the 'SM-A307G,' which is one of the models where the error appears, just to be able to reproduce the error. I formatted it, installed the application, but no error appears; it works normally. What I wanted was to reproduce the error, but no error appeared.
The File one param constructors throws NPE when called with null
public File(String pathname) {
if (pathname == null) {
// your initial error
throw new NullPointerException();
}
this.path = fs.normalize(pathname);
this.prefixLength = fs.prefixLength(this.path);
}
The error stacktrace doesnt show any recursive call so the error came from initial call to the function
for (String asn : carpetasArray) {
activityReference.get().listAllFiles(asn, nombArch);
}
So you may have one null
value in your carpetasArray
IMHO, the following code could produce null
values in this array
if (notClickedOnce) {
// possible null values here if rutas.length > 2, since you dont set carpetasArray indices higher than 1
carpetasArray = new String[rutas.length];
//button pressed first time
carpetasArray[0] = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Music/";
if (rutas.length > 1) {
// possible null value here if rutas[1] is null
carpetasArray[1] = rutas[1];
}
}
Since we have no idea from where rutas
came from, my guess would be to look for the to above possibilities.
You can also protect your listAllFiles
function to add something like
public void listAllFiles(String rutaAdentro, Set<String> archivos) {
if (rutaAdentro != null) {
// only run the function if rutaAdentro is not null to avoid NPE on new File(null)
File file = new File(rutaAdentro);
File[] files = file.listFiles();
if (files != null) {
for (File asno : files) {
if (asno.isFile()) {
archivos.add(asno.getName());
} else if (asno.isDirectory()) {
listAllFiles(asno.getAbsolutePath(), archivos);
}
}
}
}
}
By doing so, you shouldnt have NPE anymore.