简体   繁体   中英

Android app crashing when trying to set TextView in a Fragment that is dynamically added to a layout

I am trying to find a way to dynamically add fragments to an activity layout while uniquely setting the TextViews of that Fragment. Say I have the Fragment class ExampleFragment below:

package com.project.testapplication;

import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.project.testapplication.R;

public class ExampleFragment extends Fragment {

    TextView Name, Location;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_layout, container, false);
        Name=(TextView)view.findViewById(R.id.name);
        Location=(TextView)view.findViewById(R.id.location);
        return view;
    }

    public void setName(String n)
    {
        Name.setText(n);
    }

    public void setLocation(String loc)
    {
        Location.setText(loc);
    }

}

Which uses the layout fragment_layout.xml :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="56dp"
        android:text="name"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true" />

    <TextView
        android:id="@+id/location"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/name"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="109dp"
        android:text="location" />
</RelativeLayout>

Now in another activity, I want to add a user-specified number of these fragments to the layout with a user-specified Name and Location (set to the TextView) for each fragment. I am using FragmentManager to add the fragments to my activity. The fragments add correctly when I don't try to edit any of the TextViews in the Fragment (using the setter methods from the Fragment). However, if I try to setText for any of the TextViews from the Fragment, the app crashes. My code below in ExampleActivity class (contains the lines that causes the program to crash):

package com.project.testapplication;

import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import com.project.testapplication.ExampleFragment;
import com.project.testapplication.ExampleObject;
import com.project.testapplication.R;

import java.util.ArrayList;

public class ExampleActivity extends AppCompatActivity {

    ArrayList<ExampleObject> list = new ArrayList<ExampleObject>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_example);

        //Populate "list" ArrayList with "ExampleObject" objects
        list.add(new ExampleObject("name1", "location1"));
        list.add(new ExampleObject("name2", "location2"));
        list.add(new ExampleObject("name3", "location3"));

        for(ExampleObject o: list)
        {
            FragmentManager fragmentManager = getFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            ExampleFragment fragment = new ExampleFragment();
            fragment.setName(o.getName()); /***line causes crash***/
            fragment.setLocation(o.getLocation()); /***line causes crash (if not for line above)***/
            fragmentTransaction.add(R.id.linear_layout_scroll, fragment);
            fragmentTransaction.commit();
        }

    }
}

ExampleObject is defined below:

package com.project.testapplication;

public class ExampleObject {

    String name, location;
    public ExampleObject(String name, String location)
    {
        this.name=name;
        this.location=location;
    }

    public void setName(String name)
    {
        this.name=name;
    }

    public String getName()
    {
        return name;
    }

    public void setLocation(String location)
    {
        this.location=location;
    }

    public String getLocation()
    {
        return location;
    }
}

And in my activity_example.xml layout:

<?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:id="@+id/lin_lay"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.project.testapplication.ExampleActivity">

    <ScrollView
        android:id="@+id/scroll_v"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:id="@+id/linear_layout_scroll"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
        </LinearLayout>
    </ScrollView>
</LinearLayout>

In the ExampleActivity class, when i remove the two lines of code crashing the app, the fragments add fine but without the customized TextViews. I am trying to figure out a way to uniquely set the TextViews (via the methods from the fragment) without crashing the app.

Any responses are appreciated. Thank you.

EDIT: found a solution to my problem, answered below.

I finally was able to figure it out by viewing this post. I had to first add these methods to my ExampleFragment class:

     public static ExampleFragment newInstance(String name, String location) {
             ExampleFragment myFragment = new ExampleFragment();
             Bundle args = new Bundle();
             args.putString("name", name);
             args.putString("location", location);
             myFragment.setArguments(args);

             return myFragment;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        String name = getArguments().getString("name");
        String location = getArguments().getString("location");
        Name.setText(name);
        Location.setText(location);

Then in ExampleActivity, instead of instantiating the fragment as:

ExampleFragment fragment = new ExampleFragment();

I instantiated it as:

ExampleFragment fragment = ExampleFragment.newInstance(o.getName(), o.getLocation());

As well as removed the two lines of code in the OP that were originally causing it to crash. (the fragment.setName() and fragment.setLocation() statements).

The problem was that I was trying to setText on the TextView before they were initialized (before onCreateView was called). This way of instantiating the fragment ensures that the the TextView isn't set until after the fragment view has been created. This post is also a good reference, as well as the documentation on the android website.

Try this code

Fragment

public class ExampleFragment extends Fragment {
    ArrayList<ExampleObject> list = new ArrayList<ExampleObject>();
    TextView Name, Location;

    public ExampleFragment(ArrayList<ExampleObject> arrayList){
        list=arrayList;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup 
    container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_layout, container, 
    false);
        Name=(TextView)view.findViewById(R.id.name);
        Location=(TextView)view.findViewById(R.id.location);
        for(ExampleObject o: list)
        {
        setName(o.getName()); 
            setLocation(o.getLocation());
        }
        return view;
    }

    public void setName(String n)
    {
        Name.setText(n);
    }

    public void setLocation(String loc)
    {
        Location.setText(loc);
    }
}

Activity

public class ExampleActivity extends AppCompatActivity {

    ArrayList<ExampleObject> list = new ArrayList<ExampleObject>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_example);

        //Populate "list" ArrayList with "ExampleObject" objects
        list.add(new ExampleObject("name1", "location1"));
        list.add(new ExampleObject("name2", "location2"));
        list.add(new ExampleObject("name3", "location3"));


            FragmentManager fragmentManager = getFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            ExampleFragment fragment = new ExampleFragment(list);
            fragmentTransaction.add(R.id.linear_layout_scroll, fragment);
            fragmentTransaction.commit();

    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM