DevWithSigns
DevWithSigns

Reputation: 725

cannot execute android activity

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

Answers (4)

frogatto
frogatto

Reputation: 29285

Welcome to Android !

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

DevWithSigns
DevWithSigns

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

Razvan Alin Balan
Razvan Alin Balan

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

Destiny
Destiny

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

Related Questions