All Products
Search
Document Center

ApsaraVideo VOD:Strategi siklus hidup pemutar

Last Updated:Sep 11, 2026

Dokumen ini menjelaskan latar belakang desain, jenis strategi, dan penggunaan strategi siklus hidup pemutar AliPlayerKit.

Latar Belakang

Strategi siklus hidup pemutar adalah pola strategi yang diabstraksi dari pool pemutar multi-instans yang awalnya diimplementasikan untuk aplikasi drama pendek Alibaba Cloud.
Desain ini memungkinkan penggeseran video cepat dengan menggunakan pool instans pemutar yang dibagikan secara global untuk menyediakan hal-hal berikut:

  1. Penggunaan ulang instans: Mengurangi beban pembuatan instans baru.

  2. Konfigurasi dinamis: Secara fleksibel mengontrol jumlah instans.

  3. Optimalisasi thread: Memberikan kontrol detail halus atas sumber daya thread.

Pendekatan ini memberikan pemuatan frame pertama yang cepat, peralihan lancar, dan jejak memori yang terkendali, sehingga dapat diadaptasi ke berbagai skenario bisnis.

Konsep Utama

Apa itu strategi siklus hidup pemain?

Strategi siklus hidup pemutar adalah arsitektur untuk mengelola siklus hidup instans pemutar. Strategi ini mendefinisikan operasi inti seperti acquire, recycle, dan clear, serta menguraikan keterkaitan antara manajemen sumber daya pemutar dan logika bisnis.

Skenario bisnis yang berbeda memiliki kebutuhan berbeda dalam mengelola instans pemutar:

Kasus penggunaan

Kebutuhan

Strategi yang direkomendasikan

Standard video playback

Simple dan langsung, tidak perlu penggunaan ulang.

default strategy

Short video list

Frequent switching, requires fast startup.

reuse pool strategy

Video preloading

Instance is bound to an ID and supports preloading.

ID-scoped strategy

Memory-sensitive scenarios

A single global instance for a minimal memory footprint.

singleton strategy

Keunggulan pola strategi

Pola strategi menawarkan keunggulan inti berikut dalam mengelola siklus hidup pemutar:

  • Penguraian keterkaitan: Memisahkan logika bisnis dari detail pembuatan dan penghancuran instans pemutar.

  • Fleksibilitas: Memungkinkan Anda mengganti strategi saat runtime tanpa mengubah logika bisnis.

  • Ekstensibilitas: Anda dapat mengimplementasikan strategi kustom untuk memenuhi kebutuhan bisnis tertentu.

  • Kemudahan observasi: Event siklus hidup terpadu mempermudah pemantauan dan debugging.

Fitur

Masalah yang diatasi

  1. Manajemen terdesentralisasi: Tidak ada mekanisme terpadu untuk mengontrol instans pemutar.

  2. Beban performa: Pembuatan dan penghancuran instans pemutar yang sering membuang sumber daya.

  3. Tantangan penggunaan ulang: Instans pemutar tidak dapat digunakan ulang di berbagai skenario.

  4. Memori tidak terkendali: Kurangnya kontrol efektif atas jejak memori.

Nilai inti

Penggunaan

Deskripsi

Keunggulan

default strategy

Creates a new instance for each use and destroys it afterward.

Simple dan langsung, tanpa residual state.

reuse pool strategy

Maintains an object pool to reuse idle instances.

Mengurangi beban pembuatan dan meningkatkan kecepatan startup.

ID-scoped strategy

Maintains a separate instance for each ID.

Mendukung preloading dan penggunaan ulang berbasis ID.

singleton strategy

A single global instance.

Jejak memori minimal.

Keunggulan arsitektural:

  • Penguraian keterkaitan strategi: Manajemen sumber daya pemutar dipisahkan dari logika bisnis untuk tanggung jawab yang jelas.

  • Pergantian saat runtime: Ganti strategi tanpa me-restart aplikasi.

  • Thread safety: Semua implementasi strategi mendukung akses aman dari beberapa thread.

  • Berbasis event: Menerbitkan event siklus hidup melalui event bus untuk mempermudah pemantauan.

Kemampuan inti

Kemampuan

Deskripsi

Instance acquisition

