Advertisement
  1. Code
  2. Coding Fundamentals
  3. Design Patterns

Android Design Pattern: Observer Pattern

Scroll to top
Read Time: 10 min

() translation by (you can also view the original English article)

Apa yang dimaksud dengan Observer Pattern?

Observer Pattern adalah software design pattern yang menetapkan one-to-many dependensi antara objek. Kapan saja keadaan salah satu objek ("subject" atau "observable, demikianlah") perubahan, semua objek-objek lain ("observer") yang bergantung di atasnya akan diberitahu.

Mari kita gunakan contoh dari pengguna yang telah berlangganan untuk menerima penawaran dari Envato Market melalui email. Pengguna dalam kasus ini adalah pengamat. Kapan saja ada tawaran dari Envato pasar, mereka mendapatkan pemberitahuan tentang hal ini melalui email. Setiap pengguna dapat kemudian membeli ke Penawaran atau memutuskan bahwa mereka mungkin tidak akan benar-benar tertarik pada saat itu. Pengguna (observer) juga dapat berlangganan untuk menerima penawaran dari pasar e-commerce lain jika mereka inginkan dan kemudian benar-benar mungkin berhenti berlangganan dari menerima tawaran dari salah satu dari mereka.

Pattern ini sangat mirip dengan Publish-Subcribe pattern. Subjek atau observable menerbitkan keluar pemberitahuan untuk para observer tergantung tanpa bahkan mengetahui berapa banyak pengamat telah berlangganan itu, atau siapa mereka — diamati hanya tahu bahwa mereka harus menerapkan interface (kita akan segara kesana), tanpa khawatir tentang apa tindakan para pengamat mungkin melakukan.

Manfaat dari Observer Pattern

  • Subjek tahu sedikit tentang para observer. Satu-satunya yang tahu adalah bahwa pengamat menerapkan atau menyetujui kontrak tertentu atau interface.
  • Subjek dapat digunakan kembali tanpa melibatkan observer mereka, dan yang sama berlaku untuk observer terlalu.
  • Tidak ada modifikasi ini dilakukan untuk subjek untuk mengakomodasi observer yang baru. Observer baru hanya perlu untuk mengimplementasikan inteface yang subjek sadar dan kemudian mendaftar untuk subjek.
  • Observer bisa terdaftar lebih dari satu subjek yang terdaftar.

Semua manfaat ini memberi Anda longgar, kopling antara modul dalam kode Anda, yang memungkinkan Anda untuk membangun desain yang fleksibel untuk aplikasi Anda. Dalam sisa dari posting ini, kita akan melihat bagaimana untuk membuat kita sendiri Observer pattern implementasi, dan kami juga akan menggunakan built-in Java  Observer/Observable API serta melihat ke pustaka pihak ketiga yang dapat menawarkan fungsionalitas seperti itu.

Membangun Observer Pattern kita sendiri

1. Buat Interface subjek

Kita mulai dengan mendefinisikan sebuah inteface yang akan menerapkan (observables).

1
public interface Subject {
2
    void registerObserver(RepositoryObserver repositoryObserver);
3
    void removeObserver(RepositoryObserver repositoryObserver);
4
    void notifyObservers();
5
}

Pada kode diatas, kita menciptakan Java Interface dengan tiga metode. RegisterObserver() metode pertama, seperti yang dikatakan, akan mendaftarkan observer jenis RepositoryObserver (kami akan membuat interface tersebut segera) kepada subjek. removeObserver() akan dipanggil untuk menghapus observer yang ingin berhenti mendapatkan pemberitahuan dari subjek, dan akhirnya, notifyObserver() akan mengirim siaran ke semua observer setiap kali ada perubahan. Sekarang, mari kita membuat sebuah kelas concrete subjek yang akan mengimplementasikan interface subjek yang kami telah membuat:

