【问题标题】:Trying to load an image using Picasso library. Cant get the context尝试使用 Picasso 库加载图像。无法获取上下文
【发布时间】:2021-07-01 09:52:45
【问题描述】:

在我的代码中,我使用 ImageView 项目填充 RecyclerView,这些项目将保存从在线数据库中获取的一些图片。
当需要在布局上显示时,我的应用程序将自动调用我的 PosterViewHolder 子类的 bind() 函数以使用数据填充 ImageView。

为了从数据库中检索这些图像,我设置了一个名为 ShowPoster 的 ASyncTask。 ShowPoster 设置为 PosterViewHolder 的子类,它允许我引用我要填充的 ImageView。

我的 ASyncTask 在单独的字符串上执行,允许我在不中断主 UI 线程的情况下使用网络功能(这在 Android 中是强制性的)。

从数据库中检索原始 JSON 并对其进行适当解析后,我得到了 imageURL,这是我将从数据库中提取的图像的 URL。

然后我使用 Picasso 库从数据库中检索图像,并将图像加载到名为 posterView 的 ImageView 中,使用以下特定代码行:

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

这是我的错误发生的地方,特别是在.with(this) 的参数中,我需要提供我的应用程序的上下文。

我尝试用函数调用替换this 来获取应用程序上下文,例如 Context.getApplicationContext(),但在此类中,我似乎无法调用这些函数。

我还尝试在我的主 Activity 中的 onCreate() 函数中实例化一个新的 Context,然后将它传递给我的 PosterAdapter 类的构造函数,这样我就可以在我的 ASyncTask 中引用它,而无需进行任何函数调用,这是偷偷摸摸的通过 IDE 并编译,但应用程序在运行时崩溃。

在寻求解决问题的过程中,我偶然发现有人提到在 AndroidManifest 中没有 android:name="" 与问题有关,但我不完全确定在这个字段中除了包之外应该放什么姓名。

作为参考,这是我的代码和清单

代码:(完整转载,API 密钥已审查)

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();
        }
    }
}

清单:

    <?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>

【问题讨论】:

  • 你能发布你的完整适配器代码吗?
  • 从托管活动中传递上下文并在 Picasso.with() 中使用它
  • 您可以从 posterView 获取上下文。 posterView.getContext()。检查空值是个好主意。

标签: android picasso android-context


【解决方案1】:

将 Context 声明为 global 。然后在构造函数中赋值

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();
    }

然后在毕加索中使用上下文

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

【讨论】:

  • 理想情况下,您应该将上下文存储在适配器中,而不是在每个 ViewHolder 中
  • 谢谢!如果我可以更进一步,为什么要使用 ItemView.getContext()?我的理解是 Context 填充了有关应用程序的信息,而不是特定项目。 itemView 是从 super 调用 getContext,还是我的理解不正确?
  • @sasikumar in your link... "如果在 onCreateViewHolder() 方法之外需要上下文,只要有可用的 ViewHolder 实例,就可以通过以下方式检索上下文:viewHolder .itemView.getContext().itemView 是基础 ViewHolder 类中的公共、非 null 和 final 字段”,因此您不需要将 Context 本身作为字段。
【解决方案2】:

将您的上下文传递给此类

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;
        }
    }
}

并使用您的视图持有者,例如PosterViewHolder(view,getApplicationContext())

仅供参考


this 指的是当前类。在你的情况下,你想通过 活动的上下文

【讨论】:

    【解决方案3】:

    从适配器存储上下文

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

    在 ViewHolder 中使用 PosterAdapter.this.mContext

    或者使用你的 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);
        }
    

    您可以在 ViewHolder 中使用this.itemView.getContext()

    【讨论】:

    • @M.Ashish 这没什么问题。请不要编辑
    • 老兄,(this.mContext)中不需要这个,因为上下文与mContext不同。但是,这在 PosterViewHolder() 构造函数中非常好。
    • 我明白没有必要。但这是你的意见。我喜欢这样做,尽管它很冗长
    【解决方案4】:

    Picasso API 已更改

    仅获取 Picasso 实例:

    val picasso = Picasso.get()
    

    没有像以前那样将上下文作为参数传递

    【讨论】:

      【解决方案5】:

      在毕加索新版本中使用 get() 而不是 .with(context)。 2.7+

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

      【讨论】:

        【解决方案6】:

        声明上下文全局并将上下文作为构造函数参数传递。

        public class PosterAdapter extends RecyclerView.Adapter<PosterAdapter.PosterViewHolder>{
        
        private Context mContext;
        
        public PosterAdapter(Context context, Other variables...){
                mContext = context;
            }
        .
        .
        .
        
        }
        

        【讨论】:

          【解决方案7】:

          试试这个.....

          Picasso. With(getContext)  
          

          并确保将上下文传递给适配器。

          【讨论】:

            猜你喜欢
            • 2019-08-14
            • 2019-08-20
            • 1970-01-01
            • 1970-01-01
            • 2018-06-02
            • 2020-08-03
            • 1970-01-01
            • 2017-01-16
            • 2016-07-01
            相关资源
            最近更新 更多