1

When I add a TextView to a LinearLayout, I'm generating NullPointerExceptions. I'm calling this...

public void loadPlayers() {
    LinearLayout lv = (LinearLayout) findViewById(R.id.player_list);
    TextView tv = new TextView(this);

    for (int i = 0; i < Game.getPlayers().length; i++) {
        tv.setText(String.valueOf(Game.getPlayers()[i]));
        tv.setPadding(8, 8, 8, 8);
        tv.setTextSize(20);
        tv.setBackgroundColor(0xD0D0D0);

        System.out.println("Got here!");

        lv.addView(tv);
    }
}

At the end of onCreate, and I'm getting "Got here!" printed on my console. The error is coming from

lv.addView(tv);

But I don't see why that is a problem. Is the layout not loaded yet? If so, how do I fix that? Below is the complete activity, xml, and logs.

MainActivity.java:

package com.example.lineupcreator;

import android.app.Activity;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.support.v4.widget.DrawerLayout;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;


public class MainActivity extends ActionBarActivity
        implements NavigationDrawerFragment.NavigationDrawerCallbacks {

    /* My Methods */

    /**
     * Adds a player, gets input from button
     * @return 
     */
    public void addPlayer(View view) {
        EditText editText = (EditText) findViewById(R.id.edit_message);
        String name = editText.getText().toString();

        LinearLayout lv = (LinearLayout) findViewById(R.id.player_list);
        TextView tv = new TextView(this);

        tv.setText(String.valueOf(name));
        tv.setPadding(8, 8, 8, 8);
        tv.setTextSize(20);
        tv.setBackgroundColor(0xD0D0D0);
        lv.addView(tv);// not InformationActivity.tv just write tv

        Game.newPlayer(name);
    }

    /**
     * Loads all of the players
     */
    public void loadPlayers() {
        LinearLayout lv = (LinearLayout) findViewById(R.id.player_list);
        TextView tv = new TextView(this);

        for (int i = 0; i < Game.getPlayers().length; i++) {
            tv.setText(String.valueOf(Game.getPlayers()[i]));
            tv.setPadding(8, 8, 8, 8);
            tv.setTextSize(20);
            tv.setBackgroundColor(0xD0D0D0);

            System.out.println("Got here!");

            lv.addView(tv);
        }
    }

    /* Prebuilt Methods */

    /**
     * Fragment managing the behaviors, interactions and presentation of the navigation drawer.
     */
    private NavigationDrawerFragment mNavigationDrawerFragment;

    /**
     * Used to store the last screen title. For use in {@link #restoreActionBar()}.
     */
    private CharSequence mTitle;

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

        mNavigationDrawerFragment = (NavigationDrawerFragment)
                getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
        mTitle = getTitle();

        // Set up the drawer.
        mNavigationDrawerFragment.setUp(
                R.id.navigation_drawer,
                (DrawerLayout) findViewById(R.id.drawer_layout));

        /* My Code */
        Game.init();
        this.loadPlayers();
    }

    @Override
    public void onNavigationDrawerItemSelected(int position) {
        // update the main content by replacing fragments
        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction()
                .replace(R.id.container, PlaceholderFragment.newInstance(position + 1))
                .commit();
    }

    public void onSectionAttached(int number) {
        switch (number) {
            case 1:
                mTitle = getString(R.string.title_section1);
                break;
            case 2:
                mTitle = getString(R.string.title_section2);
                break;
            case 3:
                mTitle = getString(R.string.title_section3);
                break;
        }
    }

    public void restoreActionBar() {
        ActionBar actionBar = getSupportActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
        actionBar.setDisplayShowTitleEnabled(true);
        actionBar.setTitle(mTitle);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        if (!mNavigationDrawerFragment.isDrawerOpen()) {
            // Only show items in the action bar relevant to this screen
            // if the drawer is not showing. Otherwise, let the drawer
            // decide what to show in the action bar.
            getMenuInflater().inflate(R.menu.main, menu);
            restoreActionBar();
            return true;
        }
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        return super.onOptionsItemSelected(item);
    }

    /**
     * A placeholder fragment containing a simple view.
     */
    public static class PlaceholderFragment extends Fragment {
        /**
         * The fragment argument representing the section number for this
         * fragment.
         */
        private static final String ARG_SECTION_NUMBER = "section_number";

        /**
         * Returns a new instance of this fragment for the given section
         * number.
         */
        public static PlaceholderFragment newInstance(int sectionNumber) {
            PlaceholderFragment fragment = new PlaceholderFragment();
            Bundle args = new Bundle();
            args.putInt(ARG_SECTION_NUMBER, sectionNumber);
            fragment.setArguments(args);
            return fragment;
        }

        public PlaceholderFragment() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_main, container, false);
            return rootView;
        }

        @Override
        public void onAttach(Activity activity) {
            super.onAttach(activity);
            ((MainActivity) activity).onSectionAttached(
                    getArguments().getInt(ARG_SECTION_NUMBER));
        }
    }

}