1
import android.os.Handler;
2
import java.util.ArrayList;
3
4
public class UserDataRepository implements Subject {
5
    private String mFullName;
6
    private int mAge;
7
    private static UserDataRepository INSTANCE = null;
8
9
    private ArrayList<RepositoryObserver> mObservers;
10
11
    private UserDataRepository() {
12
        mObservers = new ArrayList<>();
13
        getNewDataFromRemote();
14
    }
15
16
    // Simulate network

17
    private void getNewDataFromRemote() {
18
        final Handler handler = new Handler();
19
        handler.postDelayed(new Runnable() {
20
            @Override
21
            public void run() {
22
                setUserData("Chike Mgbemena", 101);
23
            }
24
        }, 10000);
25
    }
26
27
    // Creates a Singleton of the class

28
    public static UserDataRepository getInstance() {
29
        if(INSTANCE == null) {
30
            INSTANCE = new UserDataRepository();
31
        }
32
        return INSTANCE;
33
    }
34
35
    @Override
36
    public void registerObserver(RepositoryObserver repositoryObserver) {
37
        if(!mObservers.contains(repositoryObserver)) {
38
            mObservers.add(repositoryObserver);
39
        }
40
    }
41
42
    @Override
43
    public void removeObserver(RepositoryObserver repositoryObserver) {
44
        if(mObservers.contains(repositoryObserver)) {
45
            mObservers.remove(repositoryObserver);
46
        }
47
    }
48
49
    @Override
50
    public void notifyObservers() {
51
        for (RepositoryObserver observer: mObservers) {
52
            observer.onUserDataChanged(mFullName, mAge);
53
        }
54
    }
55
56
    public void setUserData(String fullName, int age) {
57
        mFullName = fullName;
58
        mAge = age;
59
        notifyObservers();
60
    }
61
}

Kelas atas mengimplementasikan interface Subjek. Kami memiliki ArrayList yang memegang pengamat dan kemudian menciptakan dalam konstruktor pribadi. Observer register oleh ditambahkan ke ArrayList dan demikian juga, unregisters oleh dikeluarkan dari ArrayList.

Perhatikan bahwa kita adalah simulasi jaringan permintaan untuk mengambil data baru. Setelah metode setUserData() dipanggil dan diberikan nilai baru untuk nama dan usia, kita memanggil metode notifyObservers() yang, seperti dikatakan, memberitahu atau mengirim broadcast ke semua terdaftar observer tentang perubahan data baru. Nilai-nilai baru untuk nama lengkap dan umur juga dilalui sepanjang. Hal ini dapat memiliki beberapa pengamat tetapi, dalam tutorial ini, kita akan membuat hanya satu pengamat. Tapi pertama-tama, mari kita membuat observer interface.

2. membuat Observer Interface

1
public interface RepositoryObserver {
2
    void onUserDataChanged(String fullname, int age);
3
}

Pada kode diatas, kita menciptakan observer interface yang harus menerapkan. Hal ini memungkinkan kode kami untuk menjadi lebih fleksibel karena kami pengkodean untuk antarmuka bukan sebuah implementasi konkrit. Kelas Subject konkrit tidak perlu menyadari banyak interface konkrit yang mungkin memiliki; semua tahu tentang mereka adalah bahwa mereka mengimplementasikan antarmuka RepositoryObserver.

Mari kita membuat sebuah kelas konkrit yang mengimplementasikan interface ini.

1
import android.os.Bundle;
2
import android.support.v7.app.AppCompatActivity;
3
import android.widget.TextView;
4
5
public class UserProfileActivity extends AppCompatActivity implements RepositoryObserver {
6
    private Subject mUserDataRepository;
7
    private TextView mTextViewUserFullName;
8
    private TextView mTextViewUserAge;
9
10
    @Override
11
    protected void onCreate(Bundle savedInstanceState) {
12
        super.onCreate(savedInstanceState);
13
        setContentView(R.layout.activity_user_profile);
14
15
        mTextViewUserAge = (TextView) findViewById(R.id.tv_age);
16
        mTextViewUserFullName = (TextView) findViewById(R.id.tv_fullname);
17
18
        mUserDataRepository = UserDataRepository.getInstance();
19
        mUserDataRepository.registerObserver(this);
20
    }
21
22
    @Override
23
    public void onUserDataChanged(String fullname, int age) {
24
        mTextViewUserFullName.setText(fullname);
25
        mTextViewUserAge.setText(age);
26
    }
27
28
    @Override
29
    protected void onDestroy() {
30
        super.onDestroy();
31
        mUserDataRepository.removeObserver(this);
32
    }
33
}

Hal pertama untuk melihat kode diatas adalah bahwa UserProfileActivity mengimplementasikan interface RepositoryObserver — sehingga menerapkan metode onUserDataChanged(). Dalam metode onCreate() activity, kami mendapat instance UserDataRepository yang kita kemudian diinisialisasi dan akhirnya terdaftar ini observer.

Dalam metode onDestroy(), kami ingin berhenti mendapatkan pemberitahuan, jadi kami membatalkan registrasi dari menerima pemberitahuan.

Dalam metode onUserDataChanged(), kita ingin memperbarui widget TextView-mTextViewUserFullName dan mTextViewUserAge — dengan set baru nilai data.

Sekarang kita hanya memiliki satu kelas observer, tetapi mungkin dan mudah bagi kita untuk membuat kelas-kelas lain yang ingin menjadi observer kelas UserDataRepository. Sebagai contoh, kita bisa dengan mudah memiliki SettingsActivity yang ingin juga diberitahu tentang perubahan data pengguna dengan menjadi observer.

Push dan Pull model

Dalam contoh di atas, kita menggunakan model push observer pattern. Dalam model ini, subjek akan memberitahu para observer tentang perubahan oleh lewat data yang berubah. Tetapi dalam pull model, subjek masih akan memberitahu para observer, tetapi tidak benar-benar lulus data yang berubah. Para observer kemudian pull data yang mereka butuhkan setelah mereka menerima pemberitahuan.

Memanfaatkan Observer Built-In Java API

Sejauh ini, kami telah menciptakan implementasi Observer Pattern kita sendiri, tetapi Java memiliki built-in Observer / Observable dukungan dalam API. Dalam bagian ini, kita akan menggunakan ini. API ini menyederhanakan beberapa implementasi, seperti yang Anda lihat.

1. Buat Observable

UserDataRepository kami — yang merupakan subjek atau observable kami — sekarang akan extend superclass java.util.Observable menjadi Observable. Ini adalah kelas yang ingin diamati oleh observer satu atau lebih.

1
import android.os.Handler;
2
import java.util.Observable;
3
4
public class UserDataRepository extends Observable {
5
    private String mFullName;
6
    private int mAge;
7
    private static UserDataRepository INSTANCE = null;
8
9
    private UserDataRepository() {
10
        getNewDataFromRemote();
11
    }
12
13
    // Returns a single instance of this class, creating it if necessary.

14
    public static UserDataRepository getInstance() {
15
        if(INSTANCE == null) {
16
            INSTANCE = new UserDataRepository();
17
        }
18
        return INSTANCE;
19
    }
20
21
    // Simulate network

22
    private void getNewDataFromRemote() {
23
        final Handler handler = new Handler();
24
        handler.postDelayed(new Runnable() {
25
            @Override
26
            public void run() {
27
                setUserData("Mgbemena Chike", 102);
28
            }
29
        }, 10000);
30
    }
31
32
    public void setUserData(String fullName, int age) {
33
        mFullName = fullName;
34
        mAge = age;
35
        setChanged();
36
        notifyObservers();
37
    }
38
39
    public String getFullName() {
40
        return mFullName;
41
    }
42
43
    public int getAge() {
44
        return mAge;
45
    }
46
}

Sekarang bahwa kita telah direfractor kelas UserDataRepository kami untuk menggunakan API diamati Java, mari kita melihat apa yang berubah dibandingkan dengan versi sebelumnya. Hal pertama yang menyadari adalah bahwa kita extend kelas super (ini berarti bahwa kelas ini tidak bisa extend setiap kelas lain) dan tidak melaksanakan interface seperti yang kita lakukan di bagian sebelumnya.

Kami tidak lagi memegang ArrayList observer; ini ditangani di kelas super. Demikian pula, kita tidak perlu khawatir tentang pendaftaran, penghapusan, atau pemberitahuan observers—java.util.Observable menangani semua itu bagi kita.

Perbedaan lain adalah bahwa di kelas ini kami mempekerjakan pull style. Kami mengingatkan para observer bahwa perubahan yang telah terjadi dengan notifyObservers(), tetapi para observer akan perlu untuk menarik data menggunakan Getter bidang yang kita telah didefinisikan di kelas ini. Jika Anda ingin menggunakan push style sebaliknya, maka Anda dapat menggunakan metode notifyObservers(Object arg) dan parsing yang diubah data ke observer di argumen objek.

