-1

I have a RecyclerView adapter for user added favorites. The recyclerview is populated in a dialog box fragment.

public class FavoriteAdapter extends RecyclerView.Adapter<FavoriteViewHolder> implements ILatLong {

    private Context context;
    View view;
    MainActivity mainActivity;

    private List<Favorite> listFavorites;
    private SQLiteDB mDatabase;
    private int position;

    private ILatLong mCallback;

    public FavoriteAdapter(ILatLong mCallback){
        this.mCallback = mCallback;
    }

    public FavoriteAdapter(Context context, List<Favorite> listFavorites) {
        this.context = context;
        this.listFavorites = listFavorites;
        mDatabase = new SQLiteDB(context);
    }

    @Override
    public void onBindViewHolder(final FavoriteViewHolder holder, final int mPosition) {
        final Favorite singleFavorite = listFavorites.get(mPosition);

        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context, "Clicked " + "'" + singleFavorite.getName() + "'", Toast.LENGTH_SHORT, true).show();
                //mainActivity.onLatLngData(singleFavorite.getLat(), singleFavorite.getLong());
                mCallback.onLatLngData(singleFavorite.getLat(), singleFavorite.getLong());
            }
        });

        //other stuff

    @Override
    public void onLatLngData(Double lat, Double lng) {
        try {
            mCallback = (ILatLong) context;
        }
        catch (ClassCastException e) {
            Log.d("MyDialog", "Activity doesn't implement the ILatLong interface");
        }
    }
}

Interface:

public interface ILatLong {
    void onLatLngData(Double lat, Double lng);
}

MainActivity method:

public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener, ILatLong {
    @Override
    public void onLatLngData(Double lat, Double lng) {
        //use the values
    }
}

I've set up the onclicklistener in the onBindViewHolder as you can see, so I know which item is clicked, and when a recyclerview item is clicked it displays a toast with the correct item name (or whatever other attribute I want).

When I try and send the latitude and longitude back to my mainactivity method by uncommenting the line in onclick I get "java.lang.NullPointerException: Attempt to invoke virtual method ...onLatLngData(java.lang.Double, java.lang.Double)' on a null object reference".

How can I send this data back to my mainactivity? I've tried using an interface to callback to MainActivity with no luck but maybe I wasn't doing it right.

Edit: included the interface callback stuff

sS3tYo
  • 21
  • 5
  • It's because you have just declared _MainActivity mainActivity;_ not initialized. You need to pass in constructor too and give reference by _this.mainActivity = mainActivity;_ – Piyush May 21 '19 at 13:09
  • Post full code of your created interface in mainactivity – Mayur May 21 '19 at 13:10
  • Please share your adapter class completely – milad salimi May 21 '19 at 13:11
  • I'm tempted to mark this as a duplicate of https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it but it wouldn't really help to solve the problem. You are not passing the MainActivity in a constructor argument, therefore it is `null`. It is not initialized. – EpicPandaForce May 21 '19 at 13:26
  • Would be usefull und very easy for you to make a [Singleton](https://medium.com/@kevalpatel2106/how-to-make-the-perfect-singleton-de6b951dfdb0) out of you `MainActivity`. – Marcel Hofgesang May 21 '19 at 13:31
  • Possible duplicate of [Set a click listener to a RecyclerView](https://stackoverflow.com/questions/49969278/set-a-click-listener-to-a-recyclerview) – Reaz Murshed May 21 '19 at 13:37
  • Updated the answer with callback stuff in. I've tried initializing mainActivity (same problem) with: FavoriteAdapter(Context context, MainActivity mActivity) { this.mainActivity = mActivity; } – sS3tYo May 21 '19 at 13:57

2 Answers2

0

You have to do those 4 steps in order to make callback work

  1. Create an interface that contains the callback function
public interface MyCallback{
    public void onCallbackClicked(String param)
}
  1. Implement this interface my your main activity
... implements MyCallback{
// Other stuff here
@Override
public void onCallbackClicked(String param){
// Code here
}
  1. Inside your FavoriteAdapter , create variable of type MyCallback
 MyCallback myCallback;

inside your onBindViewHolder you should have something like :

@Override
    public void onBindViewHolder(final FavoriteViewHolder holder, final int mPosition) {
        final Favorite singleFavorite = listFavorites.get(mPosition);

        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(myCallback != null){
                    myCallback.onCallbackClicked(/* your data here */);
                 }
            }
        });
}
  1. This is an important step , pass the listener (Main activity) to the adapter , you can pass it using constructor
public FavoriteAdapter(MyCallback myCallback){
   this.myCallback = myCallback;
}

or using a setter

public void setCallback(MyCallback myCallback){
   this.myCallback = myCallback;
}

now you are good to go.

ikerfah
  • 2,612
  • 1
  • 11
  • 18
  • Thanks for your answer, it's similar to what I've tried to do already with no luck. Could you take a look at my updated question with the callback stuff added? I've added step 4. constructor but no change, it says constructor isn't used. – sS3tYo May 21 '19 at 14:00
  • You should pass the listener to your adapter , when you create an instance of your adapter , pass ```this``` as MyCallback param to the adapter – ikerfah May 21 '19 at 14:28
0

Thanks for the help. I managed to solve it through passing my MainActivity.

The problem was it goes MainActivty -> FavoriteDialog -> FavoriteAdapter and I think I was getting confused with the chain here. Maybe it will help someone else.

MainActivity:

public class MainActivity extends AppCompatActivity
    implements NavigationView.OnNavigationItemSelectedListener, ILatLong {

MainActivity mActivity;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mActivity = this;
    }

    // Where I call my FavoriteDialog fragment, pass mActivity in constructor
    FragmentManager fm = getSupportFragmentManager();
    FavoriteDialog dialogFavorite = new DialogFavorite(context, mActivity);
    dialogFragment.show(fm, "FavoriteDialog");
}

DialogFavorite

DialogFavorite(Context context, MainActivity mActivity) {
        mainActivity = mActivity;
    }

// Adapter, pass mainActivity
FavoriteAdapter mAdapter = new FavoriteAdapter(context, allFavorites, mainActivity);
favoriteView.setAdapter(mAdapter);

FavoriteAdapter:

public FavoriteAdapter(Context context, List<Favorite> listFavorites, MainActivity mActivity) {
    this.context = context;
    this.listFavorites = listFavorites;
    mDatabase = new SQLiteDB(context);
    this.mainActivity = mActivity;
    }

Now calling mainActivity in my FavoriteAdapter onclick works:

@Override
public void onBindViewHolder(final FavoriteViewHolder holder, final int mPosition) {
    final Favorite singleFavorite = listFavorites.get(mPosition);

    view.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mainActivity.onLatLngData(52.246218, 20.970564);
        }
    });
sS3tYo
  • 21
  • 5