fragment_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.lineupcreator.MainActivity$PlaceholderFragment" >

    <EditText android:id="@+id/edit_message"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@+id/button"
        android:hint="@string/player_name" />

    <Button
        android:id="@+id/button"
        android:layout_width="64dp"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/edit_message"
        android:layout_alignParentRight="true"
        android:onClick="addPlayer"
        android:text="@string/add" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content" 
        android:layout_below="@+id/edit_message" >

        <LinearLayout
            android:id="@+id/player_list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/darker_gray"
            android:orientation="vertical" />

    </ScrollView>

</RelativeLayout>

Logs:

07-24 17:30:48.274: D/ActivityThread(22173): handleBindApplication:com.example.lineupcreator
07-24 17:30:48.274: D/ActivityThread(22173): setTargetHeapUtilization:0.75
07-24 17:30:48.274: D/ActivityThread(22173): setTargetHeapMinFree:2097152
07-24 17:30:48.548: I/System.out(22173): Got here!
07-24 17:30:48.548: D/AndroidRuntime(22173): Shutting down VM
07-24 17:30:48.548: W/dalvikvm(22173): threadid=1: thread exiting with uncaught exception (group=0x418f1ce0)
07-24 17:30:48.555: E/AndroidRuntime(22173): FATAL EXCEPTION: main
07-24 17:30:48.555: E/AndroidRuntime(22173): Process: com.example.lineupcreator, PID: 22173
07-24 17:30:48.555: E/AndroidRuntime(22173): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.lineupcreator/com.example.lineupcreator.MainActivity}: java.lang.NullPointerException
07-24 17:30:48.555: E/AndroidRuntime(22173):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2215)
07-24 17:30:48.555: E/AndroidRuntime(22173):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2265)
07-24 17:30:48.555: E/AndroidRuntime(22173):    at android.app.ActivityThread.access$800(ActivityThread.java:145)
07-24 17:30:48.555: E/AndroidRuntime(22173):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1206)
07-24 17:30:48.555: E/AndroidRuntime(22173):    at android.os.Handler.dispatchMessage(Handler.java:102)
07-24 17:30:48.555: E/AndroidRuntime(22173):    at android.os.Looper.loop(Looper.java:136)
07-24 17:30:48.555: E/AndroidRuntime(22173):    at android.app.ActivityThread.main(ActivityThread.java:5144)
07-24 17:30:48.555: E/AndroidRuntime(22173):    at java.lang.reflect.Method.invokeNative(Native Method)
07-24 17:30:48.555: E/AndroidRuntime(22173):    at java.lang.reflect.Method.invoke(Method.java:515)
07-24 17:30:48.555: E/AndroidRuntime(22173):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
07-24 17:30:48.555: E/AndroidRuntime(22173):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:611)
07-24 17:30:48.555: E/AndroidRuntime(22173):    at dalvik.system.NativeStart.main(Native Method)
07-24 17:30:48.555: E/AndroidRuntime(22173): Caused by: java.lang.NullPointerException
07-24 17:30:48.555: E/AndroidRuntime(22173):    at com.example.lineupcreator.MainActivity.loadPlayers(MainActivity.java:64)
07-24 17:30:48.555: E/AndroidRuntime(22173):    at com.example.lineupcreator.MainActivity.onCreate(MainActivity.java:96)
07-24 17:30:48.555: E/AndroidRuntime(22173):    at android.app.Activity.performCreate(Activity.java:5231)
07-24 17:30:48.555: E/AndroidRuntime(22173):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
07-24 17:30:48.555: E/AndroidRuntime(22173):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2169)
07-24 17:30:48.555: E/AndroidRuntime(22173):    ... 11 more
07-24 17:35:48.735: I/Process(22173): Sending signal. PID: 22173 SIG: 9

EDIT:

It seemed to me that quaternion was on the right path, but his solution didn't work. I also tried to creating an array of TextViews, as seen below, but that also didn't work.

