ตัวอย่างการใช้ Picasso มาช่วยแก้ปัญหารูปภาพใน Android

ตัวอย่างการใช้ Picasso มาช่วยแก้ปัญหารูปภาพใน Android Cover Image

วันนี้ขอนำเสนอบทความเกี่ยวกับ Image Library ครับ คือการใช้ Picasso มาช่วยแก้ปัญหาในการแสดงผลรูปภาพ ImageView กันครับ ก่อนหน้านี้ผมเคยพูดถึง Library อีกตัวไปแล้ว ที่ชื่อว่า Universal Image Loader

คุณเคยไหมที่เวลาใช้ ImageView บางครั้งโปรแกรมปิดตัว เกิดอาการ OutofMemory ต้องทำการปรับ BitmapFactory.Options เอง นั่งคำนวณ ขนาดเอง หรือลดขนาดรูปภาพตามความเหมาะสม หรืออีกกรณีเวลาโหลดรูปภาพจากเว็บไซต์ อยากให้มัน cache ลงเครื่องด้วย โดยปกติเราจำเป็นต้องตั้งค่าและเขียนเองทั้งหมด เพื่อให้รองรับปัญหาต่างๆ วันนี้เจ้า Picasso มันจะมาแก้ปัญหาเหล่านี้ให้ท่านครับ

Picasso คืออะไร?

จากในเว็บเขียนอธิบายว่า A powerful image downloading and caching library for Android มันก็คือ Library ของแอนดรอยส์เกี่ยวกับการจัดการรูปภาพ ดาวน์โหลดรูปภาพ และมีการ cach รูปภาพให้นั่นเอง รายละเอียดเพิ่มเติม อ่านได้จากเว็บไซต์ต้นฉบับที่นี่ Picasso

เวอร์ชันในขณะเขียนบทความนี้คือ Picasso 2.3.2

ขั้นตอนการใช้งาน

มีด้วยกัน 2 ออปชั่น คือ จะโหลดเป็นไฟล์ .jar หรือว่าจะใช้ maven

  • โหลดแบบ .jar : ดาวน์โหลดโดยตรงได้จากลิงค์นี้ Download Picasso-2.3.2.jar หรือจะเข้าไปในหน้าเว็บไซต์หลัก แล้วเลือกส่วน Download ก็ได้

  • ใช้ maven

<dependency>
  <groupId>com.squareup.picasso</groupId>
  <artifactId>picasso</artifactId>
  <version>2.3.2</version>
</dependency>

วิธีการใช้งานก็ง่ายมากๆ ตามโค๊ดนี้

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
  • with() : โหลดด้วย Context ของ activity
  • load() : parameter URI ของไฟล์, รูปใน drawable หรือว่า File ก็ได้
  • into() : parameter คือ ImageView ที่เราต้องการจะให้มันแสดง

Options เพิ่มเติม ก็พวก

  • resize() : สำหรับเปลี่ยนขนาดรูป
  • centerCrop() : จัดภาพกึ่งกลางแบบ center crop
  • placeholder() : สำหรับใส่รูป placeholder
  • error() : ใส่รูป default กรณีที่เกิด error โหลดรูปไม่ได้
  • transform() : transform effect
  • rotate() : effect สำหรับหมุนรูปภาพ

ส่วน option อื่นๆ ก็ดูเพิ่มเติมที่เว็บไซต์หลักเลย ในส่วนรายละเอียดที่ไม่ได้เกี่ยวข้องกับ Picasso จะไม่ขอพูดถึงในบทความนี้นะครับ หากเรื่องไหนไม่เ้ข้าใจ ก็ลองค้นหาที่กล่องค้นหาของเว็บนี้ หรือ google ครับ

เริ่มต้นสร้างโปรเจ็ค

ทำการสร้างโปรเจ็คขึ้นมาใหม่ ในตัวอย่างนี้ผมใช้ Android Studio เมื่อสร้างโปรเจ็คใหม่ จะได้ไฟล์ structure ประมาณนี้

├── build
├── build.gradle
├── libs
├── proguard-rules.pro
└── src
    ├── androidTest
    │   └── java
    └── main
        ├── AndroidManifest.xml
        ├── java
            └── com
                └── devahoy
                    └── picassoexample
                        └── MainActivity.java
        └── res
            ├── drawable-hdpi
            ├── drawable-mdpi
            ├── drawable-xhdpi
            ├── drawable-xxhdpi
            ├── layout
            ├── menu
            ├── values
            └── values-w820dp   

