2016-05-12 89 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

相關問題