public void loadPlayers() {
    LinearLayout lv = (LinearLayout) findViewById(R.id.player_list);
    TextView[] tv = new TextView[Game.getPlayers().length];

    for (int i = 0; i < Game.getPlayers().length; i++) {
        tv[i] = new TextView(this);
        tv[i].setText(String.valueOf(Game.getPlayers()[i]));
        tv[i].setPadding(8, 8, 8, 8);
        tv[i].setTextSize(20);
        tv[i].setBackgroundColor(0xD0D0D0);

        System.out.println("Got here!");

        lv.addView(tv[i]);
    }
}

Update:

I tried calling loadPlayers from addPlayer and not onCreate, and it works perfectly. The only problem is created when loadPlayers is called from onCreate

  • 2
    typical case of trying to access the views of a fragment from the activity. do your loadPlayer thing inside your fragment. (or simply don't use a fragment) – njzk2 Jul 25 '14 at 01:32
  • As stated, you're mixing `Activity` with `Fragment` (very understandable for new Android developer using the latest development kit). A simple explanation is that you're setting the layout inside a `Fragment` (note the name `fragment_main.xml`), but your logic is inside `Activity`. Both are not directly linked and cannot be referred as simple as that. For the starter, you may ignore using `Fragment` at all. In `onCreate()`, change to `setContentView(R.layout.fragment_main);` (or copy the content from `fragment_main.xml` to `activity_main.xml`) and try again. – Andrew T. Jul 25 '14 at 01:44
  • @andrewT. Moving the setContentView to the fragment_main still does not work. If it helps, the repo can be found at https://github.com/42mileslong/lineup-creator. – 42mileslong Jul 25 '14 at 01:47
  • @njzk2 I understand why that might be an issue, but I was doing practically the same thing with addPlayer. Is it because I was calling it from the fragment that it works there and not in loadPlayer? Is it because I'm calling it with this.loadPlayers that it does not work? – 42mileslong Jul 25 '14 at 01:49
  • Oh sorry, just realized that there is `DrawerLayout` inside `activity_main.xml`. The modification wouldn't be as simple as I wrote before then. In the meantime, I don't think `addPlayer()` will work too currently. I'll try to write an answer using `Fragment`. – Andrew T. Jul 25 '14 at 02:03
  • I tried removing the invocation of `loadPlayers()` from `onCreate()` and instead called it from `addPlayer()`, and it works. Could the problem be that the layout doesn't exist until after `onCreate()`? – 42mileslong Jul 25 '14 at 02:05
  • Ah, I think the reason why `addPlayer()` is working, because the `Button` which calls that method is defined inside the `Fragment`, but I just knew it can be implemented like that in `Activity`. – Andrew T. Jul 25 '14 at 03:05

3 Answers3

0

Ok, the Error is that you are trying inflate a layout component from the main activity, but your are inflating a Fragment, so, your main layout is not showing in your screen, is the fragment layout that is the top. You need move

<LinearLayout
            android:id="@+id/player_list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/darker_gray"
            android:orientation="vertical" />

to Fragment Layout.

If this donsn't work just tell me.

Chefes
  • 1,892
  • 18
  • 17
  • The XML file that was posted _is_ the fragment layout. Should I add the acitivity_main.xml? – 42mileslong Jul 25 '14 at 01:11
  • Just one question, if you are using fragments, why are you calling the function in the activity??, do you try call loadPlayers in the fragment onCreateView() function? – Chefes Jul 25 '14 at 01:15
  • I don't know. I'm kind of new to android development, and other methods that referenced the fragment worked in the MainActivity.java file. Would it help if I added a picture of my project's layout? I added the names of the files to the question. Does that help? – 42mileslong Jul 25 '14 at 01:22
  • Would it help if I linked the repo @user3586222 ? – 42mileslong Jul 25 '14 at 01:41
0

I don't think you can add the same view to a parent multiple times. You will need to move you instantiation of the new TextView into the for loop.

Your loadPlayers function should look like this:

public void loadPlayers() {
    LinearLayout lv = (LinearLayout) findViewById(R.id.player_list);

    for (int i = 0; i < Game.getPlayers().length; i++) {
        TextView tv = new TextView(this);
        tv.setText(String.valueOf(Game.getPlayers()[i]));
        tv.setPadding(8, 8, 8, 8);
        tv.setTextSize(20);
        tv.setBackgroundColor(0xD0D0D0);

        System.out.println("Got here!");

        lv.addView(tv);
    }
}

Hope this helps, if not you may have a bigger issue at hand =(

quaternion
  • 77
  • 2
  • 16
  • Nope. Doesn't work. Tried creating an array of TextViews, but I still get the same error. – 42mileslong Jul 25 '14 at 01:14
  • Another nope... tried only printing the first player, but I still get the null pointer exception. Could it be because my layout isn't loaded yet? – 42mileslong Jul 25 '14 at 01:40
0
Caused by: java.lang.NullPointerException
    at com.example.lineupcreator.MainActivity.loadPlayers(MainActivity.java:64)

The reason why you're getting NullPointerException is because you're trying to get a LinearLayout which is inflated in Fragment, from the Activity, specifically these lines:

public void loadPlayers() {
    LinearLayout lv = (LinearLayout) findViewById(R.id.player_list);
        // R.id.player_list is not inside activity_main.xml
        // lv is null

    ...

    lv.addView(tv[i]); // NullPointerException                 
    }
}

One way to solve this is to move all the logic inside the Fragment.

Add onActivityCreated(Bundle savedInstanceState) inside the PlaceholderFragment and move both lines from onCreate() to there. This is to ensure that the code will be called after the activity is already set-up.

@Override
public void onActivityCreated (Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    /* My Code */
    Game.init();
    this.loadPlayers();
}

Then move loadPlayers() inside the PlaceholderFragment. However, there is no findViewById() inside a Fragment. Instead, you have to initialize the views inside onCreateView(). Don't forget to declare the variables inside the Fragment.

LinearLayout lv;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_main, container, false);
    lv = (LinearLayout) rootView.findViewById(R.id.player_list);

    return rootView;
}

