bumptech / glide

An image loading and caching library for Android focused on smooth scrolling
https://bumptech.github.io/glide/
Other
34.67k stars 6.12k forks source link

can't get a local gif's first frame secondly #2158

Closed EGOISTK21 closed 7 years ago

EGOISTK21 commented 7 years ago

Glide Version: 4.0.0-RC1

Integration libraries: I load a local file.

Device/Android Version: Nexus 5X 7.1.2

Issue details / Repro steps / Use case background: Fail to get the firstFrame of a gif when I load it at second time.

When I get a gif path like "/storage/emulated/0/bluetooth/giphy.gif", I load it with as a gifDrawable and into an ImageView viewTarget(com.bumptech.glide.request.target.ViewTarget). Then I get its firstFrame, it works at the first time. But when I load from the same path secondly, the firstFrame is null.

Glide load line / GlideModule (if any) / list Adapter code (if any):

Glide.with...
try {
    switch (FileUtil.getType(path)) {
        case GIF:
            Glide.with(this)
                    .asGif()
                    .apply(new RequestOptions().diskCacheStrategy(DiskCacheStrategy.RESOURCE))
                    .load(path)
                    .into(new ViewTarget<ImageView, GifDrawable>(mImageView) {
                        @Override
                        public void onResourceReady(GifDrawable gifDrawable, Transition<? super GifDrawable> transition) {
                            Log.e(TAG, "onResourceReady: " + gifDrawable.getFrameCount() + "\n" + gifDrawable.getSize());
                            int gWidth = gifDrawable.getIntrinsicWidth();
                            int gHeight = gifDrawable.getIntrinsicHeight();
                            Point size = new Point();
                            getWindowManager().getDefaultDisplay().getSize(size);
                            ViewGroup.LayoutParams para = mImageView.getLayoutParams();
                            para.width = size.y * (size.x < size.y ? 1 : 3 / 5) * gWidth / gHeight;
                            if (size.x * (size.x < size.y ? 1 : 3 / 5) * gHeight / gWidth > gHeight)
                                para.height = gHeight;
                            mImageView.setLayoutParams(para);
                            mImageView.setImageDrawable(gifDrawable);
                            gifDrawable.start();
                            Log.i(TAG, "glide:" +
                                    " gWidth: " + gWidth + " gHeight: " + gHeight +
                                    " wWidth: " + size.x + " wHeight: " + size.y +
                                    " ivWidth: " + para.width + " ivHeight: " + para.height);
                        }
                    });
            break;
        case JPEG:
        case PNG:
        case BMP:
        default:
            Glide.with(this)
                    .asBitmap()
                    .load(path)
                    .into(new ViewTarget<ImageView, Bitmap>(mImageView) {
                        @Override
                        public void onResourceReady(Bitmap bitmap, Transition<? super Bitmap> transition) {
                            if (bitmap == null) return;
                            int bWidth = bitmap.getWidth();
                            int bHeight = bitmap.getHeight();
                            Point size = new Point();
                            getWindowManager().getDefaultDisplay().getSize(size);
                            ViewGroup.LayoutParams para = mImageView.getLayoutParams();
                            para.width = size.y * (size.x < size.y ? 1 : 3 / 5) * bWidth / bHeight;
                            if (size.x * (size.x < size.y ? 1 : 3 / 5) * bHeight / bWidth > bHeight)
                                para.height = bHeight;
                            mImageView.setLayoutParams(para);
                            mImageView.setImageBitmap(bitmap);
                            Log.i(TAG, "glide:" +
                                    " bWidth: " + bWidth + " bHeight: " + bHeight +
                                    " wWidth: " + size.x + " wHeight: " + size.y +
                                    " ivWidth: " + para.width + " ivHeight: " + para.height);
                        }
                    });
            break;
    }
} catch (IOException e) {
    e.printStackTrace();
}

Layout XML:

<FrameLayout xmlns:android="...

title_main.xml

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rl_title_bar"
    android:layout_width="match_parent"
    android:layout_height="@dimen/common_title_bar_height_48"
    android:background="@color/colorPrimary">

    <TextView
        android:id="@+id/tv_history"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_alignParentStart="true"
        android:gravity="center"
        android:paddingEnd="@dimen/common_padding_15"
        android:paddingStart="@dimen/common_padding_15"
        android:text="@string/history"
        android:textColor="@color/colorWhite"
        android:textSize="@dimen/common_title_bar_text_size_16"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="@string/main_title"
        android:textColor="@color/colorWhite"
        android:textSize="@dimen/common_title_bar_text_size_16"/>

    <TextView
        android:id="@+id/tv_delete"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_alignParentEnd="true"
        android:gravity="center"
        android:paddingEnd="@dimen/common_padding_15"
        android:paddingStart="@dimen/common_padding_15"
        android:text="@string/delete"
        android:textColor="@color/colorWhite"
        android:textSize="@dimen/common_title_bar_text_size_16"/>

