24

I'm having a problem with the findViewById on my first android app. I'm trying to call this function but always return null.

My app have 2 activities. In the second activity (activity_display_message) I have this code:

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

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new PlaceholderFragment())
                .commit();
    }

    //Obtener el mensaje desde el intent en MainActivity
    Intent intent = getIntent();
    String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);

    //Buscar el textview en la vista
    TextView textView = (TextView) findViewById(R.id.texto);
    textView.setText(message);
}

And this is the fragment_display_message.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"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.example.app.DisplayMessageActivity$PlaceholderFragment">

<TextView
    android:id="@+id/texto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

I don't know why it return NULL and generate a NullPointerException when I try to do a setText(). I'm calling the correct Id and declaring it on the XML too. And I'm calling the setContextView() on the onCreate().

Sorry if this question is too obvious (I think that I'm ignoring something obvious) but I'm new on android development.

EDIT: Logcat error:

02-10 10:25:58.960    1031-1031/com.example.app E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.app, PID: 1031
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.app/com.example.app.DisplayMessageActivity}: java.lang.NullPointerException
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2195)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
        at android.app.ActivityThread.access$800(ActivityThread.java:135)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5017)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
        at dalvik.system.NativeStart.main(Native Method)
 Caused by: java.lang.NullPointerException
        at com.example.app.DisplayMessageActivity.onCreate(DisplayMessageActivity.java:35)
        at android.app.Activity.performCreate(Activity.java:5231)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2159)

          

Edit:

Problem solved. Just need move the code from onCreate() to onCreateView() and edit the references.

onCreate() will be the default.

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

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new PlaceholderFragment())
                .commit();
    }
}

And the onCreateView() on PlaceholderFragment:

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

        //Obtener el mensaje desde el intent en MainActivity
        Intent intent = getActivity().getIntent();
        String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);

        //Buscar el textview en la vista
        TextView textView = (TextView) rootView.findViewById(R.id.texto);
        textView.setText(message);

        return rootView;
    }
Marian Paździoch
  • 8,813
  • 10
  • 58
  • 103
JRivera294
  • 309
  • 1
  • 2
  • 12

3 Answers3

24

Activity findViewById() searches the activity's view hierarchy set with setContentView() for the given view id. The view you appear to be looking for is in a fragment and not in the activity hierarchy (yet). Fragment transactions are not immediate either so even if you add it to the container in the activity hierarchy, it is not attached there right away but only when the transaction is processed.

In theory it's possible to synchronously execute pending fragment transactions with executePendingTransactions(). However, it's better to just move the code that touches a fragment's views in its onCreateView(). Fragments and their hosting activities are supposed to be relatively independent of each other, so an activity accessing a fragment's internals should be avoided.

laalto
  • 150,114
  • 66
  • 286
  • 303
  • it will no be never in the Activity's view hierarchy. It will belong to the Fragment's one. Also if the fragment will be attached to the Activity, findViewById returns null – Blackbelt Feb 10 '14 at 15:26
  • I was suspecting that, but how I can fix it? – JRivera294 Feb 10 '14 at 15:28
  • @blackbelt Visible fragments live in the activity view hierarchy. A fragment view hierarchy is really a subtree in the activity view tree. – laalto Feb 10 '14 at 15:36
  • so findViewById will not return null? – Blackbelt Feb 10 '14 at 15:36
  • @blackbelt Not after the fragment transaction has been executed. – laalto Feb 10 '14 at 15:39
  • Ok, I understand this. Now, how I can pur this code on the onCreateView method if this begin Override on the PlaceholderFragment class. I cant add this code on a static class. I cant ovverride it again on the DisplayMessageActivity, right? – JRivera294 Feb 10 '14 at 15:46
  • @user2959046 You can use `getActivity()` to access the hosting activity from a fragment. – laalto Feb 10 '14 at 15:49
  • Ok, after researching about the operation of the fragments and its lifecycle I understand why i need to move the code to the onCreateView. It work's perfectly, thank you @laalto for your help. I will edit the main question to help other people that have the same issue. – JRivera294 Feb 10 '14 at 16:28
  • Is it alright if the codes are put in `onStart()` instead? – null Aug 17 '14 at 18:33
3

you are looking for texto in the wrong place. The layout of your activity is activity_display_message but texto belongs to fragment_display_message.xml

Blackbelt
  • 156,034
  • 29
  • 297
  • 305
  • Im using android studio, when I create an activity using the IDE it create on layout 2 files, activity_display_message.xml and fragment_display_message.xml When I add objects to the fragment activity and call setContentView to activity_display_message I guess that It redirects to fragment_display_message – JRivera294 Feb 10 '14 at 15:22
0

I agree with Blackbelt. You're looking in the wrong place. In addition I'd suggest adding id to the layout using the "@+id/<name>", this way you'll know exactly where you are in the hierarchy.

JamesC
  • 356
  • 4
  • 8