web analytics

Android Code : Glide Progressive ทำให้ระหว่างโหลดรูปแสดงเปอร์เซ็น

cover

บทคามนี้มาแชร์ code ครับ ผมมีโอกาสได้ทำ Glide ให้โหลดรูปแล้วแสดงเปอร์เซ็น แฮ่ไม่เคยทำ กว่าจะหาในอินเตอร์เน็ตได้ก็นานเลย โชคดีมีพี่ๆมาแนะนำ เลยมาเขียนบันทึก สรุปสักหน่อย

 

เพิ่ม permission ใช้ internet (เผื่อจะลืม) ใน AndroidManifest.xml

 <uses-permission android:name="android.permission.INTERNET" />
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

 

กำหนด dependencies ไลบรารี่ มี 3 ตัวดังนี้

    compile 'com.squareup.okhttp3:okhttp:3.3.1'
    compile 'com.github.bumptech.glide:okhttp3-integration:1.4.0@aar'
    compile 'com.github.bumptech.glide:glide:3.7.0'

 

ต่อมาสร้าง layout ซึ่งตัวอย่างนี้ผมจะมี
ProgressBar ตัวนึงไว้บอกความคืบหน้า
TextView ไว้แสดงเปอรเซ็น
ImageView ไว้แสดงรูป เมื่อโหลดเสร็จ

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"
    tools:context="com.benzneststudios.library.glideprogressive.MainActivity">

    <ImageView
        android:id="@+id/imgV"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
    <ProgressBar
        android:id="@+id/progress_bar"
        android:layout_width="300dp"
        android:layout_height="40dp"
        android:layout_marginTop="40dp"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:layout_centerHorizontal="true"/>
    <TextView
        android:id="@+id/tv_progress"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="0%"
        android:textSize="32sp"
        android:layout_below="@id/progress_bar"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="8dp"/>
</RelativeLayout>

1

 

ต่อมาคือใช้ OkHttpCient ใส่ไปกับ register ของ Glide
ซึ่ง okHttpClient ก็ใส่ interceptor เอาไว้ เกี่ยวกับการ listener update ขณะโหลด

GlideProgressive.java

public class GlideProgressive {
    Context context;
    OkHttpClient.Builder okClient;
    ProgressListener progressListener;

    private GlideProgressive() {
    }

    public GlideProgressive(Context context) {
        this.context = context;
    }

    public interface ProgressListener {
        void update(long bytesRead, long contentLength, boolean done);
    }

    public void setProgressListener(final ProgressListener progressListener) {
        this.progressListener = progressListener;

        okClient = new OkHttpClient.Builder()
                .addInterceptor(new Interceptor() {
                    @Override
                    public Response intercept(Chain chain) throws IOException {
                        Response originalResponse = chain.proceed(chain.request());
                        return originalResponse.newBuilder()
                                .body(new ProgressResponseBody(originalResponse.body(), progressListener))
                                .build();
                    }
                });
        
        Glide.get(context)
                .register(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(okClient.build()));
    }

    public void startDownload(String url, ImageView img) {
        Glide.with(context)
                .load(url)
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .into(img);
    }

    private static class ProgressResponseBody extends ResponseBody {

        private final ResponseBody responseBody;
        private final ProgressListener progressListener;
        private BufferedSource bufferedSource;

        public ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) {
            this.responseBody = responseBody;
            this.progressListener = progressListener;
        }

        @Override
        public MediaType contentType() {
            return responseBody.contentType();
        }

        @Override
        public long contentLength() {
            return responseBody.contentLength();
        }

        @Override
        public BufferedSource source() {
            if (bufferedSource == null) {
                bufferedSource = Okio.buffer(source(responseBody.source()));
            }
            return bufferedSource;
        }

        private Source source(Source source) {
            return new ForwardingSource(source) {
                long totalBytesRead = 0L;

                @Override
                public long read(Buffer sink, long byteCount) throws IOException {
                    long bytesRead = super.read(sink, byteCount);
                    // read() returns the number of bytes read, or -1 if this source is exhausted.
                    totalBytesRead += bytesRead != -1 ? bytesRead : 0;
                    progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
                    return bytesRead;
                }
            };
        }
    }
}

 

ทีนี้เราก็สามารถกำหนดว่าขณะโหลดให้ update อะไร โดยการสร้าง object GlideProgressive แล้วเพิ่ม listener ให้มัน เป็นอันเรียบร้อย

        GlideProgressive progressive = new GlideProgressive(context);
        progressive.setProgressListener(new GlideProgressive.ProgressListener() {
            @Override
            public void update(long bytesRead, long contentLength, boolean done) {
                // do something.
            }
        });

 

ถ้ามีการอัพเดท UI ต้องใช้คำสั่ง runOnUiThread เพราะ Glide มันรันบน Background thread

GlideProgressive progressive = new GlideProgressive(MainActivity.this);
        progressive.setProgressListener(new GlideProgressive.ProgressListener() {
            @Override
            public void update(long bytesRead, long contentLength, boolean done) {
                MainActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        // Update UI.
                    }
                });
            }
        });

 

เสร็จแล้วเรียกคำสั่ง

progressive.startDownload(url, imgView);

 

สรุป
MainActivity.java

public class MainActivity extends AppCompatActivity {

    ImageView img;
    TextView tvProgress;
    ProgressBar progressBarLoading;

    String url = "https://static.pexels.com/photos/4164/landscape-mountains-nature-mountain.jpeg";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        img = (ImageView) findViewById(R.id.imgV);
        progressBarLoading = (ProgressBar) findViewById(R.id.progress_bar);
        tvProgress = (TextView) findViewById(R.id.tv_progress);

        GlideProgressive progressive = new GlideProgressive(MainActivity.this);
        progressive.setProgressListener(new GlideProgressive.ProgressListener() {
            @Override
            public void update(long bytesRead, long contentLength, boolean done) {
                final int progress = (int) ((100 * bytesRead) / contentLength);
                MainActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        progressBarLoading.setProgress(progress);
                        tvProgress.setText(progress+"%");
                        if (progress >= 100) {
                            progressBarLoading.setVisibility(View.GONE);
                            tvProgress.setVisibility(View.GONE);
                        }
                    }
                });
            }
        });

        progressive.startDownload(url, img);
    }
}

 

ผลลัพธ์

ก็จะได้ progress bar โหลดรูปมาแล้ว

a1

 

เสร็จแล้ว ยังไงก็ลองเอาไปประยุกต์ใช้ดูนะครับ

(:

 

Reference

https://gist.github.com/fbis251/cfa169fd9e1e142e042c
ขอบคุณพี่แบงค์ที่ให้คำแนะนำครับ