acquire() Acquires a player instance. The strategy determines whether to create a new one or reuse an existing one.

Instance recycling

recycle() Recycles a player instance. The strategy determines whether to destroy it or keep it.

Resource cleanup

clear() Cleans up all resources, ensuring safe release.

Preloading

preload() Creates instances in advance to reduce time-to-first-frame.

Pool capacity control

setMaxPoolSize() Dynamically adjusts the pool capacity.

Komponen bawaan

Jenis strategi

AliPlayerKit menyediakan empat strategi siklus hidup pemutar bawaan:

Strategi

Deskripsi

Kasus penggunaan

Jejak memori

DefaultLifecycleStrategy

The default strategy. Creates a new instance for each use and destroys it immediately afterward.

Standard playback scenarios, simple dan langsung.

Rendah

ReusePoolLifecycleStrategy

The reuse pool strategy. Maintains an idle pool and uses a LIFO (Last-In, First-Out) policy for reuse.

Short video lists dan information feeds.

Sedang

IdScopedPoolLifecycleStrategy

The ID-scoped strategy. Maintains a separate instance for each ID and uses an LRU (Least Recently Used) policy for eviction.

Video preloading, multi-video switching.

Sedang

SingletonLifecycleStrategy

The singleton strategy. A single global instance.

Memory-sensitive scenarios, single video playback.

Terendah

Detail strategi

DefaultLifecycleStrategy (default strategy)

Ini adalah strategi paling sederhana. Setiap pemanggilan acquire() membuat instans baru, dan setiap pemanggilan recycle() segera menghancurkannya.

Poin utama:

  • Stateless, memberikan instans baru setiap kali.

  • Tidak ada penggunaan ulang, cocok untuk skenario sederhana.

  • Jejak memori terendah (sumber daya dilepas segera setelah digunakan).

ReusePoolLifecycleStrategy (reuse pool strategy)

Berdasarkan pola object pool, strategi ini memelihara pool idle dan daftar aktif. Strategi ini menggunakan kebijakan LIFO (Last-In, First-Out) untuk penggunaan ulang instans.

Poin utama:

  • Kebijakan LIFO untuk pool idle, di mana instans yang paling baru digunakan akan digunakan ulang terlebih dahulu.

  • Mendukung preloading untuk membuat instans lebih awal.

  • Kapasitas pool dapat dikonfigurasi. Instans akan dihancurkan jika kapasitas terlampaui.

  • Ideal untuk skenario short video list dan information feed.

Catatan

Setiap instans pemutar mengonsumsi sekitar 35–40 MB memori. Kapasitas pool default adalah 3, yang dapat Anda sesuaikan berdasarkan performa perangkat.

IdScopedPoolLifecycleStrategy (ID-scoped strategy)

Memelihara instans pemutar terpisah untuk setiap uniqueId, selalu mengembalikan instans yang sama untuk ID tertentu. Strategi ini menggunakan mekanisme LRU (Least Recently Used) untuk mengontrol jumlah instans.

Poin utama:

  • Berbasis ID, selalu menggunakan ulang instans yang sama untuk ID yang sama.

  • Mekanisme eviction LRU secara otomatis membersihkan instans yang paling jarang digunakan.

  • Mendukung preloading untuk membuat instans unbound lebih awal.

  • Ideal untuk skenario video preloading dan multi-video switching.

SingletonLifecycleStrategy (singleton strategy)

Memelihara satu instans pemutar global. Strategi ini selalu mengembalikan instans yang sama, terlepas dari uniqueId-nya.

Poin utama:

  • Unik secara global, semua pemanggil berbagi instans yang sama.

  • Jejak memori terendah.

  • Tidak cocok untuk memutar beberapa video secara bersamaan.

Event siklus hidup

Strategi menerbitkan event siklus hidup yang dapat Anda dengarkan pada event bus:

Event

Deskripsi

Kapan dipicu

PlayerCreated

A player is created.

When a new instance is created.

PlayerDestroyed

A player is destroyed.

When an instance is destroyed.

PlayerReused

A player is reused.

When an instance is retrieved from the pool for reuse.

PlayerHit

A player instance is hit.

When an existing instance is hit for a given ID.

PlayerEvicted

A player is evicted.

When an instance is evicted by the LRU policy or because the pool is full.

