Skip to content
Advertisement

Trying to populate listview with array text

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;
        }
    }
User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement