【问题标题】:Presenter object in MVP(Android) getting null object reference errorMVP(Android)中的演示者对象获取空对象引用错误
【发布时间】:2018-01-29 11:06:23
【问题描述】:

我正在使用 MVP。我的活动包含一个列表视图。我在我的 Activity 的 on Create 方法中初始化演示者,然后使用该演示者对象调用接口方法以获取数据并设置列表视图适配器。

我的问题是,当在任何 onClick 侦听器中使用 Presenter 对象时工作正常,但是当我直接使用它时,它会在 Presenter 对象上给出 NullPointerException。

这是我的代码 sn-p :

这是我的活动:-

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 inialization
}

@Override
public void initView() {
    try {
        listView = findViewById(R.id.listview);
        presenter.getEmployees(listView);     //--> interface method calling (Here I got exception.)

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                presenter.listViewClick(position);    //--> Same thing working perfectly here
            }
        });

    } 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 = new EmployeePresenter(this);
}

}

我们将提供帮助。提前谢谢你。

更新 这是我的错误日志 01-29 16:11:54.709 28540-28540/com.example.myfirstexamplemvp W/System.err: java.lang.NullPointerException: Attempt to invoke interface method 'void com.example.myfirstexamplemvp.contract.EmployeeContract$GetPresenter.getEmployees(android.widget.ListView)' on a null object reference 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.<init>(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) 01-29 16:11:54.709 28540-28540/com.example.myfirstexamplemvp W/System.err: at android.app.Activity.performCreate(Activity.java:6582) 01-29 16:11:54.709 28540-28540/com.example.myfirstexamplemvp W/System.err: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1113) 01-29 16:11:54.709 28540-28540/com.example.myfirstexamplemvp W/System.err: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2532) 01-29 16:11:54.709 28540-28540/com.example.myfirstexamplemvp W/System.err: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2667) 01-29 16:11:54.709 28540-28540/com.example.myfirstexamplemvp W/System.err: at android.app.ActivityThread.-wrap11(ActivityThread.java) 01-29 16:11:54.709 28540-28540/com.example.myfirstexamplemvp W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1494) 01-29 16:11:54.709 28540-28540/com.example.myfirstexamplemvp W/System.err: at android.os.Handler.dispatchMessage(Handler.java:111) 01-29 16:11:54.709 28540-28540/com.example.myfirstexamplemvp W/System.err: at android.os.Looper.loop(Looper.java:207) 01-29 16:11:54.710 28540-28540/com.example.myfirstexamplemvp W/System.err: at android.app.ActivityThread.main(ActivityThread.java:5776) 01-29 16:11:54.710 28540-28540/com.example.myfirstexamplemvp W/System.err: at java.lang.reflect.Method.invoke(Native Method) 01-29 16:11:54.710 28540-28540/com.example.myfirstexamplemvp W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789) 01-29 16:11:54.710 28540-28540/com.example.myfirstexamplemvp W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)

这是我的演示者:-

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();
}

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));
    }
}

}

【问题讨论】:

  • 能否请您发布错误日志?您是否知道您正在创建您的 Presenter 两次(在 onCreateonResume)?
  • 你在哪里调用 initView 方法?似乎在 onCreate() 之前调用了 initView()
  • @Heitor 我猜它是由演示者自己在初始化时调用的?也许可以解释为什么presenter 为空
  • @Eselfar 我猜你是对的。
  • 如果我是正确的,presenter 在构造函数被完全调用时被赋值。这意味着当您从构造函数调用initView 时,presenter 尚未分配,因为构造函数尚未完成是进程。这就是你获得 NPE 的原因

标签: java android callback mvp


【解决方案1】:

试试这个:

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);
}

@Override
public void initView(List<Employee> employees, Presenter.Callback callback) {
    listView = findViewById(R.id.listview);
    EmployeesAdapter adapter = new EmployeesAdapter(this, employees);
    listView.setAdapter(adapter);

    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            callback.onClick(position);
        }
    })
}

@Override
protected void onResume() {
    super.onResume();
    //presenter = new EmployeePresenter(this);
}

进入演示者

public EmployeePresenter(EmployeeView view) {

    List<Employee> employees = ...; // get the list of employees
    Callback callback = new Callback(){
        void onClick(int position){
            listViewClick(position);
        }
    }
    view.initView(employees, callback);
}


public interface Callback{
    void onClick(int position);
}

【讨论】:

  • 根据您更新的代码,某些类的名称有误,但这是一般的想法。我正在使用回调,因此视图不需要调用演示者来管理点击
  • 所以这个回调在 Presenter 的构造函数中。
  • 是在构造函数中实例化的,是的。 Callback 是一个接口。您可以将其命名为 PresenterClickListener 或任何您想要的名称。我已经在 Presenter 类中定义了它,但您可以在 EmployeeContract 或单独的 java 文件中声明它。
  • 好的,我试试这个。谢谢你的回复:)
  • 我本可以直接使用 OnClickListener 而不是创建新界面,但我不希望 Presenter 直接访问任何 View
【解决方案2】:

我认为您的代码违反了 MVP。您的 Presenter 不应包含任何 android 代码。这就是 MVP 的强大功能,便于测试。

1- 在 init() 方法中初始化您的 listView,包括设置适配器。

public void initView() {
listView = findViewById(R.id.listview);
adapter = new EmployeesAdapter(this, employeesList);
listView.setAdapter(adapter);

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        presenter.listItemWasClicked(position).
    }
})
}

2- 创建一个名为EmployeeData的接口。

public interface EmployeeData {
void add(Employee employee);
Employee getEmployee(int position);
int getSize();
}

3- 在您的适配器内部实现 EmployeeData

{

//.....adapter methods

@Overrride
public Employee getEmployee(int position){
return myEmployeeList.get(position);
   }
     //.. other methods.
}

4- 在您的演示者中

   private EmployeeData empData;
    public  EmployeePresenter  (View view,EmployeeData empData){
    this.empData=empData;
    //... other init
    }
 @Override
 public void listItemWasClicked(int position){
 Employee emp=empData.getEmployee(position)
  }

5-onCreate() 中的活动中,例如,初始化您的 Presenter。

employeePresenter=new EmployeePresenter(this,listAdapter);

注意:在创建演示者之前不要忘记致电initView()

【讨论】:

  • 我没有使用自定义适配器,我只是使用了 ArrayAdapter。感谢您的回复,但我已经解决了我的问题。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-18
  • 1970-01-01
  • 1970-01-01
  • 2017-01-26
  • 2023-03-04
  • 1970-01-01
相关资源
最近更新 更多