0

The issue I have is there're always Null Pointer Exception when I settext textview, so I cannot setText to my view.

I think the object didn't fill the field from getData method. How to fix this?

I am following this step https://firebase.google.com/docs/firestore/query-data/listen#listen_to_multiple_documents_in_a_collection and this Parcelable object passing from android activity to fragment.

This is the error output from android studio console

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.my.plkbi, PID: 24337
    java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.my.plkbi.Layanan.getSyarat()' on a null object reference
        at com.my.plkbi.SubMainFragment.onCreateView(SubMainFragment.java:78)
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2600)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:881)
        at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
        at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
        at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
        at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
        at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
        at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
        at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6119)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

EDIT: Add constructor to add object from other object, I follow this How do I copy an object in Java? This is the object about the field database and Parcelable

public class Layanan implements Parcelable {
    private String Nama;
    private String Syarat;
    private String Langkah;
    private String Lampiran;

    public Layanan(){
        //this("connect to internet", "connect to internet", "connect to internet", "connect to internet");
    }

//Constructor to add value from another object
    public Layanan(Layanan another) {
        this.nama = another.nama;
        this.syarat = another.syarat;
        this.langkah = another.langkah;
        this.lampiran = another.lampiran;
        this.deskripsi = another.deskripsi;
    }

    protected Layanan(Parcel in) {
        Nama = in.readString();
        Syarat = in.readString();
        Langkah = in.readString();
        Lampiran = in.readString();
    }

    public static final Creator<Layanan> CREATOR = new Creator<Layanan>() {
        @Override
        public Layanan createFromParcel(Parcel in) {
            return new Layanan(in);
        }

        @Override
        public Layanan[] newArray(int size) {
            return new Layanan[size];
        }
    };

    public static Layanan newInstance() {

        Bundle args = new Bundle();

        Layanan fragment = new Layanan();
        fragment.setArguments(args);
        return fragment;
    }

    private void setArguments(Bundle args) {

    }

    public String getNama() {
        return Nama;
    }

    public String getSyarat() {
        return Syarat;
    }

    public void setSyarat(String syarat) {
        Syarat = syarat;
    }

    public String getLangkah() {
        return Langkah;
    }

    public void setNama(String nama) {
        Nama = nama;
    }

    public void setLangkah(String langkah) {
        Langkah = langkah;
    }

    public String getLampiran() {
        return Lampiran;
    }

    public void setLampiran(String lampiran) {
        Lampiran = lampiran;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(Nama);
        dest.writeString(Syarat);
        dest.writeString(Langkah);
        dest.writeString(Lampiran);
    }
}

This is how i get data from Firebase, it's inside in activity

Layanan UP;
Layanan GU;
Layanan LS;


    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if(savedInstanceState == null) {
            //initMF();
            MainFragment homeFragment = MainFragment.newInstance();

            Bundle extras = new Bundle();


            getData("UP");
            Log.d(TAG, "This is the value name of " + UP.getNama()); //Output: This is the value name of null
            extras.putParcelable(UPParcelable, UP);
            if (UP.getSyarat()!=null) Log.d(TAG, "Value Added"); 
            if (UP.getSyarat()==null) Log.d(TAG, "Value not Added"); //Output: Value not Added

            homeFragment.setArguments(extras);
            getSupportFragmentManager().beginTransaction().add(R.id.main_activity, homeFragment).commit();
        }
