2013-04-05 2 views
3

имеют gridView, заполненный растровыми изображениями, которые оживляют, когда битмап загружается асинхронно. Иногда при переключении сетки некоторые элементы не отображаются должным образом. Анимация будет запускаться, но растровое изображение просто не появится.Элементы списка с анимацией не отображаются должным образом

Я подтвердил, что битмап действительно есть (по крайней мере, данные), но он просто не отображает.

Это происходит при быстром прокрутке сетки, но также происходит и при медленном прокрутке. Кажется, что переработка вида не работает должным образом. Вот мой код:

ListView адаптер:

@Override 
    public View getView(int position, View convertView, ViewGroup parent) 
    { 
     if(convertView == null){ 
      convertView = new FlipAnimatedCacheableImage(mContext); 
     } 
     final ImageInfo info = mapItem(getItem(position)); 
     FlipAnimatedCacheableImage image = (FlipAnimatedCacheableImage)convertView; 
     image.resetState(); 
     image.setTitle(info.title); 
     image.setSubTitle(info.subTitle); 
     image.loadImage(info.imgURL, false); 
     return convertView; 
    } 

Код для FlipAnimatedCacheableImage:

public class FlipAnimatedCacheableImage extends FrameLayout 
{ 
    private static final String TAG = FlipAnimatedCacheableImage.class.getCanonicalName(); 
    protected static final long DURATION = 300; 
    private ImageView mPlaceHolder; 
    private NetworkedCacheableImageView mCacheableImage; 
    private View mTextContainer; 
    private TextView mTitleTv; 
    private TextView mSubTitleTv; 
    private View mProgress; 

    private ImageLoadListener mListener = new ImageLoadListener() 
    { 

     private boolean isShown; 


     @Override 
     public void onImageLoaded(boolean animate) 
     { 
      if(animate){ 
       mProgress.setVisibility(View.GONE); 
       mPlaceHolder.setVisibility(View.VISIBLE); 
       mPlaceHolder.setRotationY(0); 
       mCacheableImage.setVisibility(View.VISIBLE); 
       mCacheableImage.setRotationY(-90); 
       mPlaceHolder.animate().rotationY(90).setDuration(DURATION).start(); 
       mCacheableImage.animate().rotationY(0).setDuration(DURATION).setStartDelay(DURATION).start(); 

       if(!TextUtils.isEmpty(mTitleTv.getText()) || !TextUtils.isEmpty(mSubTitleTv.getText())){ 
        mTextContainer.setVisibility(View.VISIBLE); 
        mTextContainer.setAlpha(0); 
        mTextContainer.animate().alpha(1).setDuration(DURATION).setStartDelay(DURATION * 2).start(); 
       } 
       else{ 
        mTextContainer.setVisibility(View.GONE); 
       } 
       isShown = true; 
       FlipAnimatedCacheableImage.this.invalidate(); 
      } 
      else{ 
       mPlaceHolder.setVisibility(View.GONE); 
       mProgress.setVisibility(View.GONE); 
       mCacheableImage.setVisibility(View.VISIBLE); 
       mCacheableImage.setRotationY(0); 
       mCacheableImage.clearAnimation(); 

       if(!TextUtils.isEmpty(mTitleTv.getText()) || !TextUtils.isEmpty(mSubTitleTv.getText())){ 
        mTextContainer.setVisibility(View.VISIBLE); 
        mTextContainer.setAlpha(1); 
       } 
       else{ 
        mTextContainer.setVisibility(View.GONE); 
       } 

       FlipAnimatedCacheableImage.this.invalidate(); 
      } 
     } 
    }; 


    public FlipAnimatedCacheableImage(Context context, boolean isLarge) 
    { 
     this(context, null, 0, isLarge); 
    } 

    public FlipAnimatedCacheableImage(Context context) 
    { 
     this(context, null); 
    } 