เปิด build.gradle ขึ้นมาเพื่อทำการเพิ่ม Library เข้าไป ดังนี้

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:19.+'
    compile 'com.squareup.picasso:picasso:2.3.2'
}

หากใครดาวน์โหลดแบบ .jar ไฟล์มา ก็ไม่ต้องเพิ่ม compile 'com.squareup.picasso:picasso:2.3.2' แต่ว่าให้ก็อบไฟล์ .jar ไว้ในโฟลเดอร์ /libs แทน เนื่องจากคอนฟิค fileTree ไว้แล้ว

สำหรับ Eclipse ก็ก็อบไฟล์ .jar ไว้ที่โฟลเดอร์ /libs เช่นกัน แล้วคลิ๊กขวาเลือก Build Path -> Add to Build Path

เริ่มต้นทำแอพจริง

ตัวอย่างนี้คือจะโหลดรูปภาพจากเว็บไซต์ dribbble มาแสดงในแอพแบบ GridView เริ่มต้นผมก็ทำการสร้าง GridViewAdapter.java ขึ้นมา และไฟล์เลเอาท์ ก็ใช้ activity_main.xml อันเดิม ส่วน grid_item.xml เอาไว้ปรับ ImageView ใน GridView

หากใครไม่เข้าใจ GridView ให้อ่านบทความนี้ประกอบ ตัวอย่างการใช้งาน GridView บน Android อย่างง่าย

ไฟล์ GridViewAdapter.java เป็นแบบนี้

package com.devahoy.picassoexample;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;

import com.squareup.picasso.Picasso;

public class GridViewAdapter extends BaseAdapter {
    private Context mContext;
    private String[] mUrls;
    private LayoutInflater mInflater;

    public GridViewAdapter(Context context, String[] urls) {
        mContext = context;
        mUrls = urls;
        mInflater = LayoutInflater.from(context);
    }

    public int getCount() {
        return mUrls.length;
    }

    public Object getItem(int position) {
        return null;
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {

        final ViewHolder viewHolder;

        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.grid_item, parent, false);
            viewHolder = new ViewHolder();

            viewHolder.imageView = (ImageView)
                    convertView.findViewById(R.id.grid_item);

            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        Picasso.with(mContext).load(mUrls[position]).into(viewHolder.imageView);
        return convertView;
    }

    public class ViewHolder {
        ImageView imageView;
    }

}

ส่วนไฟล์ activity_main.xml เป็นแบบนี้

<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=".MainActivity">

        <GridView
            android:id="@+id/gridview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:columnWidth="80dp"
            android:gravity="center"
            android:verticalSpacing="0dp"
            android:horizontalSpacing="0dp"
            android:numColumns="auto_fit"
            android:stretchMode="columnWidth"/>

</RelativeLayout>

และไฟล์ grid_item.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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">

    <ImageView
        android:id="@+id/grid_item"
        android:layout_width="100dp"
        android:layout_height="80dp"
        android:scaleType="centerCrop"/>

</FrameLayout>

เพิ่มส่วน res/values/strings.xml ไปนิดหน่อย

<string name="button_next">NEXT</string>
<string name="button_previous">PREVIOUS</string>

ส่วนสุดท้าย ไฟล์ MainActivity.java ไม่มีอะไรมาก แค่สร้าง GridView และ GridViewAdapter เท่านั้น ก็จะได้แบบนี้

ไฟล์ MainActivity.java

package com.devahoy.picassoexample;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.GridView;


public class MainActivity extends ActionBarActivity {

    private GridViewAdapter mAdapter;
    private GridView mGridView;

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

