skip to Main Content

It worked fine before I updated my Android Studio to 2020.3.1.
I just discovered that android.graphics.ColorSpace was introduced in Android API 26.
So all the devices which are under Android 8 will throw this exception.
But how could it pass the compile?

Fatal Exception: java.lang.NoClassDefFoundError
Failed resolution of: Landroid/graphics/ColorSpace;
com.facebook.imageutils.ImageMetaData.getColorSpace (ImageMetaData.java:31)
com.facebook.imagepipeline.image.EncodedImage.readImageMetaData (EncodedImage.java:398)
com.facebook.imagepipeline.image.EncodedImage.internalParseMetaData (EncodedImage.java:363)
com.facebook.imagepipeline.image.EncodedImage.parseMetaData (EncodedImage.java:341)
com.facebook.imagepipeline.producers.NetworkFetchProducer.notifyConsumer (NetworkFetchProducer.java:187)
com.facebook.imagepipeline.producers.NetworkFetchProducer.maybeHandleIntermediateResult (NetworkFetchProducer.java:151)
com.facebook.imagepipeline.producers.NetworkFetchProducer.onResponse (NetworkFetchProducer.java:108)
com.facebook.imagepipeline.producers.NetworkFetchProducer$1.onResponse (NetworkFetchProducer.java:75)
com.facebook.imagepipeline.backends.okhttp3.OkHttpNetworkFetcher$2.onResponse (OkHttpNetworkFetcher.java:185)
okhttp3.internal.connection.RealCall$AsyncCall.run (RealCall.java:504)
java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1113)
java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:588)
java.lang.Thread.run (Thread.java:818)

The exception was threw by this method.

private ImageMetaData readImageMetaData() {
    InputStream inputStream = null;
    ImageMetaData metaData = null;
    try {
      inputStream = getInputStream();
      metaData = BitmapUtil.decodeDimensionsAndColorSpace(inputStream);
      mColorSpace = metaData.getColorSpace();
      Pair<Integer, Integer> dimensions = metaData.getDimensions();
      if (dimensions != null) {
        mWidth = dimensions.first;
        mHeight = dimensions.second;
      }
    } finally {
      if (inputStream != null) {
        try {
          inputStream.close();
        } catch (IOException e) {
          // Head in the sand
        }
      }
    }
    return metaData;
  }

But there was already a ColorSpace usage in this method and it did check the API level before using it.

public static ImageMetaData decodeDimensionsAndColorSpace(InputStream is) {
    Preconditions.checkNotNull(is);
    ByteBuffer byteBuffer = DECODE_BUFFERS.acquire();
    if (byteBuffer == null) {
      byteBuffer = ByteBuffer.allocate(DECODE_BUFFER_SIZE);
    }
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    try {
      options.inTempStorage = byteBuffer.array();
      BitmapFactory.decodeStream(is, null, options);

      ColorSpace colorSpace = null;
      if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        colorSpace = options.outColorSpace;
      }
      return new ImageMetaData(options.outWidth, options.outHeight, colorSpace);
    } finally {
      DECODE_BUFFERS.release(byteBuffer);
    }
  }

Here are what I tried.

  1. Gradle clean command.

  2. Build -> Clean project.

  3. Build -> Rebuild project.

  4. Change buildToolsVersion to the latest.

  5. Change androidx.appcompat:appcompat to 2.5.0.

  6. Add multidex-config.txt and multidex-config.pro

But none of these worked.

2

Answers


  1. The problem was in these lines of code.

    ColorSpace colorSpace = null;
    
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        colorSpace = options.outColorSpace;
    }
    

    When a system that does not support that particular class, you can’t refer it’s object at all but you can still declare it. So change to this should work.

    ColorSpace colorSpace;
    
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        colorSpace = options.outColorSpace;
    }
    

    And you will need to adjust the return too. Put it in an if-else statement.

    return new ImageMetaData(options.outWidth, options.outHeight, colorSpace);
    
    Login or Signup to reply.
  2. My team faced the same issue after we migrated our project to Gradle 7.
    We started to see fatal exceptions (java.lang.NoClassDefFoundError) saying that in com.facebook.imageutils.ImageMetaData.getColorSpace (ImageMetaData.java:31) Landroid/graphics/ColorSpace could not be resolved. After a decent amount of coffee, we realized that the app crashes only in release configuration, which means that it has something to do with the proguard configuration. And the guess was right, the following wildcard rule fixed the issue

    -keep class com.facebook.** { *; }
    

    But I wanted to narrow it down to a specific class. So I started digging in usage.txt file (the one generated by proguard, in conjunction with seeds.txt), and this is what I came up with

    -keep class com.facebook.imagepipeline.image.EncodedImage { *; }
    

    I wonder if this will fix the issue you faced as well.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search