Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Resize ảnh với thư viện Picasso trên Android

Giới thiệu

Bài viết này hướng dẫn cách tải và resize ảnh từ URL trên Android sử dụng thư viện Picasso (Square). Picasso đơn giản, mạnh mẽ, tự động handle caching, placeholder, error handling, và resize.

Các bước thực hiện

Bước 1: Tạo dự án mới

Mở Android Studio, chọn File → New Project và điền thông tin cần thiết.

Bước 2: Thêm dependency (build.gradle / build.gradle.kts)

dependencies {
    // Picasso mới nhất
    implementation 'com.squareup.picasso:picasso:2.8'
    
    // Hoặc bản cũ ổn định
    // implementation 'com.squareup.picasso:picasso:2.71828'
}

Bước 3: Layout (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Picasso Resize Demo"
        android:textSize="20sp"
        android:textStyle="bold"
        android:layout_marginBottom="16dp" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:scaleType="centerCrop"
        android:contentDescription="Loaded image" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_marginTop="16dp">

        <Button
            android:id="@+id/btnResize200x500"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Resize 200x500" />

        <Button
            android:id="@+id/btnFitCenter"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_marginStart="8dp"
            android:text="Fit Center" />

        <Button
            android:id="@+id/btnCenterCrop"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_marginStart="8dp"
            android:text="Center Crop" />

    </LinearLayout>

</LinearLayout>

Bước 4: Code Picasso (src/MainActivity.java)

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import com.squareup.picasso.Picasso;

public class MainActivity extends AppCompatActivity {

    private ImageView imageView;
    private Button btnResize, btnFitCenter, btnCenterCrop;
    private static final String IMAGE_URL = "https://images.pexels.com/photos/414612/pexels-photo-414612.jpeg";

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

        imageView = findViewById(R.id.imageView);
        btnResize = findViewById(R.id.btnResize200x500);
        btnFitCenter = findViewById(R.id.btnFitCenter);
        btnCenterCrop = findViewById(R.id.btnCenterCrop);

        // Load mặc định
        loadWithFitCenter();

        btnResize.setOnClickListener(v -> loadWithResize());
        btnFitCenter.setOnClickListener(v -> loadWithFitCenter());
        btnCenterCrop.setOnClickListener(v -> loadWithCenterCrop());
    }

    private void loadWithResize() {
        Picasso.get()
            .load(IMAGE_URL)
            .resize(200, 500)           // Resize chính xác 200x500 (có thể méo ảnh)
            .centerCrop()               // Crop để fill khung (giữ tỷ lệ)
            .placeholder(R.drawable.placeholder) // Placeholder khi đang load
            .error(R.drawable.error_image)       // Error image nếu load fail
            .into(imageView);
    }

    private void loadWithFitCenter() {
        Picasso.get()
            .load(IMAGE_URL)
            .fit()                      // Fit vào ImageView bounds (cần layout_width/height xác định)
            .centerInside()             // Giữ tỷ lệ, vừa khung (có thể có padding)
            .placeholder(R.drawable.placeholder)
            .error(R.drawable.error_image)
            .into(imageView);
    }

    private void loadWithCenterCrop() {
        Picasso.get()
            .load(IMAGE_URL)
            .fit()
            .centerCrop()               // Giữ tỷ lệ, crop để fill khung
            .placeholder(R.drawable.placeholder)
            .error(R.drawable.error_image)
            .into(imageView);
    }
}

Bước 5: Manifest (androidManifest.xml)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
    package="app.com.sample">

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".MainActivity">
            <intent-filter>
                
                
            </intent-filter>
        </activity>

    </application>
</manifest>

Chạy ứng dụng

Chuẩn bị placeholder.png và error_image.png trong drawable. Kết nối thiết bị, nhấn Run. Thử các nút để thấy khác nhau giữa resize, fit, centerCrop.

So sánh các phương pháp resize trong Picasso

Phương pháp Hành vi Trường hợp dùng
.resize(w, h) Buộc ảnh thành đúng w x h pixel (có thể méo nếu tỷ lệ khác) Thumbnail cố định, avatar vuông
.resize(w, h).centerCrop() Resize giữ tỷ lệ, crop phần thừa để fill w x h Cover image, hero banner, grid item
.resize(w, h).centerInside() Resize giữ tỷ lệ, fit trong w x h (có thể nhỏ hơn) Hiển thị toàn ảnh, không crop
.fit() Tự đo kích thước ImageView (cần layout xác định), resize vừa khung ImageView có size cố định (match_parent, dp)
.fit().centerCrop() Fit ImageView bounds, crop để fill Full-width banner, cover photo
.fit().centerInside() Fit ImageView bounds, giữ tỷ lệ, vừa khung Product image, artwork
.onlyScaleDown() Chỉ resize nếu ảnh lớn hơn target, không upscale Tiết kiệm bandwidth, tránh mờ khi phóng to

Picasso nâng cao

// Transformation tùy chỉnh (rounded corners, circle, blur)
Picasso.get()
    .load(url)
    .transform(new RoundedCornersTransformation(16, 0)) // radius, margin
    .into(imageView);

// Callback
Picasso.get()
    .load(url)
    .into(imageView, new Callback() {
        @Override
        public void onSuccess() { /* Load xong */ }
        @Override
        public void onError(Exception e) { /* Xử lý lỗi */ }
    });

// Priority
Picasso.get()
    .load(url)
    .priority(Picasso.Priority.HIGH) // LOW, NORMAL, HIGH
    .into(imageView);

// Tag để cancel request
Picasso.get()
    .load(url)
    .tag("profile_fragment")
    .into(imageView);

// Cancel all với tag
Picasso.get().cancelTag("profile_fragment");

// Clear cache
Picasso.get().cache.clear(); // Memory cache
// Disk cache: OkHttp cache (Picasso dùng OkHttp dưới lớp)

Picasso vs Glide vs Coil

Đặc điểm Picasso Glide Coil (Kotlin)
API Fluent, đơn giản Fluent, nhiều option Kotlin-first, Coroutines, Extension functions
GIF/Animation Khó khăn Hỗ trợ tốt Hỗ trợ tốt
Video thumbnail Không Có (MediaMetadataRetriever) Có
Kích thước ~800KB ~400KB ~300KB (core)
Lifecycle integration Manual RequestManager (auto) Coroutine scope (auto)

Lưu ý quan trọng

  • Quyền INTERNET bắt buộc.
  • .fit() yêu cầu ImageView có width/height xác định (không phải wrap_content).
  • Picasso dùng OkHttp client - có thể custom OkHttpClient cho auth, interceptor, timeout.
  • Để dùng với RecyclerView: Picasso tự handle view recycling, không cần cancel manual.
  • Placeholder/error drawable nên là vector hoặc bitmap nhỏ để tránh flash.