...
...
    public void getData(final String p){
        mFirebase.collection("panduan_layanan")
                .whereEqualTo("nama", p)
                .addSnapshotListener(new EventListener<QuerySnapshot>() {

                    @Override
                    public void onEvent(@Nullable QuerySnapshot value, @Nullable FirebaseFirestoreException e) {
                        if (e != null){
                            Log.w(TAG, "onEvent:error", e);
                            return;
                        }
                        Layanan newLayanan = new Layanan();
                        for (QueryDocumentSnapshot doc : value) {
                            if (doc.get("nama") != null && doc.get("syarat") != null && doc.get("langkah") != null && doc.get("lampiran")!= null){
                                newLayanan.setNama(doc.getString("nama"));
                                newLayanan.setLampiran(doc.getString("lampiran"));
                                newLayanan.setLangkah(doc.getString("langkah"));
                                newLayanan.setSyarat(doc.getString("syarat"));
                                Log.d(TAG, "Update data: Success" + p);
                                Log.d(TAG, "This is the " + p + " syarat" + newLayanan.getSyarat());
                                if (newLayanan.getSyarat() != null) Log.d(TAG, "new layanan is" + newLayanan.getNama()); //new layanan isUP, it is work too
                            }
                        }
                        if (p.equals("UP")) UP = new Layanan(newLayanan);
                        Log.d(TAG, "the" + UP.getNama());  //Output theUP so it is work in here
                        if (p.equals("GU")) GU = new Layanan(newLayanan);
                        if (p.equals("LS")) LS = new Layanan(newLayanan);
                    }
                });
    }
...

Thank you so much

Fares TP
  • 11
  • 1
  • 1
  • 3
  • If you have an exception, grab the exact error message and stack trace from the logcat output of your app and add them to your question. – Frank van Puffelen May 05 '20 at 13:38
  • Thank you @FrankvanPuffelen I will add it – Fares TP May 05 '20 at 13:44
  • Thanks. Next up, what's this line in your code `com.my.plkbi.SubMainFragment.onCreateView(SubMainFragment.java:78)`? These are things you should always do straight away btw, as it improves the chances somebody will be able to help. – Frank van Puffelen May 05 '20 at 13:56
  • None of the code you shared seems to include this call: `Layanan.getSyarat()`. But it seems that it is unable to create a `Layanan` out of the data from the database. I recommend setting a breakpoint on where you create/populate the `Layanan` object, and stepping through that in a debugger. – Frank van Puffelen May 05 '20 at 13:58
  • Thank you for your follow up. This is the code from line 77 and 78. `Layanan UP = getArguments().getParcelable("UPParcelable");` `expandedCardText1.setText(UP.getSyarat());` – Fares TP May 05 '20 at 14:24
  • I thought that, when I call `getData("UP", UP = new Layanan());` it will assign new UP. I declare the UP as field in activity class. Can you show me example about what making breakpoint means? Where is the good place for me to instantiate the object and assign them, cause if I instance it from getdata method, the object will remain there and I cannot access them. Could you show me some reading material? Sorry for troubling you @FrankvanPuffelen. Thank you so much – Fares TP May 05 '20 at 14:41
  • If you've never debugger an (android) app, this would be a good place to get started: https://developer.android.com/studio/debug – Frank van Puffelen May 05 '20 at 19:52
  • Ok so after using Log.d in several place, the issue I have is, when I call getData() in onCreate, the value from UP isn't assigned and still null. After I edit the code, before the for blocks, I add the new Layanan, and after the for block, I assign UP (which is the field with Layanan as the type), UP didn't get the value from getData calling @FrankvanPuffelen – Fares TP May 06 '20 at 00:16
  • It sounds like you're trying to work around the asynchronous nature of Cloud Firestore (and most other cloud APIs). I recommend instead embracing them: all code that needs data from the database, needs to be inside the `onEvent` that gets called when the data from the database is available, or be called from there. Also see https://stackoverflow.com/questions/50434836/getcontactsfromfirebase-method-return-an-empty-list/50435519#50435519 – Frank van Puffelen May 06 '20 at 02:30
  • Well, that's sound more complicated than I expected, could you elaborate more or give me some another link? – Fares TP May 06 '20 at 03:20
  • The only think I'm sure what the problem is when I call the getData in onCreateView, i can't submit the value from Layanan object from class field, look at my newer updated code @FrankvanPuffelen . Don't you think so? How to fix it? Thank you, so much – Fares TP May 06 '20 at 03:40

1 Answers1

0

You can't do that because firebase execute that block asynchronously. So the field doesn't get value immediately just like Frank's comment said

Fares TP
  • 11
  • 1
  • 1
  • 3