    public FlipAnimatedCacheableImage(Context context, AttributeSet attrs) 
    { 
     this(context, attrs, 0, false); 
    } 

    public FlipAnimatedCacheableImage(Context context, AttributeSet attrs, int defStyle, boolean isLarge) 
    { 
     super(context, attrs, defStyle); 
     LayoutInflater inflater = LayoutInflater.from(context); 

     inflater.inflate(R.layout.item_image_thumbnail, this); 

     mCacheableImage = (NetworkedCacheableImageView)this.findViewById(R.id.image_view); 
     mPlaceHolder = (ImageView)this.findViewById(R.id.place_holder); 
     mProgress = this.findViewById(R.id.progressBar); 

     // only used by small images 
     mTextContainer = this.findViewById(R.id.text_container); 
     mTitleTv = (TextView)this.findViewById(R.id.text_title); 
     mSubTitleTv = (TextView)this.findViewById(R.id.text_sub_title); 

     // listener to animate after loading 
     mCacheableImage.setLoadListener(mListener); 

     // set default state 
     mTextContainer.setVisibility(View.GONE); 
     mTitleTv.setVisibility(GONE); 
     mSubTitleTv.setVisibility(GONE); 
     if(isLarge){ 
      // adjust the size to the correct dimensions, ignore titleAnd subTitle 
      FrameLayout.LayoutParams imageParams = new FrameLayout.LayoutParams((int)context.getResources() 
       .getDimension(R.dimen.grid_image_width_large), (int)context.getResources().getDimension(
       R.dimen.grid_image_height_large)); 
      findViewById(R.id.content_wrapper).setLayoutParams(imageParams); 
     } 
     // this.setOnClickListener(listener); 
     resetState(); 

    } 

    public void resetState() 
    { 
     mCacheableImage.setVisibility(View.VISIBLE); 
     mCacheableImage.setRotationY(0); 
     mProgress.setVisibility(View.VISIBLE); 
     mPlaceHolder.setVisibility(View.VISIBLE); 
     mTextContainer.setVisibility(View.GONE); 
     mTitleTv.setVisibility(GONE); 
     mSubTitleTv.setVisibility(GONE); 
    } 


    public boolean loadImage(String url, boolean fullSize) 
    { 
     return mCacheableImage.loadImage(url, fullSize); 
    } 

    public void setTitle(String title) 
    { 
     mTitleTv.setText(title); 
     if(!TextUtils.isEmpty(title)){ 
      mTitleTv.setVisibility(View.VISIBLE); 
     } 
     else{ 
      mTitleTv.setVisibility(View.GONE); 

     } 
    } 

    public void setSubTitle(String subTitle) 
    { 
     mSubTitleTv.setText(subTitle); 
     if(!TextUtils.isEmpty(subTitle)){ 
      mSubTitleTv.setVisibility(View.VISIBLE); 
     } 
     else{ 
      mSubTitleTv.setVisibility(View.GONE); 
     } 
    } 

} 

FlipAnimatedCache запросит изображение из кэша, написанной Крисом Бэйнс здесь https://github.com/chrisbanes/Android-BitmapCache

Здесь является то, что код:

/******************************************************************************* 
* Copyright 2011, 2013 Chris Banes. 
* 
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
* http://www.apache.org/licenses/LICENSE-2.0 
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed under the License is distributed on an "AS IS" BASIS, 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License. 
*******************************************************************************/ 


/** 
* Simple extension of CacheableImageView which allows downloading of Images of 
* the Internet. 
* 
* This code isn't production quality, but works well enough for this sample.s 
* 
* @author Chris Banes 
* 
*/ 
public class NetworkedCacheableImageView extends CacheableImageView 
{ 
    private static final String TAG = NetworkedCacheableImageView.class.getCanonicalName(); 


    public interface ImageLoadListener 
    { 
     public void onImageLoaded(boolean animate); 
    } 