</RelativeLayout>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorBackground"
    tools:context="net.cat.smms_android.main.MainActivity">

    <include
        android:id="@+id/rl_title_bar"
        layout="@layout/title_main"/>

    <ImageView
        android:id="@+id/iv_selector_preview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/btn_upload"
        android:layout_below="@+id/rl_title_bar"
        android:layout_centerHorizontal="true"
        android:layout_margin="@dimen/common_margin_15"/>

    <ProgressBar
        android:id="@+id/pb"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:visibility="gone"/>

    <Button
        android:id="@+id/btn_upload"
        android:layout_width="@dimen/common_button_width"
        android:layout_height="@dimen/common_button_height"
        android:layout_above="@+id/tv_url"
        android:layout_centerHorizontal="true"
        android:text="@string/upload"
        android:textAllCaps="false"
        android:textSize="@dimen/common_button_text_size_16"/>

    <TextView
        android:id="@+id/tv_url"
        android:layout_width="match_parent"
        android:layout_height="64dp"
        android:layout_alignParentBottom="true"
        android:gravity="center"
        android:hint="@string/sample_url"
        android:textSize="@dimen/common_url_text_size_14"/>

</RelativeLayout>

activity_main.xml (land)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorBackground"
    tools:context="net.cat.smms_android.main.MainActivity">

    <include
        android:id="@+id/rl_title_bar"
        layout="@layout/title_main"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/rl_title_bar"
        android:orientation="horizontal"
        android:weightSum="5">

        <ImageView
            android:id="@+id/iv_selector_preview"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_margin="@dimen/common_margin_15"
            android:layout_weight="3"/>

        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_margin="@dimen/common_margin_15"
            android:layout_weight="2">

            <Button
                android:id="@+id/btn_upload"
                android:layout_width="@dimen/common_button_width"
                android:layout_height="@dimen/common_button_height"
                android:layout_centerHorizontal="true"
                android:layout_marginBottom="30dp"
                android:layout_marginTop="30dp"
                android:text="@string/upload"
                android:textAllCaps="false"
                android:textSize="@dimen/common_button_text_size_16"/>

            <TextView
                android:id="@+id/tv_url"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_below="@id/btn_upload"
                android:layout_centerHorizontal="true"
                android:gravity="center"
                android:hint="@string/sample_url"
                android:textSize="@dimen/common_url_text_size_14"/>

            <ProgressBar
                android:id="@+id/pb"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:visibility="gone"/>

        </RelativeLayout>

    </LinearLayout>

</RelativeLayout>

Stack trace / LogCat:

paste stack trace and/or log here
net.cat.smms_android E/AndroidRuntime: FATAL EXCEPTION: main
    Process: net.cat.smms_android, PID: 23558
    java.lang.RuntimeException: Unable to resume activity {net.cat.smms_android/net.cat.smms_android.main.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3454)
    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3494)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1546)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6186)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
    Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
    at net.cat.smms_android.main.MainActivity$1.onResourceReady(MainActivity.java:100)
    at net.cat.smms_android.main.MainActivity$1.onResourceReady(MainActivity.java:95)
    at com.bumptech.glide.request.SingleRequest.onResourceReady(SingleRequest.java:521)
    at com.bumptech.glide.request.SingleRequest.onResourceReady(SingleRequest.java:495)
    at com.bumptech.glide.load.engine.Engine.load(Engine.java:167)
    at com.bumptech.glide.request.SingleRequest.onSizeReady(SingleRequest.java:416)
    at com.bumptech.glide.request.target.ViewTarget$SizeDeterminer.getSize(ViewTarget.java:206)
    at com.bumptech.glide.request.target.ViewTarget.getSize(ViewTarget.java:68)
    at com.bumptech.glide.request.SingleRequest.begin(SingleRequest.java:222)
    at com.bumptech.glide.manager.RequestTracker.runRequest(RequestTracker.java:39)
    at com.bumptech.glide.RequestManager.track(RequestManager.java:448)
    at com.bumptech.glide.RequestBuilder.into(RequestBuilder.java:365)
    at net.cat.smms_android.main.MainActivity.showImg(MainActivity.java:95)
    at net.cat.smms_android.main.MainActivity.onResume(MainActivity.java:188)
    at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1270)
    at android.app.Activity.performResume(Activity.java:6788)
    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3431)
    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3494) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1546) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:154) 
    at android.app.ActivityThread.main(ActivityThread.java:6186) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779) 
sjudd commented 7 years ago

guarantee in the API that getFirstFrame will return a non-null Bitmap.

sjudd commented 7 years ago

Wups: There's no guarantee in the API that getFirstFrame will return a non-null Bitmap.

EGOISTK21 commented 7 years ago

but it works well in Glide 3.7.0

saket commented 6 years ago

@sjudd in what situations will the first frame be null?

sjudd commented 6 years ago

The first frame is cleared after its displayed once. The API only exists as hack to allow us to have something to show during an animation. For example if you specify a cross fade and the GifDrawable hasn't loaded a frame yet, the cross fade will run from your placeholder to nothing. Keeping track of the first frame until the second frame is loaded lets us animate correctly without the extra memory overhead of keeping the first frame in memory for the life of the request.

Because the first frame is cleared after the second frame is loaded, it's basically never safe to assume that it's non-null.

saket commented 6 years ago

Ah understood. I have a usecase where I want to tint my screen's colors according to the image. This works fine for static images, but for GIFs the first frame is occasionally null. Is there a better way to do this?