2014-02-18 66 views
0

我在我的应用程序中使用自定义视图(非常类似于来自Volley的NetworkImageView)。 当我在适配器上膨胀它(例如:在列表视图中)它完美地工作InflateException与自定义视图

我收到一个奇怪的InflateException当我尝试直接使用到Fragment: 它的奇怪,因为类名出现在堆栈

例外不同:

android.view.InflateException: Binary XML file line #8: Error inflating class NetworkImageViewTransformed 
     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:707) 
     at android.view.LayoutInflater.rInflate(LayoutInflater.java:755) 
     at android.view.LayoutInflater.parseInclude(LayoutInflater.java:839) 
     at android.view.LayoutInflater.rInflate(LayoutInflater.java:745) 
     at android.view.LayoutInflater.rInflate(LayoutInflater.java:758) 
     at android.view.LayoutInflater.inflate(LayoutInflater.java:492) 
     at android.view.LayoutInflater.inflate(LayoutInflater.java:397) 
     at com.myapp.fragments.ProfileFragment.onCreateView(ProfileFragment.java:81) 
     at android.support.v4.app.Fragment.performCreateView(Fragment.java:1500) 
     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:927) 
     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104) 
     at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682) 
     at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1467) 
     at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:472) 
     at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141) 
     at android.support.v4.view.ViewPager.populate(ViewPager.java:1068) 
     at android.support.v4.view.ViewPager.populate(ViewPager.java:914) 
     at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1436) 
     at android.view.View.measure(View.java:16497) 
     at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:719) 
     at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:455) 
     at android.view.View.measure(View.java:16497) 
     at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125) 
     at android.widget.FrameLayout.onMeasure(FrameLayout.java:310) 
     at android.view.View.measure(View.java:16497) 
     at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125) 
     at com.android.internal.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:327) 
     at android.view.View.measure(View.java:16497) 
     at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125) 
     at android.widget.FrameLayout.onMeasure(FrameLayout.java:310) 
     at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2291) 
     at android.view.View.measure(View.java:16497) 
     at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:1916) 
     at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1113) 
     at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1295) 
     at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1000) 
     at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5670) 
     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761) 
     at android.view.Choreographer.doCallbacks(Choreographer.java:574) 
     at android.view.Choreographer.doFrame(Choreographer.java:544) 
     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747) 
     at android.os.Handler.handleCallback(Handler.java:733) 
     at android.os.Handler.dispatchMessage(Handler.java:95) 
     at android.os.Looper.loop(Looper.java:136) 
     at android.app.ActivityThread.main(ActivityThread.java:5017) 
     at java.lang.reflect.Method.invoke(Native Method) 
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779) 
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) 
Caused by: java.lang.ClassNotFoundException: Didn't find class "android.view.NetworkImageViewTransformed" on path: DexPathList[[zip file "/data/app/com.myapp-2.apk"],nativeLibraryDirectories=[/data/app-lib/com.myapp-2, /vendor/lib, /system/lib]] 
     at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56) 
     at java.lang.ClassLoader.loadClass(ClassLoader.java:511) 
     at java.lang.ClassLoader.loadClass(ClassLoader.java:469) 
     at android.view.LayoutInflater.createView(LayoutInflater.java:559) 
     at android.view.LayoutInflater.onCreateView(LayoutInflater 

而这里的我的XML(部分):

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent" 
android:layout_height="match_parent"> 

<com.myapp.views.TransformedNetworkImageView 
    android:layout_width="120dp" 
    android:layout_height="120dp" 
    android:id="@+id/blur_picture" 
    android:layout_gravity="top" 
    /> 
</FrameLayout> 

由于y OU可以看到我的观应该是com.myapp.views.TransformedNetworkImageView一个实例,但堆栈reffers到NetworkImageViewTransformedandroid.view.NetworkImageViewTransformed

我已经尝试缓存失效;干净重建;重新启动Android studio ...没有任何变化。

编辑onCreateView(在通货膨胀崩溃):

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
    View view = inflater.inflate(R.layout.fragment_profile, container, false); 


    mBlurPicture = (TransformedNetworkImageView) view.findViewById(R.id.blur_picture); 
    ..... 
    return view; 
} 