Penggunaan Dasar

Gunakan strategi default

Ini adalah cara paling sederhana untuk menggunakan pemutar, tanpa konfigurasi tambahan:

// Buat controller (secara otomatis menggunakan DefaultLifecycleStrategy)
AliPlayerController controller = new AliPlayerController(context);

// Bind pemutar
AliPlayerModel model = new AliPlayerModel.Builder()
        .videoSource(videoSource)
        .build();
controller.configure(model);
playerView.attach(controller);      

Gunakan strategi reuse pool

Strategi ini ideal untuk skenario short video list dan information feed:

// Dapatkan instans singleton dari strategi reuse pool
ReusePoolLifecycleStrategy strategy = ReusePoolLifecycleStrategy.getInstance();

// Atur kapasitas pool (opsional, default 3)
strategy.setMaxPoolSize(3);

// Suntikkan strategi saat membuat controller
AliPlayerController controller = new AliPlayerController(context, strategy);

// Bersihkan sumber daya saat selesai
strategy.clear(); 

Gunakan strategi ID-scoped

Strategi ini ideal untuk skenario yang memerlukan preloading dan peralihan antara beberapa video:

// Dapatkan instans singleton dari strategi ID-scoped
IdScopedPoolLifecycleStrategy strategy = IdScopedPoolLifecycleStrategy.getInstance();

// Atur kapasitas pool
strategy.setMaxPoolSize(3);

// Preload instans pemutar (opsional)
strategy.preload(context, 2);

// Suntikkan strategi saat membuat controller
AliPlayerController controller = new AliPlayerController(context, strategy);

// Bersihkan sumber daya saat selesai
strategy.clear(); 

Gunakan strategi singleton

Strategi ini ideal untuk skenario yang sensitif terhadap memori:

// Dapatkan instans strategi singleton
SingletonLifecycleStrategy strategy = SingletonLifecycleStrategy.getInstance();

// Preload instans (opsional, hanya membuat satu instans)
strategy.preload(context, 1);

// Suntikkan strategi saat membuat controller
AliPlayerController controller = new AliPlayerController(context, strategy);

Penggunaan Lanjutan

Mendengarkan event siklus hidup

Dengarkan event siklus hidup internal strategi melalui event bus untuk debugging dan pemantauan:

PlayerEventBus eventBus = PlayerEventBus.getInstance();

// Dengarkan pembuatan pemutar
eventBus.subscribe(PlayerLifecycleEvents.PlayerCreated.class, event -> {
    Log.d("Player", "Created: " + event.playerId);
});

// Dengarkan penggunaan ulang pemutar
eventBus.subscribe(PlayerLifecycleEvents.PlayerReused.class, event -> {
    Log.d("Player", "Reused: " + event.playerId);
});

// Dengarkan eviction pemutar
eventBus.subscribe(PlayerLifecycleEvents.PlayerEvicted.class, event -> {
    Log.d("Player", "Evicted: " + event.playerId);
});

// Dengarkan penghancuran pemutar
eventBus.subscribe(PlayerLifecycleEvents.PlayerDestroyed.class, event -> {
    Log.d("Player", "Destroyed: " + event.playerId);
});

// Berhenti berlangganan saat tidak diperlukan lagi
eventBus.unsubscribe(PlayerLifecycleEvents.PlayerCreated.class, listener);

Mengganti strategi secara dinamis

Anda dapat mengganti strategi saat runtime berdasarkan kebutuhan bisnis:

private IPlayerLifecycleStrategy mCurrentStrategy;

private void switchToReusePool() {
    // 1. Bersihkan sumber daya lama
    if (mCurrentStrategy != null) {
        mCurrentStrategy.clear();
    }

    // 2. Ganti ke strategi reuse pool
    mCurrentStrategy = ReusePoolLifecycleStrategy.getInstance();
    mCurrentStrategy.setMaxPoolSize(3);

    // 3. Preload
    mCurrentStrategy.preload(this, 2);
}

private void switchToSingleton() {
    // 1. Bersihkan sumber daya lama
    if (mCurrentStrategy != null) {
        mCurrentStrategy.clear();
    }

    // 2. Ganti ke strategi singleton
    mCurrentStrategy = SingletonLifecycleStrategy.getInstance();
}

