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)
Related
This is a very strange behavior and I don't know how to fix it.
I have an Activity as a Presenter (In a MVP Architecture).
When the activity starts, I attach a Fragment as a View. The fragment itself is very simple.
public class CurrentSaleFragment extends BaseFragment {
private MainMVP.SalesPresenterOps salesPresenterOps;
private SaleAdapter adapter;
private ListView lv;
#BindView(R.id.btn_sell)
FloatingActionButton btnAdd;
public static CurrentSaleFragment newInstance(){
CurrentSaleFragment fragment = new CurrentSaleFragment();
Bundle arguments = new Bundle();
arguments.putInt(LAYOUT_RES_ID, R.layout.fragment_quick_sale );
fragment.setArguments(arguments);
return fragment;
}
#Override
protected void init() {
super.init();
lv = (ListView)view.findViewById(R.id.lv_sale);
}
#OnClick(R.id.btn_sell)
public void addToSale(View view){
mPresenter.moveToFragment(SellProductFragment.newInstance());
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
salesPresenterOps = (MainMVP.SalesPresenterOps)context;
}
#Override
public void onDetach() {
salesPresenterOps = null;
super.onDetach();
}
}
The BaseFragment from which this fragmend extends :
public class BaseFragment extends Fragment implements MainMVP.RequiredViewOps, View.OnClickListener,
LoaderRequiredOps{
protected View view;
protected MainMVP.PresenterOps mPresenter;
protected final static String LAYOUT_RES_ID = "layout_res_id";
#Override
public void showOperationResult(String message, final long rowId) {
Snackbar.make(view, message, Snackbar.LENGTH_LONG).setAction(
R.string.see, new View.OnClickListener() {
#Override
public void onClick(View v) {
onOperationResultClick(rowId);
}
}
).show();
}
#Override
public void showSnackBar(String msg) {
Snackbar.make(view, msg, Snackbar.LENGTH_SHORT).show();
}
#Override
public void showAlert(String msg) {}
protected void onOperationResultClick(long rowId){}
#Override
public void onAttach(Context context) {
super.onAttach(context);
mPresenter = (MainMVP.PresenterOps)context;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
this.view = inflater.inflate(getArguments().getInt(LAYOUT_RES_ID), null);
init();
return view;
}
protected void addToClickListener(View ... params){
for (View v : params){
v.setOnClickListener(this);
}
}
protected void init() {
if (view != null){
ButterKnife.bind(this, view);
}
}
#Override
public void onDetach() {
mPresenter = null;
Log.d(getClass().getSimpleName(), "Fragment was detached");
super.onDetach();
}
#Override
public void onClick(View v) {}
#Override
public void onPreLoad() {
Dialogs.buildLoadingDialog(getContext(), "Loading...").show();
}
#Override
public void onLoad() {}
#Override
public void onDoneLoading() {
Dialogs.dismiss();
}
}
When I enter the method 'moveToFragment()' I just replace CurrentSaleFragment for a new Fragment:
protected void addFragment(BaseFragment fragment){
mView = fragment;
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_holder,
fragment, null).addToBackStack(null).commit();
}
Then the new fragment is attached:
public class SellProductFragment extends BaseFragment{
private ListView listView;
private ProductListAdapter adapter;
private MainMVP.SalesPresenterOps mSalesPresenter;
public static SellProductFragment newInstance(){
SellProductFragment fragment = new SellProductFragment();
Bundle arguments = new Bundle();
arguments.putInt(LAYOUT_RES_ID, R.layout.fragment_inventory);
fragment.setArguments(arguments);
return fragment;
}
private void reload(){
final Loader loader = new Loader(this);
loader.execute();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
mSalesPresenter = (MainMVP.SalesPresenterOps)context;
}
#Override
protected void init() {
super.init();
listView = (ListView)view.findViewById(R.id.lv_inventory);
reload();
FloatingActionButton button = (FloatingActionButton)view.findViewById(R.id.btn_add);
addToClickListener(button);
}
#Override
public void onLoad() {
adapter = new ProductListAdapter(getActivity().getApplicationContext(), R.layout.row_product_item,
mSalesPresenter.getProducts());
try{
updateListView();
}catch (Exception e){
Log.w(getClass().getSimpleName(), e.getMessage());
}
}
private void updateListView(){
if (adapter != null && listView != null){
listView.setAdapter(adapter);
}else{
throw new RuntimeException();
}
}
}
See that This fragment also extends from BaseFragment and implements LoaderRequiredOps. The interface is used to 'load' any data. It adds a dialog and updated the adapter when the loading is done:
public class Loader extends AsyncTask<Void, Void, Void> {
private LoaderRequiredOps presenter;
public Loader(LoaderRequiredOps presenter){
this.presenter = presenter;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
presenter.onPreLoad();
}
#Override
protected Void doInBackground(Void... params) {
presenter.onLoad();
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
presenter.onDoneLoading();
presenter = null;
}
}
Now, when I try to execute the method reload() from the SellProductFragment i get the 'Only the original thread that created a view hierarchy can touch its views.'
This does not happen if the SellProductFragment is attached first instead of CurrentSaleFragment.
What is happening here?
Your Async Loader class calls the presenters method onLoad() from a background thread during doInBackground().
My guess is that in the onLoad() method of the presenter, a view is referenced.
In order to change the view at this point, post the view logic as a Runnable to the UI thread (you said your presenter is the activity, so this should be possible from the onLoad method).
#Override
public void onLoad() {
runOnUiThread(new Runnable() {
#Override
public void run() {
// Your ui code here...
}
});
// Rest of your code here...
}
For an unknown reason, an unidentified configuration allows to execute the setting of an adapter for a ListView on the doInBackground() method.
Moved it to onPostExecute() and now it's working
I considered this documentation and several SO questions or different tutorials for fragment to activity communication. I'm building a simple chat for my App. When I click a chat room in my InboxFragment I want to pass the name of the chat room to my ChatActivity and add the name of the chat room to the ListView inside the ChatActivity.
The Problem is that I always get the error message that the ChatActivity doesn't implement the interface OnChatRommSelected.
The error message is:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.lyl.nairad, PID: 3018
java.lang.ClassCastException: com.lyl.nairad.Activities.MainAppActivity#2600f9ae must implement OnChatRoomSelected
at com.lyl.nairad.Fragments.InboxFragment.onStart(InboxFragment.java:137)
My InboxFragment looks like this:
EDIT: In the InboxFragment are some more variables, etc. but I let them away to keep the code as short as possible.
public class InboxFragment extends Fragment {
// [BEGIN: Communication instances
OnChatRoomSelected mCallback;
// END]
private final String TAG = "InboxFragment";
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_inbox, container, false);
callingActivity = getActivity();
// Some Code...
chats.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
sendChatRoomName(String.valueOf(chats.getItemAtPosition(position)));
Intent i = new Intent(getActivity(), ChatActivity.class);
startActivity(i);
}
});
return view;
}
public void refresh(){
((TextView)getActivity().findViewById(R.id.toolbar_title)).setText("Chats");
}
#Override
public void onResume() {
super.onResume();
refresh();
}
// [BEGIN: Interface for Fragment to Activity Communication
public interface OnChatRoomSelected {
public void selectedChatRoom(String chatRoomName);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
}
#Override
public void onStart() {
super.onStart();
try {
mCallback = (OnChatRoomSelected) getActivity();
} catch (ClassCastException e) {
throw new ClassCastException(getActivity().toString()
+ " must implement OnChatRoomSelected");
}
}
public void sendChatRoomName(String chatRoomName) {
mCallback.selectedChatRoom(chatRoomName);
}
// END}
}
My ChatActivity looks like this:
public class ChatActivity extends Activity implements InboxFragment.OnChatRoomSelected {
Button send;
EditText msgField;
ListView newsExtending;
ArrayList<String> messages;
ArrayAdapter<String> adapter;
private final String TAG = "ChatActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
messages = new ArrayList<>();
send = (Button) findViewById(R.id.sendMsgBtn);
msgField = (EditText) findViewById(R.id.aMessage);
newsExtending = (ListView) findViewById(R.id.privateMessagesList);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, messages);
newsExtending.setAdapter(adapter);
send.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String text = msgField.getText().toString();
messages.add(text);
adapter.notifyDataSetChanged();
msgField.setText("");
}
});
}
#Override
public void selectedChatRoom(String chatRoomName) {
messages.add(chatRoomName);
adapter.notifyDataSetChanged();
}
}
When I comment out
#Override
public void onStart() {
super.onStart();
/* try {
mCallback = (OnChatRoomSelected) getActivity();
} catch (ClassCastException e) {
throw new ClassCastException(getActivity().toString()
+ " must implement OnChatRoomSelected");
}*/
}
in the InboxFragment, my error looks like this:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.lyl.nairad, PID: 3334
java.lang.NullPointerException: Attempt to invoke interface method 'void com.lyl.nairad.Fragments.InboxFragment$OnChatRoomSelected.selectedChatRoom(java.lang.String)' on a null object reference
at com.lyl.nairad.Fragments.InboxFragment.sendChatRoomName(InboxFragment.java:143)
at com.lyl.nairad.Fragments.InboxFragment$2.onItemClick(InboxFragment.java:102)
Use methods onAttach(Context context) for register your callback
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mCallback = (ChatActivity) context;
} catch (ClassCastException e) {
Log.e("Custom TAG", "ClassCastException", e);
}
}
and onDetach to unregister callback
#Override
public void onDetach() {
mCallback = null;
super.onDetach();
}
You should get interface method through activity context and do it inside onAttach() callback like this
#override
public void onAttach(Context context){
super.onAttach(context);
try {
mCallback = (OnChatRoomSelected) context;
} catch (ClassCastException e) {
throw new ClassCastException(getActivity().toString()
+ " must implement OnChatRoomSelected");
}
}
I am trying to send data from activity to fragment and vice versa using interfaces but getting an error of cycling inheritance involving MyFragment.
Implementing interface created in MyFragment:
public class MyActivity implements OnSendFromMyFragListener {
OnSendFromMyActivityListener mCallback;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCallback.sendFromMyActivity(2);
}
#Override
public void sendFromMyFrag (int a) {
//do something
}
public interface OnSendFromMyActivityListener {
public void sendFromMyActivity(int b);
}
}
Implementing interface created in MyActivity:
public class MyFragment extends Fragment implements OnSendFromMyActivityListener {
OnSendFromMyFragListener mCallback;
public interface OnSendFromMyFragListener {
void sendFromMyFrag(int a);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mCallback = (OnSendFromMyFragListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString());
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_my, container, false);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCallback.sendFromMyFrag(1);
}
}
});
return view;
}
#Override
public void sendFromMyActivity(int b) {
//do something
}
}
Well the reason you are getting this error is because your Activity depends on your Fragment and Fragment depends on your Activity. Don't Agree?
Let me show you. Imagine you are a compiler in your work you stumbled across:
class A implements B.A {
interface B {
void foo1();
}
#Override
public void foo2()
{
// do something;
}
}
Now you know that class A depends on (implements) B.A, so before you go further into class A you move on to class B:
class B implements A.B {
interface A {
void foo2();
}
#Override
public void foo1()
{
// Do Something;
}
}
Now you see that class B depends on (implements) class A specifically class A.B! What do you (compiler) do? Go back to class A? But that depends on class B. So you see this becomes an unending cycle thus causing a cyclic dependency where both your class' definitions depend on each other.
As an alternative you could either create a member event listener or an anonymous one. Or if you don't like either of those options, you could also create a separate java interface class file for any one of the two interfaces.
Maybe you have to do this for Activity
public class MyActivity extends AppCompatActivity implements MyFragment.OnSendFromMyFragListener {
public interface OnSendFromMyActivityListener {
void sendFromMyActivity(int b);
}
OnSendFromMyActivityListener mCallback;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyFragment myFragment = MyFragment.newInstance();
//Do the transaction.....
//And after this
mCallback.sendFromMyActivity(0);
}
public void setOnSendFromMyActivityListener(OnSendFromMyActivityListener mCallback){
this.mCallback = mCallback;
}
#Override
public void sendFromMyFrag(int a) {
//do something
}}
And this for Fragment
public class MyFragment extends Fragment implements OnSendFromMyActivityListener {
OnSendFromMyFragListener mCallback;
public interface OnSendFromMyFragListener {
void sendFromMyFrag(int a);
}
public static MyFragment newInstance() {
Bundle args = new Bundle();
MyFragment fragment = new MyFragment();
fragment.setArguments(args);
return fragment;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mCallback = (OnSendFromMyFragListener) getActivity();
((MyActivity) getActivity()).setOnSendFromMyActivityListener(this);
} catch (ClassCastException e) {
throw new ClassCastException(context.toString());
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_place_suggest, container, false);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCallback.sendFromMyFrag(1);
}
});
return view;
}
#Override
public void sendFromMyActivity(int b) {
//do something
}
if you want you can put setters of the interface also to the Fragment for better abstraction.
Something you have to watch out is to look for nulls interfaces
Thanks
I'm making an Reddit app for my android exam and I have a question about inheritence.
I have a Fragment who has a RecyclerView. That recyclerview contains a list of redditposts. My app consists of multiple subreddits (funny, gaming, news, etc..). Every subreddit has his own Fragment. I have some methods that every Fragment has to have. (a showProgressBar, hideProgressBar, populateResult, etc...) I think it would be simple if i just make an Fragment class where all the subreddit Fragments can inheritance from. I could put all the methods in that fragment class because the methods are the same for every subreddit fragment. But my lecturer said that is a bad use of inheritance. So does anybody have a best practice around this problem?
This is the fragment i'm talking about:
package com.example.thomas.redditapp;
public class FunnyFragment extends Fragment {
private OnListFragmentInteractionListener mListener;
#Bind(R.id.funny_recyclerview)
RecyclerView mRecyclerView;
#Bind(R.id.progressBarFetch)
ProgressBar progress;
private RedditHelper helper;
private RedditPostRecyclerViewAdapter mAdapter;
List<RedditPost> redditPosts;
public FunnyFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
helper = null;
helper = new RedditHelper(SubRedditEnum.funny, this);
redditPosts = new ArrayList<>();
startLoad();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_funny_list, container, false);
ButterKnife.bind(this, view);
showProgressBar();
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mAdapter = new RedditPostRecyclerViewAdapter(redditPosts, mListener, mRecyclerView);
mAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
#Override
public void onLoadMore() {
redditPosts.add(null);
helper.loadListFromUrl();
}
});
mRecyclerView.setAdapter(mAdapter);
return view;
}
protected void startLoad() {
if (helper != null) {
helper.loadListFromDb();
}
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
if (isTaskRunning()) {
showProgressBar();
} else {
hideProgressBar();
}
super.onActivityCreated(savedInstanceState);
}
public void hideProgressBar() {
progress.setVisibility(View.GONE);
}
public void showProgressBar() {
progress.setVisibility(View.VISIBLE);
progress.setIndeterminate(true);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnListFragmentInteractionListener) {
mListener = (OnListFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnListFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public void populateResult(List<RedditPost> result) {
if(!redditPosts.isEmpty()){
redditPosts.remove(redditPosts.size() - 1);
}
redditPosts.addAll(result);
mAdapter.setLoaded();
mAdapter.notifyDataSetChanged();
}
protected boolean isTaskRunning() {
if (helper == null) {
return false;
} else if (helper.getStatus() == 0) {
return false;
} else {
return true;
}
}
}
I call the hideProgressBar(), showProgressBar() and populateResult() in my helper class.
There's a long standing mantra in programming that states: "Favor composition over inheritance"
You can read about the details of this statement and a lot of discussion here.
In this case, inheritance is unnecessary because you can simply build 1 Fragment and, on initialization pass it the subreddit, thus avoiding any constraining links between a super and subclass that may not even have any sort of polymorphic relationship.
This is my main activity:
public class MainActivity extends BaseGameActivity implements GameFragment.Listener {
GameFragment mGameFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mGameFragment = new GameFragment();
mGameFragment.setListener(this);
}
#Override
public void onGameEnded(int score) {
...
}
}
And this is just a fragment to host my game.
public class GameFragment extends Fragment implements View.OnClickListener {
public interface Listener {
public void onGameEnded(int score);
}
Listener mListener = null;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.game_layout, container, false);
checkSequence();
return view;
}
public void setListener(Listener l) {
mListener = l;
}
private void checkSequence() {
if (mListener != null)
mListener.onGameEnded(score);
}
}
For some reason mListener is always null. I've tried other questions on SO but none of them have worked. What am I doing wrong?
I think you have to Override this two Methods in GameFragment
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof Listener ) {
mListener = (Listener) activity;
} else {
throw new ClassCastException(activity.toString()
+ " must implemenet GameFragment.Listener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener= null;
}
for more detail Read this Tutorial
EDIT
And Don't Forget to Initialize Fragment in Activity
// Create an instance of GameFragment
GameFragment mGameFragment= new GameFragment();
// Add the fragment to the 'fragment_container' Layout
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, mGameFragment).commit();