I have a listview that I am trying to populate by changing the text of the row xml to the file paths in the folder (so I can later perform operations on the files. I am getting a crash upon starting the activity.
My code: FileView.java
package com.loopbreakr.firstpdf; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; import java.io.File; import java.util.List; public class FileView extends AppCompatActivity { ListView listView; String filePath = ""; List<String> stringList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_file_view); listView = findViewById(R.id.listView); filePath = "PDF_files"; File file = new File(getExternalFilesDir(filePath).toString()); File[] fileList = file.listFiles(); for (int i = 0; i < fileList.length; i++) { stringList.add(fileList[i].getName()); } String[] modded = (String[]) stringList.toArray(); MyAdapter adapter = new MyAdapter(this, modded); listView.setAdapter(adapter); } class MyAdapter extends ArrayAdapter<String> { Context context; String rTitle[]; MyAdapter(Context c, String title[]) { super(c, R.layout.row, R.id.activityTitle, title); this.context = c; this.rTitle = title; } @NonNull @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { LayoutInflater layoutInflater = (LayoutInflater)getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); View row = layoutInflater.inflate(R.layout.row, parent, false); TextView myTitle = row.findViewById(R.id.activityTitle); myTitle.setText(rTitle[position]); return row; } } }
activity_file_view.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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" android:orientation="vertical" tools:context=".FileView"> <ListView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/listView"/> </LinearLayout>
row.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp"> <ImageView android:layout_width="75dp" android:layout_height="75dp" android:src="@mipmap/ic_launcher" android:id="@+id/image" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/activityTitle" android:text="Main Title" android:textColor="#000" style="bold" android:layout_margin="5dp" android:textSize="20sp"/> </LinearLayout> </LinearLayout>
I am getting this error:
2021-01-26 01:49:46.447 22787-22787/com.loopbreakr.firstpdf E/AndroidRuntime: FATAL EXCEPTION: main Process: com.loopbreakr.firstpdf, PID: 22787 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.loopbreakr.firstpdf/com.loopbreakr.firstpdf.FileView}: java.lang.NullPointerException: Attempt to invoke interface method 'boolean java.util.List.add(java.lang.Object)' on a null object reference at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7656) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'boolean java.util.List.add(java.lang.Object)' on a null object reference at com.loopbreakr.firstpdf.FileView.onCreate(FileView.java:35) at android.app.Activity.performCreate(Activity.java:8000) at android.app.Activity.performCreate(Activity.java:7984) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
Appears to be a null object reference, but I am unsure how to solve
Advertisement
Answer
The root of your issue is stringList.add(fileList[i].getName());
where stringList
is not initialized. so try the following,
listView = findViewById(R.id.listView); // initialization code stringList = new ArrayList(); String[] modded = (String[]) stringList.toArray(); // comment this line out // pass the ArrayList instead of Array MyAdapter adapter = new MyAdapter(this, stringList); //rest of the logic remains same
Edit:
Though your adapter seems to work, the inflation logic is wrong as your arent recycling the views instead just creating new views for every data item to be displayed, so try the following instead
// recommended adapter code class MyAdapter extends ArrayAdapter<String> { Context context; List<String> rTitle; MyAdapter(Context c, List<String> title) { // since you will be inflating views manually, you don't need to pass any layoutId instead just pass 0 super(c, 0 , title); this.context = c; this.rTitle = title; } @NonNull @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { // convertView contains the old used view if any, else create a new view if(convertView == null){ LayoutInflater layoutInflater = (LayoutInflater)getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = layoutInflater.inflate(R.layout.row, parent, false); } TextView myTitle = convertView.findViewById(R.id.activityTitle); myTitle.setText(rTitle.get(position)); //return convertview return convertView; } }