我正在尝试为Android Lollipop(5.0)构建一个应用程序。有一个登录片段,当我按登录按钮时,应用程序自动崩溃。我正在分享我的代码和错误消息,请指导我。

BaseActivity.java

public abstract class BaseActivity extends AppCompatActivity {
    protected CoreApplication coreApplication;
    @Override
    protected void onCreate(Bundle savedState) {
        super.onCreate(savedState);
        coreApplication = (CoreApplication) getApplication();
    }
}


BaseAuthenticatedActivity.java

public abstract class BaseAuthenticatedActivity extends BaseActivity {
    @Override
    protected final void onCreate(Bundle savedState) {
        super.onCreate(savedState);
        if (!coreApplication.getAuth().getUser().isLoggedIn()) {
            startActivity(new Intent(this, LoginActivity.class));
            finish();
            return;
        }
        onCoreApplicationCreate(savedState);
    }
    protected abstract void onCoreApplicationCreate(Bundle savedState);
}


LoginActivity.java

public class LoginActivity extends BaseActivity implements View.OnClickListener, LoginFragment.CallBacks {
    private static final int REQUEST_NARROW_LOGIN = 1;
    private View loginButton;
    @Override
    protected void onCreate(Bundle savedState) {
        super.onCreate(savedState);
        setContentView(R.layout.activity_login);
        loginButton = findViewById(R.id.LoginJustChat);
        if (loginButton != null) {
            loginButton.setOnClickListener(this);
        }
    }
    @Override
    public void onClick(View view) {
        if (view == loginButton)
            startActivityForResult(new Intent(this, LoginNarrowActivity.class), REQUEST_NARROW_LOGIN);
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode != RESULT_OK)
            return;
        if (requestCode == REQUEST_NARROW_LOGIN) {
            finishLogin();
        }
    }
    private void finishLogin() {
        startActivity(new Intent(this, MainActivity.class));
        finish();
    }
    @Override
    public void onLoggedIn() {
        finishLogin();
    }
}


LoginNarrowActivity.java

public class LoginNarrowActivity extends BaseActivity implements LoginFragment.CallBacks {
    @Override
    protected void onCreate(Bundle savedState){
        super.onCreate(savedState);
        setContentView(R.layout.activity_login_narrow);
    }
    @Override
    public void onLoggedIn() {
        setResult(RESULT_OK);
        finish();
    }
}


MainActivity.java

public class MainActivity extends BaseAuthenticatedActivity {
    @Override
    protected void onCoreApplicationCreate(Bundle savedState) {
    }
}


BaseFragment.java

public abstract class BaseFragment extends Fragment {
    protected CoreApplication application;
    @Override
    public void onCreate(Bundle savedInstance) {
        super.onCreate(savedInstance);
        application = (CoreApplication) getActivity().getApplication();
    }
}


LoginFragment.java

public class LoginFragment extends BaseFragment implements View.OnClickListener {

    private Button loginButton;
    private CallBacks callBacks;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup root, Bundle savedState) {
        View view = inflater.inflate(R.layout.fragment_login, root, false);
        loginButton = (Button) view.findViewById(R.id.fragment_login_loginButton);
        loginButton.setOnClickListener(this);
        return view;
    }
    @Override
    public void onClick(View view) {
        if (view == loginButton) {
            application.getAuth().getUser().setIsLoggedIn(true);
            callBacks.onLoggedIn();

        }
    }
    // because onAttach(Activity activity) is deprecated
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof CallBacks) {
            callBacks = (CallBacks) context;
        } else {
            throw new ClassCastException(context.toString()
                    + " must implement MyListFragment.OnItemSelectedListener");
        }
    }
    @Override
    public void onDetach() {
        super.onDetach();
        callBacks = null;
    }

    public interface CallBacks {
        void onLoggedIn();
    }
}


错误:


  java.lang.NullPointerException:尝试调用接口方法
  '无效
  com.example.usama.demoapp.fragments.LoginFragment $ CallBacks.onLoggedIn()'
  在空对象引用上


请用这个指导我。

最佳答案

欢迎使用Android!

您得到一个NullPointerException。这是非常普遍的[而且很可爱;因为它很容易调试] Java中的异常。检查您的LoginFragment。以下方法将引发此异常。

@Override
public void onClick(View view) {
    if (view == loginButton) {
        application.getAuth().getUser().setIsLoggedIn(true);
        callBacks.onLoggedIn();
    }
}


为了诊断此错误,有几点注意事项:


在声明类成员并对其进行初始化时(在本例中为callBacks),Java会自动将其初始化为null
null引用上调用任何方法都将导致NPE


好吧,让我们缩小到您的具体情况。您声明了一个名为callBacks的类成员,但从未对其进行初始化,而且,我看不到为其分配任何内容的方法。因此,该类成员始终保持为null,因此对其进行的任何后续方法调用都将导致我们进入NPE

作为解决方案,您应该在您的LoginFragment类中添加一个setter方法,在其中设置该callBacks。在另一面提供此对象,您首先在其中创建此片段的实例。

更新#1


  当我在onAttach方法中将Activity而不是Context作为参数传递时,它将起作用。但我想知道为什么会导致错误?


原因很简单。由于您的活动已经实现了该接口,因此将其作为上下文传递给您的LoginFragment会导致条件if (context instanceof CallBacks)变为true。但是,传递裸context不会导致建立该if语句。


  你能告诉我如何定义二传手吗?


非常简单!就像其他常规方法一样,声明这样的方法:

public void setOnLoginListener(Callbacks listener){
    this.callbacks = listener;
}


更新#2


  我需要定义setOnLoginListener方法的地方


LoginFragment类中。


  我应该在哪里称呼它


在您首先实例化LoginFragment类的主要活动中。


  有什么参数?


您的活动,该活动实现了该Java接口。

10-06 01:17