Preloading instans pemutar

Preloading membuat instans pemutar lebih awal untuk mengurangi time-to-first-frame:

// Strategi reuse pool: Instans yang dipreloaded ditempatkan di pool idle
ReusePoolLifecycleStrategy strategy = ReusePoolLifecycleStrategy.getInstance();
strategy.preload(context, 2);  // Pra-buat 2 instans

// Strategi ID-scoped: Melakukan preload instans unbound
IdScopedPoolLifecycleStrategy strategy = IdScopedPoolLifecycleStrategy.getInstance();
strategy.preload(context, 2);  // Pra-buat 2 instans unbound

// Strategi singleton: Melakukan preload instans global
SingletonLifecycleStrategy strategy = SingletonLifecycleStrategy.getInstance();
strategy.preload(context, 1);  // Membuat instans global (parameter jumlah diabaikan)

Mengimplementasikan strategi kustom

Implementasikan strategi kustom dengan memperluas BaseLifecycleStrategy:

public class MyCustomStrategy extends BaseLifecycleStrategy {

    private final Map<String, IMediaPlayer> playerMap = new HashMap<>();

    @NonNull@Overridepublic IMediaPlayer acquire(@NonNull Context context, @NonNull String uniqueId) {
        // Logika akuisisi kustom
        IMediaPlayer player = playerMap.get(uniqueId);
        if (player != null) {
            // Hit instans yang sudah ada
            PlayerEventBus.getInstance().post(
                new PlayerLifecycleEvents.PlayerHit(player.getPlayerId()));
            return player;
        }

        // Buat instans baru
        player = createPlayer(context);
        playerMap.put(uniqueId, player);
        return player;
    }

    @Overridepublic void recycle(@Nullable IMediaPlayer player, @NonNull String uniqueId, boolean force) {
        if (player == null) return;

        if (force) {
            // Hancurkan paksa
            playerMap.remove(uniqueId);
            destroyPlayer(player);
        } else {
            // Hanya hentikan pemutar, simpan instansnya
            player.stop();
        }
    }

    @Overridepublic void clear() {
        // Bersihkan semua instans
        for (IMediaPlayer player : playerMap.values()) {
            destroyPlayer(player);
        }
        playerMap.clear();
    }
}

Praktik Terbaik

Pemilihan strategi

Kasus penggunaan

Strategi yang direkomendasikan

Deskripsi

Standard video playback

default strategy

Simple dan langsung, tanpa overhead tambahan.

Short video list (TikTok-style)

reuse pool strategy

Menggunakan ulang instans untuk peralihan cepat.

Video preloading

ID-scoped strategy

Mengikat instans ke ID dan mendukung preloading.

Perangkat low-end

singleton strategy

Jejak memori minimal.

Educational videos (multi-video switching)

ID-scoped strategy

Preload video berikutnya.

Optimalisasi memori

Setiap instans pemutar mengonsumsi sekitar 35–40 MB memori (berdasarkan hasil profiling memori dari pool pemutar multi-instans Alibaba Cloud untuk drama pendek). Kami merekomendasikan menyesuaikan kapasitas pool berdasarkan performa perangkat:

Jenis perangkat

Konfigurasi yang direkomendasikan

Kapasitas pool

High-end device

ReusePool atau IdScopedPool

3

Mid-range device

ReusePool atau IdScopedPool

2

Low-end device

Singleton

1 (default)

Memory-sensitive scenarios

Singleton

1

// Sesuaikan secara dinamis berdasarkan memori perangkat
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
boolean isLowMemory = am.isLowRamDevice();

if (isLowMemory) {
    // Gunakan strategi singleton pada perangkat bermemori rendah
    strategy = SingletonLifecycleStrategy.getInstance();
} else {
    // Gunakan strategi reuse pool pada perangkat standar
    strategy = ReusePoolLifecycleStrategy.getInstance();
    strategy.setMaxPoolSize(isHighEndDevice ? 3 : 2);
}

Peringatan

Item

Deskripsi

Clean up promptly

Call clear() atau recycle(force=true) untuk melepas sumber daya saat halaman dihancurkan.

Strategy singletons