Metode setChanged() kelas super menetapkan tanda ke true, menunjukkan bahwa data telah berubah. Kemudian Anda dapat memanggil metode notifyObservers(). Perlu diketahui bahwa jika Anda tidak memanggil setChanged() sebelum memanggil notifyObsevers(), observer tidak akan diberitahu. Anda dapat memeriksa nilai falg ini dengan menggunakan hasChanged() metode dan jelas itu kembali ke false dengan clearChanged(). Sekarang bahwa kita memiliki kelas kami observable dibuat, mari kita lihat bagaimana mengatur observer juga.

2. Membuat Observer

Kelas observable UserDataRepository kami membutuhkan seorang Observer yang sesuai untuk menjadi berguna, jadi mari kita refactor kami UserProfileActivity untuk mengimplementasikan interface java.util.Observer.

1
import android.os.Bundle;
2
import android.support.v7.app.AppCompatActivity;
3
import android.widget.TextView;
4
import com.chikeandroid.tutsplusobserverpattern.R;
5
import java.util.Observable;
6
import java.util.Observer;
7
8
public class UserProfileActivity extends AppCompatActivity implements Observer {
9
    private Observable mUserDataRepositoryObservable;
10
    private TextView mTextViewUserFullName;
11
    private TextView mTextViewUserAge;
12
13
    @Override
14
    protected void onCreate(Bundle savedInstanceState) {
15
        super.onCreate(savedInstanceState);
16
        setContentView(R.layout.activity_user_profile);
17
18
        mTextViewUserAge = (TextView) findViewById(R.id.tv_age);
19
        mTextViewUserFullName = (TextView) findViewById(R.id.tv_fullname);
20
21
        mUserDataRepositoryObservable = UserDataRepository.getInstance();
22
        mUserDataRepositoryObservable.addObserver(this);
23
    }
24
25
    @Override
26
    public void update(Observable observable, Object o) {
27
        if (observable instanceof UserDataRepository) {
28
            UserDataRepository userDataRepository = (UserDataRepository)observable;
29
            mTextViewUserAge.setText(String.valueOf(userDataRepository.getAge()));
30
            mTextViewUserFullName.setText(userDataRepository.getFullName());
31
        }
32
    }
33
34
    @Override
35
    protected void onDestroy() {
36
        super.onDestroy();
37
        mUserDataRepositoryObservable.deleteObserver(this);
38
    }
39
}

Dalam metode onCreate(), kami menambahkan kelas ini sebagai pengamat ke UserDataRepository observable dengan menggunakan metode addObserver() di kelas super java.util.Observable.

Dalam metode update() akan membuat yang observer harus menerapkan, kami memeriksa jika Observable kita menerima sebagai parameter adalah instance dari UserDataRepository kami (Perhatikan bahwa observer dapat berlangganan berbeda observables), dan kemudian kita melemparkannya bahwa contoh dan mengambil nilai-nilai yang kita inginkan menggunakan Getter bidang. Kemudian kita menggunakan nilai-nilai tersebut untuk memperbarui tampilan widget.

Ketika activity hancur, kita tidak perlu untuk mendapatkan setiap update dari diamati, jadi kami hanya akan menghapus aktivitas dari daftar pengamat dengan memanggil metode deleteObserver().

Perpustakaan untuk menerapkan Observer Pattern

Jika Anda tidak ingin untuk membangun implementasi Observer Pattern Anda sendiri dari awal atau menggunakan Java Observer API, Anda dapat menggunakan beberapa bebas dan open source perpustakaan yang tersedia untuk Android seperti Greenrobot's EventBus. Untuk mempelajari lebih lanjut tentang hal itu, memeriksa tutorial saya di sini di Envato Tuts +.

Atau, Anda mungkin seperti RxAndroid dan RxJava. Pelajari lebih banyak tentang mereka di sini:

Kesimpulan

Dalam tutorial ini, Anda belajar tentang pola Observer di Java: apa itu, manfaat menggunakan itu, bagaimana untuk menerapkan Anda sendiri, menggunakan API Observer Java, dan juga beberapa librari pihak ketiga untuk melaksanakan pola ini.

Sementara itu, memeriksa beberapa kami kursus dan tutorial pada bahasa Java dan pengembangan aplikasi Android!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.