title: Loading Images from URL Is Producing Unexpected Results
body: <p>I am loading images from Wikipedia into a Grid view.  For the most part this is working correctly.  Because there could possible be up to 200 or more images being loaded I am try to run it in a new thread.  I see a definite delay when scrolling from my Album tab to the Artist tab that is loading the images.  I am also see some lag as images are still getting load while scrolling up and down the list.  Also when I scroll back to the top of the list place holders that previously occupied by the default image because I am unable to get an image from Wikipedia are now occupied by images from another artist.</p>
  <p>When I scroll back to the song list and then back to the artist list the view is reset but it still has a lot of delay when going into the artist tab.</p>
  <p>This image is what the screen looks like when first entering the Artist tab.</p>
  <p><a href="https://i.stack.imgur.com/W6xzD.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/W6xzD.jpg" alt="enter image description here" /></a></p>
  <p>This image is what the screen looks like after scrolling to the bottom of the list and back to the top.</p>
  <p><a href="https://i.stack.imgur.com/wqhwl.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/wqhwl.jpg" alt="enter image description here" /></a></p>
  <p>As you can see the &lt;unknow. and AJR have had their default image replaced.</p>
  <p>Here is my code that I am calling to load the images from Wikipedia.</p>
  <pre><code>@Override
  public void onBindViewHolder(@NonNull ARV holder, int position) {
  
      Artist artist = artistList.get(position);
      if(artist!=null) {
          holder.artistName.setText(artist.artistName);
          String bandName = artist.artistName;
          bandName = bandName.replace(' ','_');
          try {
              String imageUrl = cutImg(getUrlSource(&quot;https://en.wikipedia.org/w/api.php?action=query&amp;titles=&quot;+bandName+&quot;&amp;prop=pageimages&amp;format=json&amp;pithumbsize=250&quot;));
              URL url = new URL(imageUrl);
              ImageLoader.getInstance().displayImage(imageUrl, holder.artistImage,
                      new DisplayImageOptions.Builder().cacheInMemory(true).showImageOnLoading(R.drawable.album)
                              .resetViewBeforeLoading(true).build());
          } catch (IOException e) {
              e.printStackTrace();
          }
  
          /*ImageLoader.getInstance().displayImage(getCoverArtPath(context,artist.id),holder.artistImage,
                  new DisplayImageOptions.Builder().cacheInMemory(true).showImageOnLoading(R.drawable.album)
                          .resetViewBeforeLoading(false).build());*/
          }
  }
  
  private StringBuilder getUrlSource(String site) throws IOException {
      StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
      StrictMode.setThreadPolicy(policy);
      URL localUrl = null;
      localUrl = new URL(site);
      URLConnection conn = localUrl.openConnection();
      BufferedReader reader = new BufferedReader(
              new InputStreamReader(conn.getInputStream()));
      String line = &quot;&quot;;
      String html;
      StringBuilder ma = new StringBuilder();
      while ((line = reader.readLine()) != null) {
          ma.append(line);
          Log.i(ContentValues.TAG, &quot;StringBuilder &quot; + ma);
      }
      Log.i(ContentValues.TAG, &quot;Final StringBuilder &quot; + ma);
      return ma;
  }
  
  public static String cutImg(StringBuilder split){
      int start=split.indexOf(&quot;\&quot;source\&quot;:&quot;)+new String(&quot;\&quot;source\&quot;:\&quot;&quot;).length();
      split.delete(0, start);
      split.delete(split.indexOf(&quot;\&quot;&quot;), split.length());
      Log.i(ContentValues.TAG, &quot;StringBuilder &quot; + split);
      return split.toString();
  }
  </code></pre>
  <p>Here is the code that is call the Artist Fragment.</p>
  <pre><code>public class ArtistFragment extends Fragment {
  
      int spanCount = 3; // 2 columns
      int spacing = 20; // 20px
      boolean includeEdge = true;
  
      private RecyclerView recyclerView;
      private ArtistAdapter adapter;
  
      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
                               Bundle savedInstanceState) {
          View view = inflater.inflate(R.layout.fragment_artist, container, false);
          recyclerView = view.findViewById(R.id.artistFragment);
          recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 3));
  
          Thread t = new Thread()
          {
              public void run()
              {
                  // put whatever code you want to run inside the thread here.
                  new LoadData().execute(&quot;&quot;);
              }
          };
  
          t.start();
          return view;
      }
  
      public class LoadData extends AsyncTask&lt;String, Void, String&gt; {
  
          @Override
          protected String doInBackground(String... strings) {
              if(getActivity()!=null) {
                  adapter=new ArtistAdapter(getActivity(),new ArtistLoader().artistList(getActivity()));
              }
              return &quot;Executed&quot;;
          }
  
          @Override
          protected void onPostExecute(String s) {
              recyclerView.setAdapter(adapter);
              if(getActivity()!=null) {
                  recyclerView.addItemDecoration(new GridSpacingItemDecoration(spanCount, spacing, includeEdge));
              }
          }
  
          @Override
          protected void onPreExecute() {
              super.onPreExecute();
          }
      }
  }
  </code></pre>
  <p>I have also tried this using Picasso using the following code:</p>
  <pre><code> bandName = artist.artistName;
      bandName = bandName.replace(' ','_');
      try {
             String imageUrl = cutImg(getUrlSource(&quot;https://en.wikipedia.org/w/api.php?action=query&amp;titles=&quot;+bandName+&quot;&amp;prop=pageimages&amp;format=json&amp;pithumbsize=250&quot;));
                      URL url = new URL(imageUrl);
                      Picasso.get().load(imageUrl).placeholder(R.drawable.album)
                              .error(R.drawable.artistdefault).into(holder.artistImage);
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
  </code></pre>
  <p>The results are pretty much the same as when I used Android-Universal-Image-Loader. I have been try for several days to fix this, I have tried several different examples that I found on Stack overflow but none of them seem to resolve the issues I am seeing.  I am hoping that someone will be able to identify what I am doing incorrectly.
  Thanks in advance.</p>
  <p>ArtistFragmentconverted to Kotlin</p>
  <pre><code>class ArtistFragment : Fragment() {
  var spanCount = 3 // 2 columns
  var spacing = 20 // 20px
  var includeEdge = true
  
  var retrofit: Retrofit? = null
  var wikiService: WikiService? = null
  var adapter: ArtistAdapter? = null
  
  private var recyclerView: RecyclerView? = null
  
  private var viewModelJob = Job()
  private val viewModelScope = CoroutineScope(Dispatchers.Main + viewModelJob)
  
  private var progress_view: ProgressBar? = null
  
  override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                            savedInstanceState: Bundle?): View? {
      val view = inflater.inflate(R.layout.fragment_artist, container, false)
      recyclerView = view.findViewById(R.id.artistFragment)
      recyclerView?.setLayoutManager(GridLayoutManager(activity, 3))
      progress_view = view.findViewById(R.id.progress_view)
      initWikiService()
      initList()
      //LoadData().execute(&quot;&quot;)
      return view
  }
  
  override fun onDestroy() {
      super.onDestroy()
      viewModelJob.cancel()
  }
  
  private fun initList() {
      recyclerView!!.addItemDecoration(GridSpacingItemDecoration(spanCount, spacing, includeEdge))
      adapter = ArtistAdapter(this)
      adapter?.items = ArrayList()
      adapter?.listener = this
      recyclerView?.adapter = adapter
  
      viewModelScope.launch {
          progress_view.visibility = View.VISIBLE
          val wikiPages = getWikiPages()
          adapter?.items = wikiPages
          progress_view?.visibility = View.GONE
      }
  }
  
  private suspend fun getWikiPages(): ArrayList&lt;Artist&gt; {
      val newItems = ArrayList&lt;Artist&gt;()
  
      withContext(Dispatchers.IO) {
          ArtistData.artists.map { artist -&gt;
  
              async { wikiService?.getWikiData(artist) }
          }.awaitAll().forEach { response -&gt;
              val pages = response?.body()?.query?.pages
              pages?.let {
                  for (page in pages) {
                      val value = page.value
                      val id = value.pageid?.toLong() ?: value.title.hashCode().toLong()
                      val title = value.title ?: &quot;Unknown&quot;
                      val url = value.thumbnail?.source
                      newItems.add(Artist(id, title, albumCount = 0, songCount = 0, artistUrl = url!!))
                  }
              }
          }
      }
      return newItems
  }
  
  private fun initWikiService() {
      retrofit = Retrofit.Builder()
              .baseUrl(&quot;https://en.wikipedia.org/&quot;)
              .addConverterFactory(GsonConverterFactory.create())
              .build()
      wikiService = retrofit?.create(WikiService::class.java)
  }
  </code></pre>
  <p>I believe I have resolved most of the issues I was previously seeing I am now down to the following problems:</p>
  <p><code>Artist.item.map { artist -&gt;</code> - Not sure how this should be called, Unresolved reference: item</p>
  <p><code>}.awaitAll().forEach { response -&gt;</code> = forEach is telling me Overload resolution ambiguity. All these functions match.
  public inline fun  Iterable&lt;TypeVariable(T)&gt;.forEach(action: (TypeVariable(T)) → Unit): Unit defined in kotlin.collections
  public inline fun &lt;K, V&gt; Map&lt;out TypeVariable(K), TypeVariable(V)&gt;.forEach(action: (Map.Entry&lt;TypeVariable(K), TypeVariable(V)&gt;) → Unit): Unit defined in kotlin.collections</p>
  <p><code>newItems.add(Artist(id, title, url))</code> - I know that the variables for the Artist Model need to go here, but when I put them there they are unresolved.</p>
  <p>I have reworked the ArtistAdapter not sure if it is correct though.</p>
  <pre><code>class ArtistAdapter(private val context: ArtistFragment, private val artistList: List&lt;Artist&gt;?) : RecyclerView.Adapter&lt;ArtistAdapter.ARV&gt;() {
  
  private var dimension: Int = 64
  
  init {
      val density = context.resources.displayMetrics.density
      dimension = (density * 64).toInt()
      hasStableIds()
  }
  
  var items: MutableList&lt;Artist&gt; = ArrayList()
      set(value) {
          field = value
          notifyDataSetChanged()
      }
  
  var listener: Listener? = null
  
  interface Listener {
      fun onItemClicked(item: Artist)
      abstract fun ArtistAdapter(context: ArtistFragment): ArtistAdapter
  }
  
  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ARV {
      return ARV(LayoutInflater.from(parent.context).inflate(R.layout.artist_gride_item, parent,
              false))
  }
  
  override fun onBindViewHolder(holder: ARV, position: Int) {
      holder.onBind(getItem(position))
  }
  
  private fun getItem(position: Int): Artist = items[position]
  
  override fun getItemId(position: Int): Long = items[position].id
  
  override fun getItemCount(): Int {
      return artistList?.size ?: 0
  }
  
  inner class ARV(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
  
      private val artistNameView: TextView = itemView.findViewById(R.id.artistName)
      private val artistAlbumArtView: SquareCellView = itemView.findViewById(R.id.artistAlbumArt)
  
      fun onBind(item: Artist) {
          artistNameView.text=item.artistName
  
          if(item.artistURL!=null) {
              Picasso.get()
                          .load(item.artistURL)
                          .resize(dimension, dimension)
                          .centerCrop()
                          .error(R.drawable.artistdefualt)
                          .into(artistAlbumArtView)
          } else {
              artistAlbumArtView.setImageResource(R.drawable.artistdefualt)
          }
          itemView.setOnClickListener(this)
      }
  
      override fun onClick(view: View) {
          val artistId = artistList!![bindingAdapterPosition].id
          val fragmentManager = (context as AppCompatActivity).supportFragmentManager
          val transaction = fragmentManager.beginTransaction()
          val fragment: Fragment
          transaction.setCustomAnimations(R.anim.layout_fad_in, R.anim.layout_fad_out,
                  R.anim.layout_fad_in, R.anim.layout_fad_out)
          fragment = ArtistDetailsFragment.newInstance(artistId)
          transaction.hide(context.supportFragmentManager
                  .findFragmentById(R.id.main_container)!!)
          transaction.add(R.id.main_container, fragment)
          transaction.addToBackStack(null).commit()
      }
  }
  </code></pre>
  <p>}</p>
  <p>Logcat Snippet</p>
  <pre><code>java.lang.NoSuchMethodError: No static method metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; in class Ljava/lang/invoke/LambdaMetafactory; or it
  
      s super classes (declaration of 'java.lang.invoke.LambdaMetafactory' appears in /apex/com.android.art/javalib/core-oj.jar)
              at okhttp3.internal.Util.&lt;clinit&gt;(Util.java:87)
              at okhttp3.internal.Util.skipLeadingAsciiWhitespace(Util.java:321)
              at okhttp3.HttpUrl$Builder.parse(HttpUrl.java:1313)
              at okhttp3.HttpUrl.get(HttpUrl.java:917)
              at retrofit2.Retrofit$Builder.baseUrl(Retrofit.java:506)
              at com.rvogl.androidaudioplayer.fragments.ArtistFragment.initWikiService(ArtistFragment.kt:103)
              at com.rvogl.androidaudioplayer.fragments.ArtistFragment.onCreateView(ArtistFragment.kt:43)
  </code></pre>