You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Fragment添加TextWatcher报空指针异常解决方法

报错根因

你触发的空指针异常是Fragment开发的典型新手问题,核心问题点如下:

  • Fragment没有独立的findViewById()方法,你代码里声明的所有控件(licznik、mianownik、kreska等)从未完成初始化赋值,默认值都是null,直接调用null对象的addTextChangedListener方法必然抛出空指针。
  • 代码执行顺序错误:你在onCreateView里还没加载布局、绑定控件,就提前给控件设置监听器。
  • 原有skracamy()方法还存在两个隐藏崩溃点:一是把EditText控件本身强转为CharSequence做判空,逻辑完全错误;二是调用setText()时直接传入int类型数值,系统会把int值当作字符串资源ID查找,找不到资源同样会崩溃;没有判断分母为0的场景,会触发算术异常。
Fragment下控件绑定正确写法

Fragment中查找控件不能直接调用Activity的方法,需要先把布局文件inflate为View对象,再通过这个View对象的findViewById()方法绑定控件,所有控件绑定完成后再设置监听器、执行业务逻辑。

修复后的完整可运行代码如下:

package com.example.tabbedapp;

import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

public class Fragment1 extends Fragment {

    protected TextView ulamekLabel;
    protected EditText licznik;
    protected EditText mianownik;
    protected TextView kUlamkowa;
    protected TextView calosci;
    protected TextView nLicznik;
    protected TextView nMianownik;
    protected TextView kreska;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        // 第一步:先加载布局,得到布局的根View对象
        View rootView = inflater.inflate(R.layout.fragment1_layout, container, false);
        
        // 第二步:通过根View的findViewById绑定所有控件,这就是Fragment中等价于Activity findViewById的逻辑
        ulamekLabel = rootView.findViewById(R.id.ulamekLabel);
        licznik = rootView.findViewById(R.id.licznik);
        mianownik = rootView.findViewById(R.id.mianownik);
        kUlamkowa = rootView.findViewById(R.id.kUlamkowa);
        calosci = rootView.findViewById(R.id.calosci);
        nLicznik = rootView.findViewById(R.id.nLicznik);
        nMianownik = rootView.findViewById(R.id.nMianownik);
        kreska = rootView.findViewById(R.id.kreska);

        // 第三步:控件全部绑定完成后,再设置监听器
        licznik.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

            @Override
            public void afterTextChanged(Editable editable) {
                skracamy();
            }
        });

        mianownik.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

            @Override
            public void afterTextChanged(Editable editable) {
                skracamy();
            }
        });

        // 最后返回加载好的根View
        return rootView;
    }

    private void skracamy() {
        // 修正判空逻辑:判断输入框的文本内容,不是把控件本身强转
        if (TextUtils.isEmpty(licznik.getText()) || TextUtils.isEmpty(mianownik.getText())) {
            calosci.setText("0");
            calosci.setVisibility(View.INVISIBLE);
            nLicznik.setText("0");
            nLicznik.setVisibility(View.INVISIBLE);
            nMianownik.setText("0");
            nMianownik.setVisibility(View.INVISIBLE);
            kreska.setVisibility(View.INVISIBLE);
            return;
        }

        int a = Integer.parseInt(licznik.getText().toString());
        int b = Integer.parseInt(mianownik.getText().toString());

        // 新增分母为0判断,避免算术异常
        if (b == 0) {
            calosci.setVisibility(View.INVISIBLE);
            nLicznik.setText("分母不能为0");
            nLicznik.setVisibility(View.VISIBLE);
            nMianownik.setVisibility(View.INVISIBLE);
            kreska.setVisibility(View.INVISIBLE);
            return;
        }

        int nwd = NWD(a, b);
        int l = a / nwd;
        int m = b / nwd;

        int c = l / m;
        int d = l % m;

        calosci.setVisibility(View.VISIBLE);
        nLicznik.setVisibility(View.VISIBLE);
        nMianownik.setVisibility(View.VISIBLE);
        kreska.setVisibility(View.VISIBLE);

        if (c != 0 && d != 0) {
            // 修正setText传int的问题:int转String再设置,否则会被当成资源ID查找
            calosci.setText(String.valueOf(c));
            nLicznik.setText(String.valueOf(d));
            nMianownik.setText(String.valueOf(m));
        } else if (d != 0) {
            calosci.setText("");
            nLicznik.setText(String.valueOf(d));
            nMianownik.setText(String.valueOf(m));
        } else {
            calosci.setText(String.valueOf(c));
            nLicznik.setText("0");
            nMianownik.setText("0");
        }
    }

    int NWD(int a, int b) {
        if(b!=0)
            return NWD(b,a%b);
        return a;
    }
}
关键注意点
  • Fragment的控件绑定必须依托inflate得到的View对象调用findViewById(),不能直接调用,也不要在onCreateView返回根View之前操作控件。
  • 给TextView/EditText设置文本时,如果传入的是int类型,一定要手动转成String,否则系统会将int值解析为res/values/strings.xml里的资源ID,找不到对应资源就会崩溃。
  • 涉及除法计算的逻辑,一定要提前判断除数是否为0,避免运行时算术异常。

内容的提问来源于stack exchange,提问作者Greg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 10:01:08