9

I have the following scenario. I have an activity which holds a fragment. In this fragment I'm displaying some records from a back-end database. I'm also using an adapter that looks like this:

public class MovieAdapter extends PagedListAdapter<Movie, MovieAdapter.MovieViewHolder> {
    private Context context;

    public MovieAdapter(Context context) {this.context = context;}

    @NonNull
    @Override
    public MovieViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        //Create the view
    }

    @Override
    public void onBindViewHolder(@NonNull final MovieViewHolder holder, int position) {
        Movie movie = getItem(position);
        String title = movie.title;
        holder.titleTextView.setText(title);

        MovieRepository movieRepository = new MovieRepository(context);
        LiveData<Movie> liveData = movieRepository.retrieveFavoriteMovie(movie.id);
        liveData.observe(context, m -> { //Error
            if(m != null) {
                boolean favorite = m.favorite;
                if(favorite) {
                    //Do something
                } else {
                    //Do something else
                }
            }
        });
    }

    class MovieViewHolder extends RecyclerView.ViewHolder {
        ImageView favoriteImageView;
        TextView titleTextView;

        MovieViewHolder(View itemView) {
            super(itemView);
            titleTextView = itemView.findViewById(R.id.title_text_view);                favoriteImageView = itemView.findViewById(R.id.favorite_image_view);
        }
    }
}

In the onBindViewHolder I'm trying to check if a specific movie exist in Romm database but I get this error:

Wrong 1st argument type. Found: 'android.content.Context', required: 'android.arch.lifecycle.LifecycleOwner'

So how to transform the context of fragment into a LifecycleOwner so I can use it as in argument in my method?

Joan P.
  • 2,368
  • 6
  • 30
  • 63
  • Does your `Activity` implements `LifecycleOwner` ? Also how are you passing `Context` to Adapter ? – ADM Jan 31 '19 at 12:59
  • You can use `context` as **`((Fragment) context)`** if **context** is instance of `Fragment`. – Jeel Vankhede Jan 31 '19 at 13:02
  • @ADM No, it does not. I'm passing the context to the constructor `public MovieAdapter(Context context) {this.context = context;}`. Do you have any idea how I can solve this? Thanks anyway! – Joan P. Jan 31 '19 at 13:18
  • @JeelVankhede I get `Inconvertible types; cannot cast 'android.content.Context' to 'android.support.v4.app.Fragment'`. – Joan P. Jan 31 '19 at 13:20
  • @ADM And being a fragment I'm using this `adapter = new MovieAdapter(getContext());` Is this correct? – Joan P. Jan 31 '19 at 13:22
  • Why do you need to observe LiveData inside Adapter? You are already receiving a `Movie`. – EpicPandaForce Jan 31 '19 at 22:12
  • @EpicPandaForce I'm receiving a `Movie` from a backend server and I need to observe if a property (favorite) from my local database holds a specific value. How can I achieve that? Thanks! – Joan P. Feb 01 '19 at 06:11
  • You already have a `Movie` object, if you are using LiveData – EpicPandaForce Feb 01 '19 at 12:51
  • @EpicPandaForce I have a Movie object that I want to compare with a Movie object that exist within my Room database. Is this possible? – Joan P. Feb 01 '19 at 13:08

2 Answers2

12

android.content.Context does not implement android.arch.lifecycle.LifecycleOwner.

You'd have to pass an instance of AppCompatActivity, which implements android.arch.lifecycle.LifecycleOwner (or any other class which does that).

or cast (AppCompatActivity) context, when context is an instanceof AppCompatActivity. To get the Activity from the Context in a reliable manner, check https://stackoverflow.com/a/46205896/2413303

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
Martin Zeitler
  • 1
  • 19
  • 155
  • 216
  • Thanks Martin, I'll try that. – Joan P. Jan 31 '19 at 20:10
  • I'm trying to pass to the constructor a new instance of the Fragment where I'm constructing the adapter but nothing happens. Do have any other idea? Thanks! – Joan P. Feb 01 '19 at 06:40
  • A simple cast to `AppCompatActivity` finally did the trick but it seems that in this case the observer is not removed :( I'll check that out and ask another question. – Joan P. Feb 01 '19 at 07:01
  • 1
    @IoanaP. there's also `.observeForever(Observer)` and `.removeObserver(Observer)` if there is demand for manually controlling the removal of the observation. see https://developer.android.com/topic/libraries/architecture/livedata – Martin Zeitler Feb 01 '19 at 09:56
1

Posting this for people figuring out the solution suggested above, below i have added a short hand extension version of this for kotlin android

private fun Context?.getLifeCycleOwner() : AppCompatActivity? = when {
    this is ContextWrapper -> if (this is AppCompatActivity) this else this.baseContext.getLifeCycleOwner()
    else -> null
}

Usage of above extension in a fragment would look like :

private var mainActivityContext: Context? = null //class level variable

//below statement called after context variable assigned / OnCreate
mainActivityContext?.getLifeCycleOwner()?.let { lifeCycleOwner ->
            YourViewModel.liveDataReturningMethod(text.toString())
                .observe(lifeCycleOwner , Observer { x ->
                    //your logic here...
                })
        }
MDT
  • 1,535
  • 3
  • 16
  • 29