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

Android MVP模式下Presenter对象空指针异常排查求助

问题分析与解决方案

问题根源

从错误日志的调用链就能定位到问题核心:

01-29 16:11:54.709 28540-28540/com.example.myfirstexamplemvp W/System.err: at com.example.myfirstexamplemvp.view.EmployeeListActivity.initView(EmployeeListActivity.java:35)
01-29 16:11:54.709 28540-28540/com.example.myfirstexamplemvp W/System.err: at com.example.myfirstexamplemvp.presenter.EmployeePresenter.initPresenter(EmployeePresenter.java:40)
01-29 16:11:54.709 28540-28540/com.example.myfirstexamplemvp W/System.err: at com.example.myfirstexamplemvp.presenter.EmployeePresenter.(EmployeePresenter.java:34)
01-29 16:11:54.709 28540-28540/com.example.myfirstexamplemvp W/System.err: at com.example.myfirstexamplemvp.view.EmployeeListActivity.onCreate(EmployeeListActivity.java:28)

当你在EmployeeListActivity的onCreate里执行presenter = new EmployeePresenter(this)时,Presenter的构造函数会触发initPresenter(),进而调用view.initView()。这时候Activity中的presenter变量还没完成赋值(毕竟new EmployeePresenter(this)这个构造过程还在跑),所以在initView()里调用presenter.getEmployees(listView)时,presenter还是null,直接抛出空指针异常。

而onItemClick里调用正常,是因为到那个时候Presenter的构造已经完成,Activity的presenter变量已经被正确赋值了。

解决方案

我们需要调整初始化顺序,确保presenter变量完全赋值后,再调用initView()方法。

步骤1:修改Presenter代码

把view.initView()从Presenter的初始化流程中移除,让Activity来控制调用时机:

public class EmployeePresenter implements EmployeeContract.AddPresenter, EmployeeContract.GetPresenter, EmployeeContract.EditPresenter {
    private EmployeeContract.View view;
    AddEmployeeModel model;
    SqliteController controller;

    public EmployeePresenter(EmployeeContract.View view) {
        this.view = view;
        initPresenter();
        // 移除这里的view.initView()调用
    }

    private void initPresenter() {
        model = new AddEmployeeModel();
        controller = new SqliteController((Context) view);
        // 移除view.initView()
    }

    @Override
    public void getEmployees(final ListView listView) {
        List<AddEmployeeModel> list = controller.getEmployeeList();
        ArrayList<String> empname = new ArrayList<String>();
        if (list.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
                empname.add(list.get(i).getFirstName() + " " + list.get(i).getLastName());
            }
            listView.setAdapter(new ArrayAdapter<String>((Context) view, android.R.layout.simple_expandable_list_item_1, empname));
        }
    }
}

步骤2:调整Activity代码

在presenter赋值完成后,主动调用initView()方法,同时可以去掉onResume里重复创建Presenter的代码(除非你有特殊的复用需求):

public class EmployeeListActivity extends AppCompatActivity implements EmployeeContract.View {
    private static final String TAG = EmployeeListActivity.class.getSimpleName();
    private ListView listView;
    private EmployeeContract.GetPresenter presenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_employee_list);
        presenter = new EmployeePresenter(this); // Presenter初始化完成
        initView(); // 现在调用initView,presenter已经不为null了
    }

    @Override
    public void initView() {
        try {
            listView = findViewById(R.id.listview);
            presenter.getEmployees(listView); // 现在调用不会空指针
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    presenter.listViewClick(position);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
            String methodName = Thread.currentThread().getStackTrace()[2].getMethodName();
            ErrorLog.saveLog(getBaseContext(), TAG, methodName, e.getMessage(), String.valueOf(e.getCause()));
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        // 如果没有特殊需求,不需要重复创建Presenter,否则会覆盖之前的实例
        // presenter = new EmployeePresenter(this);
    }
}

额外建议

  • MVP架构中,Presenter的构造函数尽量只做简单初始化(比如绑定View、初始化Model),不要触发View的方法调用,避免这种初始化顺序导致的空指针。
  • 如果需要在页面可见时刷新数据,可以在onResume里调用presenter.getEmployees(listView),而不是重新创建Presenter实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:57:50