        String[] urls = initSampleData();
        mGridView = (GridView) findViewById(R.id.gridview);
        mAdapter = new GridViewAdapter(this, urls);
        mGridView.setAdapter(mAdapter);
    }

    private String[] initSampleData() {
        return new String[] {
                "https://d13yacurqjgara.cloudfront.net/users/3460/screenshots/1628158/animal-stickers_1x.png",
                "https://d13yacurqjgara.cloudfront.net/users/14521/screenshots/1628431/designers_wanted_2_1x.png",
                "https://d13yacurqjgara.cloudfront.net/users/57127/screenshots/1628433/kickstarterproject_1x.jpg",
                "https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/1628196/enter_1x.gif",
                "https://d13yacurqjgara.cloudfront.net/users/32336/screenshots/1627983/dribbble3_1x.png",
                "https://d13yacurqjgara.cloudfront.net/users/254554/screenshots/1628567/20140703--satellit2_1x.gif",
                "https://d13yacurqjgara.cloudfront.net/users/144388/screenshots/1628118/table-creative-dribbble_1x.gif",
                "https://d13yacurqjgara.cloudfront.net/users/13307/screenshots/1628973/logotypes_1x.jpg",
                "https://d13yacurqjgara.cloudfront.net/users/45269/screenshots/1628472/workspace_1x.gif",
                "https://d13yacurqjgara.cloudfront.net/users/124059/screenshots/1627992/search-filter_1x.gif",
                "https://d13yacurqjgara.cloudfront.net/users/3375/screenshots/1628760/btt_cody_forever_1x.gif",
                "https://d13yacurqjgara.cloudfront.net/users/79978/screenshots/1628721/koltozzbe.hu_2_1x.png",
                "https://d13yacurqjgara.cloudfront.net/users/51395/screenshots/1628377/mercedes_minisite_1x.jpg",
                "https://d13yacurqjgara.cloudfront.net/users/465131/screenshots/1628903/rpg_1x.jpg",
                "https://d13yacurqjgara.cloudfront.net/users/267247/screenshots/1628670/prayer_app_1x.png",
                "https://d13yacurqjgara.cloudfront.net/users/303896/screenshots/1628068/sitepreview_1x.png",
                "https://d13yacurqjgara.cloudfront.net/users/9964/screenshots/1628170/crank-it-up_1x.png",
                "https://d13yacurqjgara.cloudfront.net/users/155551/screenshots/1628228/icons_1x.png",
                "https://d13yacurqjgara.cloudfront.net/users/38311/screenshots/1628047/dfst-mg4_1x.png",
                "https://d13yacurqjgara.cloudfront.net/users/146798/screenshots/1628405/bubbly_birdy_1x.png",
                "https://d13yacurqjgara.cloudfront.net/users/607501/screenshots/1628351/logo_mockup_display__07_1x.jpg",
                "https://d13yacurqjgara.cloudfront.net/users/147435/screenshots/1628399/sufweb_teaser.jpg",
                "https://d13yacurqjgara.cloudfront.net/users/111948/screenshots/1628041/rocket-pop_1x.jpg",
                "https://d13yacurqjgara.cloudfront.net/users/157303/screenshots/1628313/12_1x.png",
                "https://d13yacurqjgara.cloudfront.net/users/24711/screenshots/1628676/trivantis-city_2x_1x.png",
                "https://d13yacurqjgara.cloudfront.net/users/604158/screenshots/1627943/final_1x.jpg",
                "https://d13yacurqjgara.cloudfront.net/users/25416/screenshots/1628248/drib_1x.jpg",
                "https://d13yacurqjgara.cloudfront.net/users/292484/screenshots/1628461/designers_guide_to_startup_weekend-1_1x.jpg",
                "https://d13yacurqjgara.cloudfront.net/users/5976/screenshots/1628234/space_watchers_eye_planet_logo_design_symbol_by_alex_tass_teaser.jpg",
                "https://d13yacurqjgara.cloudfront.net/users/271951/screenshots/1628799/thumb_1x.jpg",
                "https://d13yacurqjgara.cloudfront.net/users/483231/screenshots/1628447/anicons1_1x.png",
                "https://d13yacurqjgara.cloudfront.net/users/16540/screenshots/1628044/engage.independence.dribbb_1x.jpg"
        };
    }
}

url ของรูปภาพผมใช้รูปภาพจากการ api ของ dribbble นะครับ

อ้อเมื่อต่อ internet ก็อย่าลืมเพิ่ม permission internet ที่ไฟล์ AndroidManifest.xml ด้วยละ

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

สุดท้ายเมื่อรันโปรแกรม จะได้หน้าตาแบบนี้

Result

ลองไปลองเล่นกันดูนะครับ

Chai

Chai Phonbopit : Developer แห่งหนึ่ง • ผู้ชายธรรมดาๆ ที่ชื่นชอบ Node.js, JavaScript และ Open Source มีงานอดิเรกเป็น Acoustic Guitar และ Football

บทความล่าสุด