Reputation: 725
I'm trying to build an App for Android Lollipop (5.0). There is a login fragment and when i press login button then app automatically crashes. I'm sharing my code and error message please guide me.
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();
}
}
Error:
java.lang.NullPointerException: Attempt to invoke interface method 'void com.example.usama.demoapp.fragments.LoginFragment$CallBacks.onLoggedIn()' on a null object reference
Please guide me with this.
Upvotes: 1
Views: 155
Reputation: 29285
You got a NullPointerException
. It's a very common [and lovely; since it's rather easy to debug] exception in Java. Check your LoginFragment
. The following method will cause this exception to raise.
@Override
public void onClick(View view) {
if (view == loginButton) {
application.getAuth().getUser().setIsLoggedIn(true);
callBacks.onLoggedIn();
}
}
A couple of notes in order to diagnose this error:
When you declare a class member with initializing it, in this casecallBacks
, Java automatically initialize it to null
.
Invoking any method on a null
reference will result in NPE
.
Okay, let's narrow down to your specific case. You declared a class member called callBacks
but never initialized it, as well as, I can see no methods that assign something to it. Therefore, that class member always remains null
and thereby any subsequent method invocation on it leads us to NPE
.
As a solution, you should add a setter method to your LoginFragment
class in which you set that callBacks
. In other side supply this object where you first create an instance of this fragment.
Update #1
when i pass Activity instead of Context as parameter in onAttach method it works. but i want to know why it is causing the error?
The why is simple. Since your activity already implemented that interface, so passing it to your LoginFragment
as context will result in the condition if (context instanceof CallBacks)
becoming true. However, passing bare context
won't result in establishment of that if
statement.
can u please tell me how i can define setter?
It's pretty simple! Just as other regular method, declare a method like this:
public void setOnLoginListener(Callbacks listener){
this.callbacks = listener;
}
Update #2
where i need to define setOnLoginListener method
Inside the LoginFragment
class.
and where should i call it
In your main activity where you first instantiate LoginFragment
class.
with what parameters?
Your activity, which implements that Java interface.
Upvotes: 1
Reputation: 725
Actually the error was here in onAttach(Context context) when i pass Activity like this onAttach(Activity activity) then it worked. But i want to know why it is causing the error? and onAttach(Activity activity) is deprecated in android 5.0
Upvotes: 0
Reputation: 96
You can try writing a public setter for the callBacks object in LoginFragment and setting it from the activity instead, like this, supposing you defined your fragment in the activity's layout file:
public class LoginNarrowActivity extends BaseActivity implements LoginFragment.CallBacks {
@Override
protected void onCreate(Bundle savedState){
super.onCreate(savedState);
setContentView(R.layout.activity_login_narrow);
LoginFragment loginFragment = (LoginFragment)getSupportFragmentManager().findFragmentById(R.id.your_fragment_id);
loginFragment.setCallBacks(this);
}
Upvotes: 0
Reputation: 1
You can avoid setting onClickListener for the button by having adding android:onClink="login" in your xml file and a function that looks like this in your java file:
public void login(View view) {
application.getAuth().getUser().setIsLoggedIn(true);
callBacks.onLoggedIn();
}
Upvotes: 0