I have two fragments FGames and FGamesDetail. which display the list of Games and when clicked should populate the FGamesDetail fragment. I am using MVP pattern.
I am trying to implement MultiPane layout for tablet to have list and detail view next to each other.
I am getting a null pointer exception at 'mListener.onGameSelected(gameEntity);' in FGames. I know I have not initialised it at this place but should I be initialising it every method I go through in MVP pattern.
GamesAdapter - RecyclerView Adapter.
@OnClick(R.id.row_container)
void rowClick(){
GamesPresenter gamesPresenter = new GamesPresenterImpl();
gamesPresenter.showGameDetail(data.get(getLayoutPosition()));
Toast.makeText(context, "itemClicked " + data.get(getLayoutPosition()), Toast.LENGTH_SHORT).show();
}
GamesPresenter - Interface
public interface GamesPresenter {
void initUi();
void showGameDetail(GameEntity gameEntity);
}
GamesPresenterImpl -
public class GamesPresenterImpl implements GamesPresenter {
GamesView gamesView;
private ApiInterface apiInterface;
/**
* Collects all subscriptions to unsubscribe later
*/
@NonNull
private CompositeDisposable mCompositeDisposable = new CompositeDisposable();
public GamesPresenterImpl() {}
public GamesPresenterImpl(GamesView gamesView) {
this.gamesView = gamesView;
}
@Override
public void initUi() {
getGamesData();
}
@Override
public void showGameDetail(GameEntity gameEntity) {
//gamesView was null so initialised here
GamesView gamesView = new FGames();
gamesView.onListItemClick(gameEntity);
}
}
GamesView - interface
public interface GamesView {
/**
* Initialise the recycler view to list Games data
* @param gameEntities
*/
void initRecyclerView(List<GameEntity> gameEntities);
void showToast(String message);
void onListItemClick(GameEntity gameEntity);
}
#
FGames - has all the implementation for the Fragment
public class FGames extends Fragment implements GamesView {
@BindView(R.id.rv_games)
RecyclerView rvGames;
private GamesAdapter gamesAdapter;
private GamesPresenterImpl presenter;
OnGameSelectedListener mListener;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.games_layout, container, false);
ButterKnife.bind(this, view);
presenter = new GamesPresenterImpl(this);
return view;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mListener = (OnGameSelectedListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement OnArticleSelectedListener");
}
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
presenter.initUi();
}
@Override
public void initRecyclerView(List<GameEntity> gameEntities) {
gamesAdapter = new GamesAdapter(getActivity(), gameEntities);
rvGames.setAdapter(gamesAdapter);
rvGames.setLayoutManager(new LinearLayoutManager(getActivity()));
}
@Override
public void showToast(String message) {
Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show();
}
@Override
public void onListItemClick(GameEntity gameEntity) {
//Here is where the NUll pointer exception is
mListener.onGameSelected(gameEntity);
}
public interface OnGameSelectedListener{
public void onGameSelected(GameEntity gameEntity);
}
}
MainActivity - which displays the performs the game selected operation to update the UI if detail fragment is available. I followed Android documentation to do this.
public class MainActivity extends AppCompatActivity implements FGames.OnGameSelectedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//FGames fGames = new FGames();
//getSupportFragmentManager().beginTransaction().add(R.id.games_container, fGames).commit();
}
@Override
public void onGameSelected(GameEntity gameEntity) {
FGameDetail gameDetailFrag = (FGameDetail) getSupportFragmentManager()
.findFragmentById(R.id.fragment_fGameDetail);
if (gameDetailFrag == null) {
// DisplayFragment (Fragment B) is not in the layout (handset layout),
} else {
// DisplayFragment (Fragment B) is in the layout (tablet layout),
// so tell the fragment to update
gameDetailFrag.updateContent(gameEntity);
}
}
}
ErrorLog
Process: com.example.rao.igttest, PID: 21481
java.lang.NullPointerException: Attempt to invoke interface method 'void com.example.rao.igttest.Games.View.FGames$OnGameSelectedListener.onGameSelected(com.example.rao.igttest.Games.Entity.GameEntity)' on a null object reference
at com.example.rao.igttest.Games.View.FGames.onListItemClick(FGames.java:73)
at com.example.rao.igttest.Games.Presenter.GamesPresenterImpl.showGameDetail(GamesPresenterImpl.java:53)
at com.example.rao.igttest.Games.View.GamesAdapter$GamesViewHolder.rowClick(GamesAdapter.java:72)
at com.example.rao.igttest.Games.View.GamesAdapter$GamesViewHolder_ViewBinding$1.doClick(GamesAdapter$GamesViewHolder_ViewBinding.java:33)
at butterknife.internal.DebouncingOnClickListener.onClick(DebouncingOnClickListener.java:22)
at android.view.View.performClick(View.java:5637)
at android.view.View$PerformClick.run(View.java:22429)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)