    /** 
    * This task simply fetches an Bitmap from the specified URL and wraps it in 
    * a wrapper. This implementation is NOT 'best practice' or production ready 
    * code. 
    */ 
    private static class ImageUrlAsyncTask extends AsyncTask<String, Void, CacheableBitmapDrawable> 
    { 

     private final BitmapLruCache mCache; 
     private final WeakReference<ImageView> mImageViewRef; 
     private final WeakReference<NetworkedCacheableImageView> viewRef; 
     private final BitmapFactory.Options mDecodeOpts; 

     private final ImageLoadListener mLoadListener; 
     private boolean outOfMemoryFailure; 
     private String mURL; 


     ImageUrlAsyncTask(ImageView imageView, BitmapLruCache cache, BitmapFactory.Options decodeOpts, 
      ImageLoadListener listener, NetworkedCacheableImageView view) 
     { 
      mCache = cache; 
      mLoadListener = listener; 
      mImageViewRef = new WeakReference<ImageView>(imageView); 
      viewRef = new WeakReference<NetworkedCacheableImageView>(view); 
      mDecodeOpts = decodeOpts; 

     } 

     @Override 
     protected CacheableBitmapDrawable doInBackground(String... params) 
     { 
      try{ 
       // Return early if the ImageView has disappeared. 
       if(null == mImageViewRef.get()){ 
        return null; 
       } 

       mURL = params[0]; 

       // Now we're not on the main thread we can check all caches 
       CacheableBitmapDrawable result = mCache.get(mURL, mDecodeOpts); 

       if(null == result){ 
        Log.w("CACHE", "Downloading: " + mURL); 

        // The bitmap isn't cached so download from the web 
        HttpURLConnection conn = (HttpURLConnection)new URL(mURL).openConnection(); 
        InputStream is = new BufferedInputStream(conn.getInputStream()); 

        // Add to cache 
        result = mCache.put(mURL, is, mDecodeOpts); 
       } 
       else{ 
        Log.w("CACHE", "Got from Disk Cache: " + mURL); 
       } 

       return result; 

      } 
      catch(IOException e){ 
       Log.e("Error downloading image", e.toString()); 
      } 
      catch(OutOfMemoryError e){ 
       Log.e(TAG, "running out of memory, trimming image memory cache"); 
       outOfMemoryFailure = true; 
      } 

      return null; 
     } 

     @Override 
     protected void onPostExecute(final CacheableBitmapDrawable result) 
     { 
      // super.onPostExecute(result); 
      if(outOfMemoryFailure || result == null || !result.hasValidBitmap()){ 
       mCache.trimMemory(); 
       // viewRef.get().loadImageAsync(mURL, mDecodeOpts); 
       Log.e(TAG, "image probably did not load::" + mURL); 
      } 
      else{ 
       if(BuildConfig.DEBUG){ 
        Log.d("bitmapCache", "NetworkedCacheableImageView.ImageUrlAsyncTask.onPostExecute() WIDTH:" 
         + result.getBitmap().getWidth()); 
        Log.d("bitmapCache", "NetworkedCacheableImageView.ImageUrlAsyncTask.onPostExecute() HEIGHT:" 
         + result.getBitmap().getHeight()); 

       } 
       Log.i(TAG, "RESULT for :" + mURL + " mImageViewRef::" + mImageViewRef + " outOfMemoryFailure::" 
        + outOfMemoryFailure); 
       if(result != null){ 
        Log.i(TAG, "RESULT object for :" + mURL + " result:hasValidBitmap" + result.hasValidBitmap() 
         + " result:isReferencedByCache" + result.isReferencedByCache() + " result.isBeingDisplayed() " 
         + result.isBeingDisplayed()); 
       } 

       Runnable runnable = new Runnable() 
       { 

        @Override 
        public void run() 
        { 
         if(mImageViewRef != null){ 
          final ImageView iv = mImageViewRef.get(); 
          Log.e(TAG, "RESULT image view reference :" + mURL + " view ref::" + iv); 

          if(null != iv){ 
           iv.setImageDrawable(result); 
           if(mLoadListener != null){ 
            mLoadListener.onImageLoaded(true); 
           } 
          } 

         } 

        } 
       }; 

       Handler handler = new Handler(); 
       handler.postDelayed(runnable, 50); 

      } 
      super.onPostExecute(result); 
     } 
    } 


