2016-05-12 63 views
0

这个简单的应用程序从用户获取标签,并在ListView中显示前10个匹配标签的闪烁图像。我用this简单的教程,我只是修改它,所以它可以使用闪烁搜索,而不是硬编码的链接。它可以工作,但不知何故,它会在某些视图中一个接一个地加载图像因此,用户在视图中看到图像发生了一段变化。如果用户滚动,它会重新加载它们。如果这是一个指针问题,我无法解决它。我将静态ViewHolder更改为非静态类,但没有任何更改。为什么会发生,我该如何解决它?ListView在视图中一个接一个地加载图像

主要类:

public class FlickerSearchMain extends AppCompatActivity implements AdapterView.OnItemClickListener, View.OnClickListener{ 
     private EditText tag; 
     private Button send; 
     private ListView listView; 
     ArrayList<ListItem> listData; 

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

      send = (Button) findViewById(R.id.send_button); 
      send.setOnClickListener(this); 
      tag = (EditText) findViewById(R.id.tag_input); 

      //ArrayList<ListItem> listData = getListData(); 
      listView = (ListView) findViewById(R.id.list); 
      listView.setOnItemClickListener(this); 


     } 

     @Override 
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 

      int itemPosition = position; 
      Toast.makeText(getApplicationContext(), 
        "Position :"+ itemPosition, Toast.LENGTH_SHORT) 
        .show(); 
     } 


     @Override 
     public void onClick(View v) { 
      if(v == send){ 
       String input = tag.getText().toString(); 
       new FlickerRequest(this).execute(input); 
      } 
     } 


     private class FlickerRequest extends AsyncTask<String, Void, ArrayList<ListItem>>{ 
      ArrayList<ListItem> elements_list; 
      Context context; 

      public FlickerRequest(Context context){ 
       this.context = context; 
       this.elements_list = new ArrayList<ListItem>(); 

      } 

      @Override 
      protected ArrayList<ListItem> doInBackground(String... params) { 
       String tag = params[0]; 

       int SIZE = 10; 
       URL flicker; 
       URLConnection urlcon; 
       BufferedReader in = null; 

       try { 
        flicker = new URL("https://api.flickr.com/services/feeds/photos_public.gne?tags=" 
          + tag + "&format=json"); 
        urlcon = flicker.openConnection(); 
        in = new BufferedReader(new InputStreamReader(urlcon.getInputStream())); 

        String inputLine; 
        StringBuilder strbuilder = new StringBuilder(); 

        in.skip(15); 

        while ((inputLine = in.readLine()) != null) 
         strbuilder.append(inputLine); 

        in.close(); 

        JSONObject job = new JSONObject(strbuilder.toString()); 
        JSONArray items = job.getJSONArray("items"); 

        for(int i=0; i<SIZE; i++) { 
         JSONObject item = items.getJSONObject(i); 
         ListItem newdata = new ListItem(); 
         newdata.setHeadline(item.getString("title")); 
         newdata.setAuthor(item.getString("author")); 
         newdata.setDate(item.getString("date_taken")); 
         newdata.setUrl(item.getJSONObject("media").getString("m")); 

         elements_list.add(newdata); 
        } 

       } catch (MalformedURLException e) { 
        e.printStackTrace(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } catch (JSONException e) { 
        e.printStackTrace(); 
       } 

       return elements_list; 
      } 

      protected void onPostExecute(ArrayList<ListItem> result) { 
       if(listData == null) { 
        listData = result; 
        listView.setAdapter(new FlickerAdapter(context, listData)); 
       } 
       else{ 
        listData = result; 
        ((BaseAdapter) listView.getAdapter()).notifyDataSetChanged(); 
       } 

      } 

     } 
    } 

适配器类别:

public class FlickerAdapter extends BaseAdapter { 
     private ArrayList<ListItem> listData; 
     private LayoutInflater layoutInflater; 

     public FlickerAdapter(Context context, ArrayList<ListItem> listData) { 
      this.listData = listData; 
      layoutInflater = LayoutInflater.from(context); 
     } 

     @Override 
     public int getCount() { 
      return listData.size(); 
     } 

     @Override 
     public Object getItem(int position) { 
      return listData.get(position); 
     } 

     @Override 
     public long getItemId(int position) { 
      return position; 
     } 

     public View getView(int position, View convertView, ViewGroup parent) { 
      ViewHolder holder; 
      if (convertView == null) { 
       convertView = layoutInflater.inflate(R.layout.list_row_layout, null); 
       holder = new ViewHolder(); 
       holder.headlineView = (TextView) convertView.findViewById(R.id.title); 
       holder.authorView = (TextView) convertView.findViewById(R.id.author); 
       holder.dateView = (TextView) convertView.findViewById(R.id.date); 
       holder.imageView = (ImageView) convertView.findViewById(R.id.image); 
       convertView.setTag(holder); 

      } else { 
       holder = (ViewHolder) convertView.getTag(); 
      } 

      ListItem newsItem = listData.get(position); 
      holder.headlineView.setText(newsItem.getHeadline()); 
      holder.authorView.setText("By, " + newsItem.getAuthor()); 
      holder.dateView.setText(newsItem.getDate()); 

      if (holder.imageView != null) { 
       new ImageDownloaderTask(holder.imageView).execute(newsItem.getUrl()); 
      } 

      return convertView; 
     } 