Lastly, Fragment use Context from its Activity. While you can use this in Activity to refer to its Context, in Fragment you cannot. Instead, use getActivity().

public void loadPlayers() {
    // LinearLayout lv = (LinearLayout) findViewById(R.id.player_list);
    TextView tv;

    for (int i = 0; i < Game.getPlayers().length; i++) {
        tv = new TextView(getActivity());
        tv.setText(String.valueOf(Game.getPlayers()[i].getName()));
        tv.setPadding(8, 8, 8, 8);
        tv.setTextSize(20);
        tv.setBackgroundColor(0xD0D0D0);

        lv.addView(tv);
    }
}
Andrew T.
  • 4,701
  • 8
  • 43
  • 62
  • I don't see the `PlaceholderFragment` file that you are talking about. Should I create a new one, and what should I put in it? – 42mileslong Jul 25 '14 at 02:30
  • No, the `PlaceholderFragment` is inside your `MainActivity` at the bottom. You just need to add `onActivityCreated(Bundle savedInstanceState)` and move `addPlayer()` and `loadPlayers()`. – Andrew T. Jul 25 '14 at 02:33
  • When I do this I get errors on the `findViewById` saying that I am referencing a non-static method from a static one. Should I change the PlaceholderFragment class to a non-static class? I also get errors on the `new TextView(this)` saying that `The constructor TextView(MainActivity.PlaceholderFragment) is undefined`. How do I fix that? Do you want me to push to the repository so it is easier to see? – 42mileslong Jul 25 '14 at 02:38
  • I think this should be the proper modifications. – Andrew T. Jul 25 '14 at 02:58
  • Whoa... you are amazing! One problem though - using addPlayer still crashes the program, because it's not in the main activity any more. Is there a way to reference it from the button, or should I just make a method that calls in in the main activity? – 42mileslong Jul 25 '14 at 04:30
  • Another small issue is that multiple copies of the player's name are printed. Is that because the fragment saves the names, while the activity does not? However, this is not an issue when addPlayer is still in the MainActivity – 42mileslong Jul 25 '14 at 04:35
  • Hmm... I think you can just move `addPlayer()` back to inside `MainActivity` if there is no problem. I never use `android:onClick`, so I don't know how to refer it from the fragment. Instead, I usually use `setOnClickListener()` when initializing the `Button` inside `onCreate()` (for activity) `onCreateView()` (for fragment). Edit: seems from [this question](http://stackoverflow.com/questions/21192386/android-fragment-onclick-button-method), you're right, move that back to the activity. – Andrew T. Jul 25 '14 at 04:37
  • 1
    Okay. Adding `addPlayer()` back to MainActivity actually works perfectly. Thanks so much! – 42mileslong Jul 25 '14 at 04:41