Chris Phillips
Chris Phillips

Reputation: 2124

Trying to load an image using Picasso library. Cant get the context

In my code, I am populating a RecyclerView with ImageView items that will hold some pictures taken from an online database.
My application will call the bind() function of my PosterViewHolder subclass automatically to populate the ImageViews with data, when they need to be displayed on the layout.

To retrieve these images from the database, I setup an ASyncTask, named ShowPoster. ShowPoster is set up as a subclass of PosterViewHolder, which allows me to reference the ImageView which I am trying to populate.

My ASyncTask executes on a separate string, allowing me to use network functions without interrupting the main UI thread (which is mandatory in Android).

After retrieving the raw JSON from the database, and parsing it appropriately, I have imageURL, which is the URL of the image I will pull from the database.

I then use the Picasso library to retrieve the image from the database, and load the image into my ImageView, named posterView, using this specific line of code:

Picasso.with(this).load(imageURL).into(posterView);

This is where my error occurs, specifically in the parameters of .with(this), where I need to provide the context of my app.

I have tried substituting this with function calls to get application context, like Context.getApplicationContext(), but in this class, it appears I cannot call these functions.

I have also tried instantiating a new Context in my onCreate() function in my main Activity, then passing it to the constructor of my PosterAdapter class, so that I can reference it within my ASyncTask without making any function calls, which sneaks past the IDE and compiles, but the application crashes when run.

In my quest to find a solution to my problem, I stumbled across someone mentioning that not having android:name="" in the AndroidManifest is related to the problem, but I'm not entirely sure what to put in this field beyond the package name.

For reference, here is my code, and my manifest

CODE: (Reposted in full, API Keys censored)

package com.example.android.myapplication;

import android.content.Context;
import android.os.AsyncTask;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.squareup.picasso.Picasso;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;

public class PosterAdapter extends RecyclerView.Adapter<PosterAdapter.PosterViewHolder>{
    private String POPULAR_MOVIES_URL = "https://api.themoviedb.org/3/movie/popular?api_key=XXXX";
    private String RATED_MOVIES_URL = "https://api.themoviedb.org/3/movie/top_rated?api_key=XXXX";
    private String searchQueryURL;
    private int mNumberItems;
    private MovieDBJSONTools mJSONTools;

    public PosterAdapter(int numItems, String query){
        mNumberItems = numItems;
        mJSONTools = new MovieDBJSONTools();
        searchQueryURL = null;
        switch(query){
            case "popular":
                searchQueryURL = POPULAR_MOVIES_URL;
                break;
            case "rating":
                searchQueryURL = RATED_MOVIES_URL;
                break;
        }
    }

    @Override
    public PosterViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType){
        Context context = viewGroup.getContext();
        int layoutIdForListItem = R.layout.poster_item;
        LayoutInflater inflater = LayoutInflater.from(context);
        boolean shouldAttachToParentImmediately = false;

        View view = inflater.inflate(layoutIdForListItem, viewGroup, shouldAttachToParentImmediately);
        PosterViewHolder viewHolder = new PosterViewHolder(view);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(PosterViewHolder viewHolder, int position){
            viewHolder.bind(position);
    }

    @Override
    public int getItemCount(){
        return mNumberItems;
    }

     class PosterViewHolder extends RecyclerView.ViewHolder{
        ImageView posterView;

        public PosterViewHolder(View itemView) {
            super(itemView);

            posterView = (ImageView) itemView.findViewById(R.id.poster_item);
        }

        void bind(int pos){
            new ShowPoster().execute(pos);
        }

        private class ShowPoster extends AsyncTask<Integer, Void, Void>{
            @Override
            protected Void doInBackground(Integer... params) {
                try {
                    String rawJSON = getResponseFromHttpURL(new URL(searchQueryURL));
                    String imageURL = mJSONTools.GetMoviePosterURL(rawJSON, params[0]);
                    Picasso.with(this).load(imageURL).into(posterView);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }
    }

    private String getResponseFromHttpURL(URL url) throws IOException {
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        try {
            InputStream in = urlConnection.getInputStream();

            Scanner scanner = new Scanner(in);
            scanner.useDelimiter("\\A");

            boolean hasInput = scanner.hasNext();
            if (hasInput) {
                String next = scanner.next();
                return next;
            } else {
                return null;
            }
        } finally {
            urlConnection.disconnect();
        }
    }
}

Manifest:

    <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.myapplication">
    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="Popular Movies"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Upvotes: 1

Views: 3592

Answers (7)

Hemant Jain
Hemant Jain

Reputation: 1

use the get() instead of .with(context) in picasso new version. for 2.7+

 Picasso.get().load(imageURL).into(posterView);

Upvotes: 0

Andrew
Andrew

Reputation: 37969

Picasso API has changed

To get Picasso instance just:

val picasso = Picasso.get()

Without passing the context as param as before

Upvotes: 0

Apurv
Apurv

Reputation: 1

try this.....

Picasso. With(getContext)  

And make sure you are passing context to your adapter.

Upvotes: -2

OneCricketeer
OneCricketeer

Reputation: 191728

Store the Context from the Adapter

private Context mContext;
public PosterAdapter(Context context, int numItems, String query){
    this.mContext = context;

Use in the ViewHolder as PosterAdapter.this.mContext

Or use your itemView

class PosterViewHolder extends RecyclerView.ViewHolder{
    final View itemView;
    ImageView posterView;

    public PosterViewHolder(View itemView) {
        super(itemView);
        this.itemView = itemView;
        posterView = (ImageView) itemView.findViewById(R.id.poster_item);
    }

And you can use this.itemView.getContext() within the ViewHolder

Upvotes: 0

Ashish M
Ashish M

Reputation: 823

Declare Context global and pass context as Constructor parameter.

public class PosterAdapter extends RecyclerView.Adapter<PosterAdapter.PosterViewHolder>{

private Context mContext;

public PosterAdapter(Context context, Other variables...){
        mContext = context;
    }
.
.
.

}

Upvotes: -1

Sasi Kumar
Sasi Kumar

Reputation: 13348

Declare Context as global . Then assign value in the constructor

private class PosterViewHolder extends RecyclerView.ViewHolder{
ImageView posterView;
Context context;

    public PosterViewHolder(View itemView) {
    super(itemView);

    posterView = (ImageView) itemView.findViewById(R.id.poster_item);
    context = itemView.getContext();
    }

then use the context in picasso

 Picasso.with(context).load(imageURL).into(posterView);

Upvotes: 4

Kiran Benny Joseph
Kiran Benny Joseph

Reputation: 6813

Pass your context to this class like

private class PosterViewHolder extends RecyclerView.ViewHolder{
    ImageView posterView;
    Context context;
    public PosterViewHolder(View itemView,Context context) {
        super(itemView);
        this.context=context;
        posterView = (ImageView) itemView.findViewById(R.id.poster_item);
    }

    void bind(int pos){
        new ShowPoster().execute(pos);
    }


    private class ShowPoster extends AsyncTask<Integer, Void, Void>{
        private Bitmap poster;
        @Override
        protected Void doInBackground(Integer... params) {
            poster = null;
            try {
                String rawJSON = getResponseFromHttpURL(new URL(searchQueryURL));
                String imageURL = mJSONTools.GetMoviePosterURL(rawJSON, params[0]);
                Picasso.with(context).load(imageURL).into(posterView);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
}

And use your view holder like PosterViewHolder(view,getApplicationContext())

FYI


this refers to the current class. In your case, you want to pass the activity's context

Upvotes: 0

Related Questions