     static class ViewHolder { 
      TextView headlineView; 
      TextView authorView; 
      TextView dateView; 
      ImageView imageView; 
     } 
    } 

AsynTask ImageLoader的类

class ImageDownloaderTask extends AsyncTask<String, Void, Bitmap> { 
     private final WeakReference<ImageView> imageViewReference; 

     public ImageDownloaderTask(ImageView imageView) { 
      imageViewReference = new WeakReference<ImageView>(imageView); 
     } 

     @Override 
     protected Bitmap doInBackground(String... params) { 
      return downloadBitmap(params[0]); 
     } 



     @Override 
     protected void onPostExecute(Bitmap bitmap) { 
      if (isCancelled()) { 
       bitmap = null; 
      } 

      if (imageViewReference != null) { 
       ImageView imageView = imageViewReference.get(); 
       if (imageView != null) { 
        if (bitmap != null) { 
         imageView.setImageBitmap(bitmap); 
        } else { 
         //Drawable placeholder = imageView.getContext().getResources().getDrawable(R.drawable.penguin); 
         //imageView.setImageDrawable(placeholder); 
        } 
       } 

      } 
     } 

     private Bitmap downloadBitmap(String url) { 
      HttpURLConnection urlConnection = null; 
      try { 
       URL uri = new URL(url); 
       urlConnection = (HttpURLConnection) uri.openConnection(); 

       int statusCode = urlConnection.getResponseCode(); 
       if (statusCode != HttpURLConnection.HTTP_OK) { 
        return null; 
       } 

       InputStream inputStream = urlConnection.getInputStream(); 
       if (inputStream != null) { 
        Bitmap bitmap = BitmapFactory.decodeStream(inputStream); 
        return bitmap; 
       } 
      } catch (Exception e) { 
       urlConnection.disconnect(); 
       Log.w("ImageDownloader", "Error downloading image from " + url); 
      } finally { 
       if (urlConnection != null) { 
        urlConnection.disconnect(); 
       } 
      } 
      return null; 
     } 
    } 
+1

那是因为你的被重用和'''AsynkTask'' '有一个重用位图的参考。你必须找到一种方法来在创建新项目时取消任务,或者从AsyncTask中移除ImageView的引用。 – danypata

+0

使用像glide一样的图像加载器库,它为您处理异步加载并缓存图像,以便在用户滚动时不会再次加载 –

回答

0

你必须确保被填充ImageView任务是最目前的任务为ImageView,因为任务可能无法完成,直到ImageView已被回收。

这里就是我所做的:

 if (holder.imageView != null) { 
      Drawable placeholder = holder.imageView.getContext().getResources().getDrawable(R.drawable.penguin); 
      holder.imageView.setImageDrawable(placeholder); 

      ImageDownloaderTask task = new ImageDownloaderTask(holder.imageView); 
      holder.imageView.setTag(R.id.tag_key, task); 
      task.execute(newsItem.getUrl()); 
     } 

...

@Override 
    protected void onPostExecute(Bitmap bitmap) { 
     if (isCancelled()) { 
      bitmap = null; 
     } 

     if (bitmap != null && imageViewReference != null) { 
      ImageView imageView = imageViewReference.get(); 
      if (imageView != null && imageView.getTag(R.id.tag_key) == this) { 
       imageView.setImageBitmap(bitmap); 
       imageView.setTag(R.id.tag_key, null); 
      } 
     } 
    } 

在你的资源:

<?xml version="1.0" encoding="utf-8"?> 
<resources> 
    <item name="tag_key" type="id" /> 
</resources> 
+0

感谢您的回答,但不能指定task.execute的返回值( )到任务。我测试了这个代码,只是将这部分改为'ImgDTask task = new ImgDTask(holder.imageView); (但是这次的图片加载非常晚,如果我滚动他们消失并最近再次加载。看到一个占位符而不是每个图像都有点难看。 – user3717434

+0

好悲伤,我甚至无法在没有IDE的情况下编写工作代码。更新正确代码的答案。所以是的,这不是一个理想的解决方案,但它确实解决了出现错误图像的问题。您的下一步将是为图像设置一个LRUCache,因此当用户再次滚动时不必重新加载它们。或者你可以做一些@ChristianStengel所说的:使用Glide或毕加索并完成它。 –

+0

没有人可以编写没有IDE的工作代码:)谢谢无论如何,我会尝试这种方式。 – user3717434

相关问题