Picasso คืออะไร?
Picasso เป็น Image Loading Library จาก Square Inc. โดดเด่นด้วย API ที่เรียบง่ายมาก "One-liner" เหมาะสำหรับโปรเจกต์ที่ต้องการโหลดภาพพื้นฐาน ไม่ต้องการฟีเจอร์ซับซ้อน כמו GIF/Video
การติดตั้ง
build.gradle (Module: app)
dependencies {
// Picasso เวอร์ชันล่าสุด (ตรวจสอบที่ GitHub: square/picasso)
implementation 'com.squareup.picasso:picasso:2.8'
// สำหรับ OkHttp (แนะนำให้ใช้ร่วม)
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
// Picasso OkHttp3 Downloader (ถ้าใช้ OkHttp)
// implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
}
> ⚠️ **หมายเหตุ:** โค้ดตัวอย่างเดิมใช้ `com.squareup.picasso3:picasso:2.71828` ซึ่งเป็นเวอร์ชันเก่า/ผิดปกติ ควรใช้ `com.squareup.picasso:picasso:2.8` หรือใหม่กว่า
การใช้งานพื้นฐาน
Layout (activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView"
android:layout_width="200dp"
android:layout_height="200dp"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView imageView = findViewById(R.id.imageView);
Picasso.get() // ใช้ get() แทน with(context) ในเวอร์ชันใหม่
.load("https://www.tutorialspoint.com/images/tp-logo-diamond.png")
.placeholder(R.mipmap.ic_launcher) // ระหว่างโหลด
.error(R.drawable.ic_error) // โหลดล้มเหลว
.resize(400, 400) // Resize ก่อนโหลด (ป้องกัน OOM)
.centerCrop() // Crop ให้เต็มพื้นที่
.rotate(0) // หมุนองศา
.into(imageView, new Callback() {
@Override
public void onSuccess() {
Toast.makeText(MainActivity.this, "โหลดภาพสำเร็จ", Toast.LENGTH_SHORT).show();
}
@Override
public void onError(Exception e) {
Toast.makeText(MainActivity.this, "โหลดภาพล้มเหลว: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
เมธอดหลักของ Picasso (Cheat Sheet)
| เมธอด | คำอธิบาย |
get() | ดึง Singleton Instance (แทน with(context) เดิม) |
load(String/File/Uri/Resource) | ระบุแหล่งที่มาของภาพ |
placeholder(Drawable/ResId) | ภาพชั่วคราวระหว่างโหลด |
error(Drawable/ResId) | ภาพเมื่อโหลดล้มเหลว |
memoryPolicy(MemoryPolicy) | NO_CACHE, NO_STORE |
networkPolicy(NetworkPolicy) | OFFLINE, NO_CACHE |
resize(int, int) | ปรับขนาด (px) - ทำ Downscaling บน Network Thread |
resizeDimen(int, int) | ปรับขนาดจาก Dimen Resource |
centerCrop() | ScaleType.CENTER_CROP |
centerInside() | ScaleType.CENTER_INSIDE |
fit() | วัดขนาด View อัตโนมัติ (ต้องไม่มี fixed size) |
rotate(float degrees) | หมุนภาพ |
rotate(float degrees, float pivotX, float pivotY) | หมุนพร้อมจุดหมุน |
transform(Transformation) | Custom Transformation |
priority(Priority) | LOW, NORMAL, HIGH |
tag(Object) | Tag สำหรับ Cancel request กลุ่ม |
into(ImageView) | โหลดลง ImageView |
into(ImageView, Callback) | โหลดพร้อม Callback |
into(Target) | โหลดลง Custom Target |
fetch() | ดึงแค่ Cache ไม่แสดง |
fetch(Callback) | ดึง Cache พร้อม Callback |
ฟีเจอร์ขั้นสูง
1. Custom Transformation (มุมโค้ง, วงกลม)
import com.squareup.picasso.Transformation;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Shader;
public class CircleTransform implements Transformation {
@Override
public Bitmap transform(Bitmap source) {
int size = Math.min(source.getWidth(), source.getHeight());
int x = (source.getWidth() - size) / 2;
int y = (source.getHeight() - size) / 2;
Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);
if (squared != source) source.recycle();
Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
BitmapShader shader = new BitmapShader(squared, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(shader);
paint.setAntiAlias(true);
float radius = size / 2f;
canvas.drawCircle(radius, radius, radius, paint);
squared.recycle();
return bitmap;
}
@Override
public String key() { return "circle"; }
}
// ใช้งาน
Picasso.get().load(url).transform(new CircleTransform()).into(imageView);
2. Request Creator และ Target สำหรับ RecyclerView
// ใน Adapter onBindViewHolder
Picasso.get()
.load(item.getImageUrl())
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.fit() // ใช้กับ View ที่ไม่มี fixed size
.centerCrop()
.into(holder.imageView);
// สำคัญ: Cancel request เมื่อ View Recycle
@Override
public void onViewRecycled(@NonNull ViewHolder holder) {
super.onViewRecycled(holder);
Picasso.get().cancelRequest(holder.imageView);
}
3. Debugging และ Indicators
// เปิด Debug Mode (แสดงสีขอบ: แดง=Network, น้ำเงิน=Disk, เขียว=Memory)
Picasso.get().setIndicatorsEnabled(true);
// Logging
Picasso.get().setLoggingEnabled(true);
Picasso vs Glide: เลือกตัวไหนดี?
| ด้าน | Picasso | Glide |
| API Complexity | Simple, Minimal | Rich, Fluent |
| GIF/Video | ❌ | ✅ |
| Auto Lifecycle | ❌ (Manual cancel) | ✅ (with Fragment/Activity) |
| Transformations | Basic + Custom | Rich Built-in |
| Memory Management | Good | Excellent (Downsampling) |
| Size | ~120 KB | ~400 KB |
| Kotlin Extensions | Community | Official |
แนวทางเลือก
- Picasso: โปรเจกต์เล็ก, โหลดภาพ Static, API เรียบง่าย, ขนาด APK สำคัญ
- Glide: โปรเจกต์ Production, ต้องการ GIF/Video, RecyclerView มาก, Lifecycle Awareness
- Coil: โปรเจกต์ Kotlin ใหม่ (Recommended สำหรับ Kotlin First)
สิ่งที่ควรระวัง
- Picasso ไม่ Cancel Request อัตโนมัติเมื่อ View Detach → เรียก
Picasso.get().cancelRequest(imageView) ใน onViewRecycled หรือ onDestroyView
- ใช้
.fit() แทน .resize() เมื่อ ImageView ไม่มีขนาดคงที่
- Placeholder/Error ควรเป็น Resource (ResId) ไม่ใช่ Drawable Object เพื่อ Performance
- สำหรับ List ใหญ่ ใช้
memoryPolicy(MemoryPolicy.NO_CACHE) เพื่อไม่ให้เต็ม Memory