尝试在 Android 片段中查找按钮 ID 时抛出 NPE

NPE thrown when trying to Find Button ID in Android Fragment

无论我重做多少次,这个问题都反复出现。根据 Android 开发人员的说法,片段的视图层次结构中对象的 ID 是在 onCreateView 期间获得的,我在这里仔细研究的所有问题都证实了这一点。但是由于某种原因,在我进行设置的检查过程中它总是 returns null,因此我无法继续使用这些按钮。片段在该项目的 "decision events" 期间加载,每个事件都有不同的决定。因此,我只想使用一个片段并根据需要更改按钮文本。但是我似乎无法让他们不 return null。我只需要帮助找出导致 NPE 的我做错了什么。

DecisionFragment.java:

package com.saphiric.simproject.uimanipulation;

import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

import com.saphiric.simproject.R;
import com.saphiric.simproject.datacontrols.DataCore;

public class DecisionFragment extends Fragment {

    // Activity/Global variables
    private static final String TAG = "DecisionFragment";
    DataCore dataCore = DataCore.getInstance();

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

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.i(TAG, "Begin: Inflate");

        // Gets handles to important UI elements for scalability
        View root = inflater.inflate(R.layout.fragment_decision, container, false);
        Button buttonTrue = (Button) root.findViewById(R.id.btnChoiceOne);
        Button buttonFalse = (Button) root.findViewById(R.id.btnChoiceTwo);


        if(buttonTrue == null){
            System.out.println("buttonTrue is null");
        } else {
            System.out.println("buttonTrue is working fine");
        }

        Log.i(TAG, "Finished: Inflate");
        if (root == null){
            Log.e(TAG, "omg Inflate == null");
        }
        switch (dataCore.controller.getCurrentDecision()){
            case "OPSDecision":
//                buttonTrue.setText(R.string.ops_decision_one);
//                buttonFalse.setText(R.string.ops_decision_two);
                break;
            default:
                System.out.println("ERROR: No decision set");
        }
        return root;
    }

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

    }
}

fragment_decision.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="90dp"
    android:orientation="horizontal"
    android:weightSum="1.0"
    tools:context="com.saphiric.simproject.uimanipulation.DecisionFragment">

    <Button
        android:id="@+id/decisionOne"
        android:layout_width="0dp"
        android:layout_height="90dp"
        android:layout_weight=".5"
        android:text="@string/defaul_btn"
        android:onClick="cryingDecisionOne"/>

    <Button
        android:id="@+id/decisionTwo"
        android:layout_width="0dp"
        android:layout_height="90dp"
        android:layout_weight=".5"
        android:text="@string/defaul_btn"
        android:onClick="cryingDecisionTwo"/>
</LinearLayout>

DayOne.java:

package com.saphiric.simproject.activities;

import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.saphiric.simproject.R;
import com.saphiric.simproject.datacontrols.DataCore;
import com.saphiric.simproject.uimanipulation.ControlsFragment;
import com.saphiric.simproject.uimanipulation.DecisionFragment;


/**
 * Created by Saphiric on 11/12/14.
 */
public class DayOne extends Activity {

    /**
     * Necessary activity variables
     */
    ControlsFragment controlsFragment = new ControlsFragment();
    DecisionFragment decisionFragment = new DecisionFragment();
    DataCore dataCore = DataCore.getInstance();