这里的TransformedNetworkImageView的完整代码:

public class TransformedNetworkImageView extends ImageView { 
/** 
* Interface to transform the bitmap image before the draw 
*/ 
public static interface OnBitmapDisplayedListener { 
    public Bitmap onBitmapDisplayed(Bitmap downloadedBitmap); 
} 

/** The URL of the network image to load */ 
private String mUrl; 

/** 
* Resource ID of the image to be used as a placeholder until the network image is loaded. 
*/ 
private int mDefaultImageId; 

/** 
* Resource ID of the image to be used if the network response fails. 
*/ 
private int mErrorImageId; 

/** Local copy of the ImageLoader. */ 
private ImageLoader mImageLoader; 

/** Current ImageContainer. (either in-flight or finished) */ 
private ImageContainer mImageContainer; 


private OnBitmapDisplayedListener mBitmapDisplayedListener; 

public TransformedNetworkImageView(Context context) { 
    this(context, null); 
    init(); 
} 

public TransformedNetworkImageView(Context context, AttributeSet attrs) { 
    this(context, attrs, 0); 
    init(); 
} 

public TransformedNetworkImageView(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 
    init(); 
} 


/** 
* Sets URL of the image that should be loaded into this view. Note that calling this will 
* immediately either set the cached image (if available) or the default image specified by 
* {@link TransformedNetworkImageView#setDefaultImageResId(int)} on the view. 
* 
* NOTE: If applicable, {@link TransformedNetworkImageView#setDefaultImageResId(int)} and 
* {@link TransformedNetworkImageView#setErrorImageResId(int)} should be called prior to calling 
* this function. 
* 
* @param url The URL that should be loaded into this ImageView. 
* @param imageLoader ImageLoader that will be used to make the request. 
*/ 
public void setImageUrl(String url, ImageLoader imageLoader) { 
    mUrl = url; 
    mImageLoader = imageLoader; 
    // The URL has potentially changed. See if we need to load it. 
    loadImageIfNecessary(false); 
} 

/** 
* Sets the default image resource ID to be used for this view until the attempt to load it 
* completes. 
*/ 
public void setDefaultImageResId(int defaultImage) { 
    mDefaultImageId = defaultImage; 
} 

/** 
* Sets the error image resource ID to be used for this view in the event that the image 
* requested fails to load. 
*/ 
public void setErrorImageResId(int errorImage) { 
    mErrorImageId = errorImage; 
} 

/** 
* Loads the image for the view if it isn't already loaded. 
* @param isInLayoutPass True if this was invoked from a layout pass, false otherwise. 
*/ 
void loadImageIfNecessary(final boolean isInLayoutPass) { 
    int width = getWidth(); 
    int height = getHeight(); 

    boolean wrapWidth = false, wrapHeight = false; 
    if (getLayoutParams() != null) { 
     wrapWidth = getLayoutParams().width == LayoutParams.WRAP_CONTENT; 
     wrapHeight = getLayoutParams().height == LayoutParams.WRAP_CONTENT; 
    } 

    // if the view's bounds aren't known yet, and this is not a wrap-content/wrap-content 
    // view, hold off on loading the image. 
    boolean isFullyWrapContent = wrapWidth && wrapHeight; 
    if (width == 0 && height == 0 && !isFullyWrapContent) { 
     return; 
    } 

    // if the URL to be loaded in this view is empty, cancel any old requests and clear the 
    // currently loaded image. 
    if (TextUtils.isEmpty(mUrl)) { 
     if (mImageContainer != null) { 
      mImageContainer.cancelRequest(); 
      mImageContainer = null; 
     } 
     setDefaultImageOrNull(); 
     return; 
    } 

    // if there was an old request in this view, check if it needs to be canceled. 
    if (mImageContainer != null && mImageContainer.getRequestUrl() != null) { 
     if (mImageContainer.getRequestUrl().equals(mUrl)) { 
      // if the request is from the same URL, return. 
      return; 
     } else { 
      // if there is a pre-existing request, cancel it if it's fetching a different URL. 
      mImageContainer.cancelRequest(); 
      setDefaultImageOrNull(); 
     } 
    } 

    // Calculate the max image width/height to use while ignoring WRAP_CONTENT dimens. 
    int maxWidth = wrapWidth ? 0 : width; 
    int maxHeight = wrapHeight ? 0 : height; 

    // The pre-existing content of this view didn't match the current URL. Load the new image 
    // from the network. 
    ImageContainer newContainer = mImageLoader.get(mUrl, 
      new ImageListener() { 
       @Override 
       public void onErrorResponse(VolleyError error) { 
        if (mErrorImageId != 0) { 
         setImageBitmap(mBitmapDisplayedListener.onBitmapDisplayed(
           BitmapFactory.decodeResource(getContext().getResources(), 
             mErrorImageId))); 
        } 
       } 

       @Override 
       public void onResponse(final ImageContainer response, boolean isImmediate) { 
        // If this was an immediate response that was delivered inside of a layout 
        // pass do not set the image immediately as it will trigger a requestLayout 
        // inside of a layout. Instead, defer setting the image by posting back to 
        // the main thread. 
        if (isImmediate && isInLayoutPass) { 
         post(new Runnable() { 
          @Override 
          public void run() { 
           onResponse(response, false); 
          } 
         }); 
         return; 
        } 

        if (response.getBitmap() != null) { 
         setImageBitmap(mBitmapDisplayedListener.onBitmapDisplayed(
                   response.getBitmap())); 
        } else if (mDefaultImageId != 0) { 
         setImageBitmap(mBitmapDisplayedListener.onBitmapDisplayed(
          BitmapFactory.decodeResource(getContext().getResources(), 
            mDefaultImageId))); 
        } 
       } 
      }, maxWidth, maxHeight); 

    // update the ImageContainer to be the new bitmap container. 
    mImageContainer = newContainer; 
} 


/** 
* Initiate the default bitmap transformation listener 
*/ 
private void init() { 
    setOnBitmapDisplayedListener(new OnBitmapDisplayedListener() { 
     @Override 
     public Bitmap onBitmapDisplayed(final Bitmap downloadedBitmap) { 
      return downloadedBitmap; 
     } 
    }); 
} 

public void setOnBitmapDisplayedListener(OnBitmapDisplayedListener listener) { 
    mBitmapDisplayedListener = listener; 
} 

private void setDefaultImageOrNull() { 
    if(mDefaultImageId != 0) { 
     setImageBitmap(mBitmapDisplayedListener.onBitmapDisplayed(
       BitmapFactory.decodeResource(getContext().getResources(), 
         mDefaultImageId)));  } 
    else { 
     setImageBitmap(null); 
    } 
} 

@Override 
protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 
    super.onLayout(changed, left, top, right, bottom); 
    loadImageIfNecessary(true); 
} 

@Override 
protected void onDetachedFromWindow() { 
    if (mImageContainer != null) { 
     // If the view was bound to an image request, cancel it and clear 
     // out the image from the view. 
     mImageContainer.cancelRequest(); 
     setImageBitmap(null); 
     // also clear out the container so we can reload the image if necessary. 
     mImageContainer = null; 
    } 
    super.onDetachedFromWindow(); 
} 

@Override 
protected void drawableStateChanged() { 
    super.drawableStateChanged(); 
    invalidate(); 
} 
} 
+2

你可以从ProfileFragment发布onCreateView吗? – Blackbelt

+0

你可以发布你的TransformedNetworkImageView类吗? – nurisezgin

+0

我用代码编辑过,但正如我所说,视图在一个adpater中工作... – Arnaud

回答

2

这是绝对是一个缓存的问题,由于Android的工作室...

仅供参考:我关闭了我的项目,关闭了IDE,启动了./gradlew clean并重新启动以使其正常工作。