    private final BitmapLruCache mCache; 
    private ImageUrlAsyncTask mCurrentTask; 
    private ImageLoadListener mListener; 


    public NetworkedCacheableImageView(Context context, AttributeSet attrs) 
    { 
     super(context, attrs); 
     mCache = WatchApplication.getBitmapCache(); 

    } 

    public void setLoadListener(ImageLoadListener listener) 
    { 
     mListener = listener; 
    } 

    public void removeListener() 
    { 
     mListener = null; 
    } 

    /** 
    * Loads the Bitmap. 
    * 
    * @param url 
    *  - URL of image 
    * @param fullSize 
    *  - Whether the image should be kept at the original size 
    * @return true if the bitmap was found in the cache 
    */ 
    public boolean loadImage(String url, final boolean fullSize) 
    { 
     setImageDrawable(null); 
     // First check whether there's already a task running, if so cancel it 
     if(TextUtils.isEmpty(url)) 
      return false; 
     if(null != mCurrentTask){ 
      mCurrentTask.cancel(false); 
     } 

     // Check to see if the memory cache already has the bitmap. We can 
     // safely do 
     // this on the main thread. 
     BitmapDrawable wrapper = mCache.getFromMemoryCache(url); 

     if(null != wrapper){ 
      // The cache has it, so just display it 
      if(BuildConfig.DEBUG){ 
       Log.w(TAG, "CACHE. FOUND IN MEMORY:" + url); 
      } 
      setImageDrawable(wrapper); 
      if(mListener != null){ 
       mListener.onImageLoaded(false); 
      } 
      return true; 
     } 
     else{ 
      // Memory Cache doesn't have the URL, do threaded request... 

      BitmapFactory.Options decodeOpts = null; 

      if(!fullSize){ 
       decodeOpts = new BitmapFactory.Options(); 
       // decodeOpts.inDensity = DisplayMetrics.DENSITY_XHIGH; 
       decodeOpts.inPurgeable = true; 
       decodeOpts.outHeight = this.getHeight(); 
       decodeOpts.outWidth = this.getWidth(); 
      } 

      loadImageAsync(url, decodeOpts); 

      return false; 
     } 
    } 

    public void loadImageAsync(String url, BitmapFactory.Options decodeOpts) 
    { 
     mCurrentTask = new ImageUrlAsyncTask(this, mCache, decodeOpts, mListener, this); 

     if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){ 
      SDK11.executeOnThreadPool(mCurrentTask, url); 
     } 
     else{ 
      mCurrentTask.execute(url); 
     } 
    } 

} 

Заранее благодарим за любую помощь!

ответ

0

Две вещи стоит попробовать -

для построения цепочки анимации операций использует слушатель:

mPlaceHolder.animate() 
    .alpha(0f) 
    .scaleX(0.9f) 
    .scaleY(0.9f) 
    .rotationY(90) 
    .setDuration(DURATION) 
    .setListener(new AnimatorListenerAdapter() { 
       @Override 
       public void onAnimationEnd(Animator animation) { 
        mCacheableImage.setImageDrawable(drawable); 
        mCacheableImage.animate() 
          .alpha(1f) 
          .scaleY(1f) 
          .scaleX(1f) 
          .rotationY(0) 
          .setDuration(DURATION) 
          .setListener(null); 
       } 
    }); 

Использование setHasTransientState() для обеспечения мнение не перерабатывается в ListView/GridView. См. Это DevByte video для получения дополнительной информации.

Смежные вопросы