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
JavaScript
x
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
JavaScript
<?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
JavaScript
<?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:
JavaScript
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,
JavaScript
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
JavaScript
// 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;
}
}