Kelas ReusePoolLifecycleStrategy, IdScopedPoolLifecycleStrategy, dan SingletonLifecycleStrategy diimplementasikan sebagai singleton dengan status yang dibagikan secara global.

Thread safety

Semua implementasi strategi bersifat thread-safe dan dapat digunakan di lingkungan multi-threaded.

Unsubscribe from events

Untuk menghindari memory leak, selalu berhenti berlangganan dari event siklus hidup pada waktu yang tepat.

Initialization order

Strategi diinisialisasi secara otomatis. Anda tidak perlu memanggil init() secara manual.

Contoh

Contoh lengkap disediakan dalam proyek di playerkit-examples/example-lifecycle-strategy.

Fitur contoh

Feature

Description

Strategy switching

Beralih secara dinamis antara keempat strategi bawaan.

Status display

Menampilkan status real-time dari strategi (created/reused/hit/evicted).

Event listening

Mendengarkan dan menampilkan event lifecycle.

Multi-video playback

Menunjukkan efek dari peralihan antara multiple video dengan strategi yang berbeda.

Jalankan contoh

Dalam aplikasi demo, pilih contoh Lifecycle Strategy untuk melihatnya beraksi.

API

Antarmuka inti

Interface/class

Deskripsi

IPlayerLifecycleStrategy

Antarmuka strategi siklus hidup pemutar, yang mendefinisikan operasi inti.

BaseLifecycleStrategy

Kelas dasar untuk strategi, yang mengenkapsulasi logika umum.

IPlayerFactory

Antarmuka factory pemutar, yang bertanggung jawab untuk membuat dan menghancurkan instans.

Metode IPlayerLifecycleStrategy

Metode

Deskripsi

init(IPlayerFactory)

Menginisialisasi strategi dan menginjeksi player factory.

acquire(Context, String)

Mengambil instans pemutar.

recycle(IMediaPlayer, String, boolean)

Mendaur ulang instans pemutar.

clear()

Membersihkan semua sumber daya.

preload(Context, int)

Memuat instans pemutar lebih awal.

Metode BaseLifecycleStrategy

Metode

Deskripsi

setMaxPoolSize(int)

Mengatur kapasitas maksimum pool (hanya berlaku untuk strategi berbasis pool).

createPlayer(Context)

Membuat instans pemutar (dipanggil oleh subclass).

destroyPlayer(IMediaPlayer)

Menghancurkan instans pemutar (dipanggil oleh subclass).

Cara Kerja

Thread safety

Strategi

Thread safety

DefaultLifecycleStrategy

Stateless dan thread-safe.

ReusePoolLifecycleStrategy

synchronized blocks.

IdScopedPoolLifecycleStrategy

synchronized blocks.

SingletonLifecycleStrategy

AtomicReference + double-checked locking.

Perbandingan strategi pooling

Fitur

ReusePool

IdScopedPool

Reuse mechanism

LIFO (Last-In, First-Out)

ID binding + LRU

Preloading support

Yes (places instances in the idle pool)

Yes (places instances in an unbound queue)

Eviction policy

Evicts when the pool is full

Automatic LRU eviction

Use case

Short video list

Multi-video preloading

Logika arsitektural dasar:

  • Mengapa strategi reuse pool menggunakan LIFO (Last-In, First-Out)?

    Dalam skenario pengguliran naik-turun yang sering dalam feed, instans pemutar yang baru saja ditambahkan ke pool idle adalah yang paling "panas" dalam hal konteks decoder dan sumber daya perangkat kerasnya (cache-nya belum dipindahkan oleh sistem). Menggunakannya kembali terlebih dahulu secara signifikan mengurangi waktu yang diperlukan untuk reset konteks tingkat rendah, meningkatkan kecepatan startup berdasarkan prinsip lokalitas spasial.

  • Mengapa strategi ID-scoped menggunakan LRU (Least Recently Used)?

    Pooling multi-instans mengikuti prinsip lokalitas temporal: saat pengguna menggulir feed, probabilitas memutar ulang video yang jauh lebih lama menurun. Kebijakan eviction LRU selaras dengan pola penurunan ini dalam riwayat penjelajahan pengguna, memungkinkan kontrol efektif atas jejak memori puncak aplikasi sekaligus mempertahankan ikatan ketat dengan ID.

FAQ