    /**
     * Android activity methods
     *
     * @param savedInstanceState is the apps savedInstanceState
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_day_one);

        // Initializes the opening story text
        // Initializes the dayProgress variable in DataController
        String storyStart = getResources().getString(R.string.story_opening_one);
        dataCore.controller.setCurrentText(storyStart);
        dataCore.controller.setCurrentDecision("OPSDecision");

        // Handles for fragment management
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        // UI will add the ControlsFragment in it's starting state for that activity.
        fragmentTransaction.add(R.id.fragmentContainer, controlsFragment);
        fragmentTransaction.commit();
    }

    @Override
    public void onResume(){
        super.onResume();

    }

    public void cryingDecisionOne(View view) {

        dataCore.controller.setDayProgress(dataCore.controller.getDayProgress());

        // Sets cryingDecision Story Lock
        dataCore.locks.setCryingDecision(true);
        dataCore.controller.setCurrentDecision("HLSOne");

        // Removes the decision fragment and replaces it with the controls fragment
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        // Sets the text to be pulled to storyText
        String decision = getResources().getString(R.string.crying_decision_true);
        dataCore.controller.setCurrentText(decision);

        fragmentTransaction.replace(R.id.fragmentContainer, controlsFragment);
        fragmentTransaction.commit();
    }

    public void cryingDecisionTwo(View view) {

        dataCore.controller.setDayProgress(dataCore.controller.getDayProgress());

        // Sets cryingDecision choice
        dataCore.locks.setCryingDecision(false);
        dataCore.controller.setCurrentDecision("HWSOne");

        // Removes the decision fragment and replaces it with the controls fragment
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        // Updates the currentText for updating the story view
        String decision = getResources().getString(R.string.crying_decision_false);
        dataCore.controller.setCurrentText(decision);

        fragmentTransaction.replace(R.id.fragmentContainer, controlsFragment);
        fragmentTransaction.commit();
    }

    public void advanceGameFunction(View view) {

        String textUpdate;

        // Handles for fragment management
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        // Obtains handles to UI components
        TextView storyText = (TextView) findViewById(R.id.storyText);
        RelativeLayout gameStart = (RelativeLayout) findViewById(R.id.gameStart);
        ImageView charOne = (ImageView) findViewById(R.id.char_one);
        ImageView charTwo = (ImageView) findViewById(R.id.char_two);
        ImageView charThree = (ImageView) findViewById(R.id.char_three);
        ImageView charFour = (ImageView) findViewById(R.id.char_four);

        // Increments the data variable in DataController
        dataCore.controller.setDayProgress(dataCore.controller.getDayProgress());
        System.out.println(dataCore.controller.getDayProgress());

        // Switch case for handling day progression
        switch (dataCore.controller.getDayProgress()) {
            case 1:
                textUpdate = getResources().getString(R.string.story_opening_two);
                dataCore.controller.setCurrentText(textUpdate);
                storyText.setText(dataCore.controller.getCurrentText());
                break;
            case 2:
                fragmentTransaction.replace(R.id.fragmentContainer, decisionFragment);
                fragmentTransaction.commit();
                break;
            case 3:
                if (dataCore.locks.getCryingDecision()) {
                    storyText.setText(dataCore.controller.getCurrentText());

                } else {
                    storyText.setText(dataCore.controller.getCurrentText());
                }
                break;
            case 4:
                if (dataCore.locks.getCryingDecision()) {
                    textUpdate = getResources().getString(R.string.ops_d1_line1);
                    dataCore.controller.setCurrentText(textUpdate);
                    storyText.setText(dataCore.controller.getCurrentText());
                } else {
                    textUpdate = getResources().getString(R.string.ops_d2_line1);
                    dataCore.controller.setCurrentText(textUpdate);
                    storyText.setText(dataCore.controller.getCurrentText());
                }
                break;
            case 5: // Transition to hurt leg scene if Crying Decision is true, hallway scene if false
                if (dataCore.locks.getCryingDecision()){
                    gameStart.setBackgroundResource(R.drawable.bg_gym_front);
                    textUpdate = getResources().getString(R.string.hls_line1);
                    dataCore.controller.setCurrentText(textUpdate);
                    storyText.setText(dataCore.controller.getCurrentText());
                }else{
                    gameStart.setBackgroundResource(R.drawable.bg_hallway);
                    textUpdate = getResources().getString(R.string.hws_line1);
                    dataCore.controller.setCurrentText(textUpdate);
                    storyText.setText(dataCore.controller.getCurrentText());
                }
                break;
            case 6:
                if(dataCore.locks.getCryingDecision()){
                    textUpdate = getResources().getString(R.string.hls_line2);
                    dataCore.controller.setCurrentText(textUpdate);
                    storyText.setText(dataCore.controller.getCurrentText());
                }else{
                    textUpdate = getResources().getString(R.string.hws_line2);
                    dataCore.controller.setCurrentText(textUpdate);
                    storyText.setText(dataCore.controller.getCurrentText());
                }
                break;
            case 7:
                if(dataCore.locks.getCryingDecision()){
                    charOne.setVisibility(View.VISIBLE);
                    textUpdate = getResources().getString(R.string.hls_line3);
                    dataCore.controller.setCurrentText(textUpdate);
                    storyText.setText(dataCore.controller.getCurrentText());
                }else {

                }
                break;
            case 8:
                if(dataCore.locks.getCryingDecision()){
                    textUpdate = getResources().getString(R.string.hls_line4);
                    dataCore.controller.setCurrentText(textUpdate);
                    storyText.setText(dataCore.controller.getCurrentText());
                }else{

                }
                break;
            case 9:
                if(dataCore.locks.getCryingDecision()){

                }else{

                }
                break;
            default:
                System.out.println("Default case called");
        }
    }
}

您在代码中使用了错误的 ID!您布局中的按钮具有 ID decisionOnedecisionTwo 但在您的代码中您使用的是 btnChoiceOnebtnChoiceTwo.

要修复它,请替换为:

Button buttonTrue = (Button) root.findViewById(R.id.btnChoiceOne);
Button buttonFalse = (Button) root.findViewById(R.id.btnChoiceTwo);

在你的 DecisionFragment:

Button buttonTrue = (Button) root.findViewById(R.id.decisionOne);
Button buttonFalse = (Button) root.findViewById(R.id.decisionTwo);

代码中的按钮 ID 与 xml 布局中的不匹配。

在你的 xml 中,id 是 'decisionOne' 但代码正在寻找 'R.id.btnChoiceOne'