Memilih strategi yang tepat

Pilih berdasarkan skenario bisnis Anda:

  • Pemutaran sederhana: Gunakan strategi default untuk kompleksitas tambahan nol.

  • Feed short video/informasi: Gunakan strategi reuse pool untuk peralihan cepat.

  • Preloading video: Gunakan strategi ID-scoped untuk ikatan ID.

  • Skenario sensitif memori: Gunakan strategi singleton untuk jejak terkecil.

Mengatur kapasitas pool

Sesuaikan kapasitas berdasarkan performa perangkat dan kebutuhan bisnis:

  • Setiap instans pemutar mengonsumsi sekitar 35–40 MB memori.

  • Kapasitas pool default adalah 3, yang mengonsumsi sekitar 100–120 MB.

  • Untuk perangkat low-end, atur kapasitas menjadi 2 atau gunakan strategi singleton.

Menggunakan preloading

Gunakan preloading dalam skenario yang memerlukan pengurangan time-to-first-frame:

  • Short video list: Preload 1 hingga 2 instans.

  • Halaman detail video: Preload video rekomendasi berikutnya.

  • Hindari preloading berlebihan karena akan meningkatkan penggunaan memori.

Perangkap umum

Situasi berikut adalah penyebab paling umum masalah yang dilaporkan pengguna. Pastikan untuk menghindarinya:

Contoh 1: Lupa memanggil clear()

Kode salah:

@Overrideprotected void onDestroy() {
    super.onDestroy();
    // Hanya detach View, lupa membersihkan instans yang disimpan oleh strategi
    mPlayerView.detach();
}

Kode benar:

@Overrideprotected void onDestroy() {
    super.onDestroy();
    // Detach View
    mPlayerView.detach();
    // Bersihkan sumber daya strategi
    if (mStrategy != null) {
        mStrategy.clear();
    }
}

Penyebab: Strategi (seperti ReusePool) menyimpan referensi ke instans pemutar. Gagal membersihkannya akan menyebabkan memory leak.

Contoh 2: Gagal berhenti berlangganan dari pendengar event

Kode salah:

@Overrideprotected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Berlangganan ke event tetapi tidak pernah berhenti berlangganan
    PlayerEventBus.getInstance().subscribe(
        PlayerLifecycleEvents.PlayerCreated.class,
        event -> updateUI()
    );
}

Kode benar:

private PlayerEventBus.EventListener<PlayerLifecycleEvents.PlayerCreated> mListener;

@Overrideprotected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mListener = event -> updateUI();
    PlayerEventBus.getInstance().subscribe(
        PlayerLifecycleEvents.PlayerCreated.class, mListener);
}

@Overrideprotected void onDestroy() {
    super.onDestroy();
    // Berhenti berlangganan if (mListener != null) {
        PlayerEventBus.getInstance().unsubscribe(
            PlayerLifecycleEvents.PlayerCreated.class, mListener);
    }
}

Penyebab: Event bus menyimpan referensi ke Activity. Jika pendengar tidak dihapus, Activity tidak dapat dilepas setelah dihancurkan.

Contoh 3: Menggunakan instans pemutar setelah didaur ulang

Kode salah:

// Daur ulang pemutar
strategy.recycle(player, "video_1", false);

// Lanjutkan menggunakan pemutar setelah didaur ulang
player.start();  // Dapat menyebabkan exception

Kode benar:

// Daur ulang pemutar
strategy.recycle(player, "video_1", false);
player = null;  // Hapus referensi untuk mencegah penyalahgunaan. Ambil kembali saat diperlukan.
player = strategy.acquire(context, "video_1");

Penyebab: Setelah instans pemutar didaur ulang, pemutar tersebut mungkin dihentikan atau dihancurkan. Menggunakannya setelah itu akan menyebabkan exception.

Debugging

  1. Periksa log: Filter Logcat dengan menggunakan tag:AliPlayerKit.

  2. Dengarkan event siklus hidup: Amati event pembuatan, penggunaan ulang, dan eviction pada event bus.

  3. Periksa status pool: Periksa ukuran pool saat ini dan jumlah instans aktif melalui log.

  4. Analisis memori: Gunakan Android Profiler untuk memeriksa jumlah instans pemutar dan jejak memorinya.