Soru Android'de Gözlemlenebilir Kullanımı


Uygulamak istiyorum Navigation View tamamen tanımlanmış bir değere bağlı olan birçok parça ile MainActivity. MainActivity'deki değişkenlere erişilebildiğini biliyorum değeri almak için diğer Fragmentlerden MainActivity olarak tanımlanan yöntemi kullanmaama burada yakalama, MainActivity'deki değişkenin değeri olabilir. değişiklik (üzerinde çalışır AsyncThread). Şimdi ya kodu değiştireceğim Fragmanlar değerlerini günceller dayalı parçanın kendisinde bir olay veya kullan SharedPreference. Ancak, SharedPreferences'ı kullanmak istemiyorum, ya da değerindeki değişikliklerin gereksiz yere defalarca kontrol edilmesi gerekmiyor.

RxJS'de biliyorum, kullanıyoruz izlenebilir Zaman uyumsuz olarak çalışır ve bir konveyör bandına benzer bir şekilde çalışır. Biraz googling resmi dokümanlar: Gözlenebilir Android'de benzer bir şeyle ilgili şüphelerimi doğruladı, ancak nasıl uygulanacağı konusunda herhangi bir uygun Eğitim veya açıklama bulamadı. Yani, Android'de Gözlemlenebilir'in nasıl çalıştığı ve Async ise ve onun RxJS uygulamasına benzemesine bağlı olarak nasıl netlik kazandırabilecek basit bir kod parçacığı arıyorum. (Hayır, RxJS uygulamasını istemiyorum)

Test durumu:

MainActivity : int a, b (need observable for both variables)
Frag1 : int a1 , b1, a1changed(),b1changed()
Frag2 : int a2 , b2, a2Changed(), b2changed()

MainActivity değeri değiştiğinde, Fragmanlar boyunca karşılık gelen tam sayılarla yansıtılmalı ve fark edilmekte olan değişiklik hakkında her Fragman için ayrı bir işlev çağırmalıdır.


18
2018-03-23 17:33


Menşei


Java’yı Gözlemlenebilir’e bağladığınız veya kendi uyguladığınız dokümanlar için kullanabilirsiniz. Şahsen iyi bir şekilde öğrenmek için örüntüyü kendi uygulamanızı kullanmanızı tavsiye ederim. İnternette kullanımı hakkında tonlarca eğitici var. Eğer yardımcı olursa, bakabilirsiniz bu cevap benimki gibi bunu açıklayabildiğim kadar basit anlatmaya çalıştım :) - Onik
Elbette çevrimiçi eğiticiler var, ancak onlarla sorun, genellikle gerekli olmayan belirli vakalara başvurmalarıdır. Eminim ki yarım günlüğünü takip edersem, Cevabı alırdım. Fakat şu an için yapamadığımdan, uygulamasında daha basit bir örnek istedim. Kesinlikle benden hoşlanan diğer kişilere, henüz hiçbir şeyden geçmek istemedikleri ve Gözlemlenebilir ile Android davranışları için daha basit bir açıklama aramaya yardımcı olacaklardır. - Kaushik NP


Cevaplar:


İşte basit bir örnek Activity ve tek Fragment ama diğer parçalarla aynı olacak.

Öncelikle gözlemlemek istediğiniz değer için bir sınıf ayakta oluşturmanız gerekir; int bu yüzden bunu içeren bir sınıf oluşturun int ve bu uzanıyor Observable (uygular Serializable aktivite ve parça arasındaki değişimi basitleştirmek için):

...
import java.util.Observable;

public class ObservableInteger extends Observable implements Serializable {

    private int value;

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
        this.setChanged();
        this.notifyObservers(value);
    }
}

Sonra bu gözlemlenebilir int'yi bir aktivitede kullanın ( Button ve bir FrameLayout görüntülemek için kullanılır Fragment):

public class MainActivity extends Activity {

    private ObservableInteger a;
    private Button button;

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

        // Create observable int
        a = new ObservableInteger();
        // Set a default value to it
        a.setValue(0);

        // Create frag1
        Frag1 frag1 = new Frag1();
        Bundle args = new Bundle();
        // Put observable int (That why ObservableInteger implements Serializable)
        args.putSerializable(Frag1.PARAM, a);
        frag1.setArguments(args);

        // Add frag1 on screen
        getFragmentManager().beginTransaction().add(R.id.container, frag1).commit();

        // Add a button to change value of a dynamically
        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // Set a new value in a
                a.setValue(a.getValue() + 1);
            }
        });
    }
}

Son olarak, bir Fragment bir değer değişikliği dinler:

...
import java.util.Observer;

public class Frag1 extends Fragment {
    public static final String PARAM = "param";

    private ObservableInteger a1;
    private Observer a1Changed = new Observer() {
        @Override
        public void update(Observable o, Object newValue) {
            // a1 changed! (aka a changed)
            // newValue is the observable int value (it's the same as a1.getValue())
            Log.d(Frag1.class.getSimpleName(), "a1 has changed, new value:"+ (int) newValue);
        }
    };

    public Frag1() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            // Get ObservableInteger created in activity
            a1 = (ObservableInteger) getArguments().getSerializable(PARAM);
            // Add listener for value change
            a1.addObserver(a1Changed);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_blank, container, false);
    }
}

Değişkenlerimi sizinkiyle aynı şekilde adlandırmaya çalışıyorum, umarım size yardımcı olacaktır.


17
2018-03-26 19:33



Güzel örnek. Orada çok az şüphe var. Gözlemlenebilir eğer 'b' diye adlandırılan başka bir int varsa ve 'a' ile birlikte gözlemlemiş olsaydınız. Ve seri hale getirilebilir kullanımı nedir? - Kaushik NP
Eğer senin Observable object, her biri için getter / setter oluşturabileceğiniz birden fazla özellik içerir ve notifyObservers() ayarlayıcılarda, nesnenin değişmiş olduğu her gözlemciye (ama hangi özellikte değil) söyleyecektir. Serializable bir Bundle kullanarak Etkinlikten Fragmente veri aktarmak için sadece burada putSerializable yöntem. - Gaëtan M.
@KaushikNP, eğer cevabım ihtiyaçlarınızı karşılarsa kabul etmeyi unutmayın;) - Gaëtan M.
Üzgünüm, şimdi kontrol edildi. Tabii ki, ödül sana gider ve cevap iyiydi, ama diğer cevaplar da ortaya çıkabilir ve daha büyük kitleler için de geçerli. - Kaushik NP
Merhaba, kodunuzu takip ediyordum ama bunu biraz uzatmak zorundayım. Farzedelim ObservableInteger sınıfın söyleyeceği başka bir alan var ObservableCharacter. Bunu gözlemlemek ve değişikliklerle ilgili ana sınıfı bilgilendirmek istiyorum. ObservableCharacter. Doğru bildirimi nasıl yapabilirim? - shurrok


Android'in Gözlemlenebilir'ini kullanmanın iyi bir örneği var (Java.util.Observable) İşte: https://andhradroid.wordpress.com/2012/04/05/object-observer-pattern-in-android/

Java'daki Observer desenini kullanmanın bir başka örneği: http://www.journaldev.com/1739/observer-design-pattern-in-java.

Genellikle iki yol vardır:

  • kullanım java.util.Observable.
  • Kendi tasarımını yap izlenebilir (daha esnek, daha derinlemesine anlamamıza yardımcı olun).

İkinci yolu daha çok beğeniyorum, örneğin: (Üzgünüm, çalıştığından emin olmak istiyorum ki tam bir örnek yapıyorum)

Gözlemlenebilir:

public interface MyObservable {
    void addObserver(MyObserver myObserver);
    void removeObserver(MyObserver myObserver);
    void notifyObserversAboutA();
    void notifyObserversAboutB();
}

Gözlemci:

public interface MyObserver {
    void onAChange(int newValue);
    void onBChange(int newValue);
}

MainActivity:

public class MainActivity extends AppCompatActivity implements MyObservable {

    private List<MyObserver> myObservers;
    private int a, b;
    private EditText etA;
    private EditText etB;

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

        myObservers = new ArrayList<>();

        ViewPager vpContent = (ViewPager) findViewById(R.id.activity_main_vp_content);
        etA = (EditText) findViewById(R.id.et_a);
        etB = (EditText) findViewById(R.id.et_b);
        Button btnOk = (Button) findViewById(R.id.btn_ok);

        //add fragments to viewpager
        List<Fragment> fragments = new ArrayList<>();
        Fragment1 fragment1 = new Fragment1();
        addObserver(fragment1);
        Fragment2 fragment2 = new Fragment2();
        addObserver(fragment2);

        fragments.add(fragment1);
        fragments.add(fragment2);
        MyFragmentPagerAdapter fragmentPagerAdapter
                = new MyFragmentPagerAdapter(getSupportFragmentManager(), fragments);
        vpContent.setAdapter(fragmentPagerAdapter);

        btnOk.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String a = etA.getText().toString().trim();
                String b = etB.getText().toString().trim();

                if (!a.equals("") && !b.equals("")) {
                    setA(Integer.parseInt(a));
                    setB(Integer.parseInt(b));
                }
            }
        });
    }

    private void setA(int value) {
        a = value;
        notifyObserversAboutA();
    }

    private void setB(int value) {
        b = value;
        notifyObserversAboutB();
    }

    @Override
    public void addObserver(MyObserver myObserver) {
        myObservers.add(myObserver);
    }

    @Override
    public void removeObserver(MyObserver myObserver) {
        myObservers.remove(myObserver);
    }

    @Override
    public void notifyObserversAboutA() {
        for (MyObserver observer : myObservers) {
            observer.onAChange(this.a);
        }
    }

    @Override
    public void notifyObserversAboutB() {
        for (MyObserver observer : myObservers) {
            observer.onBChange(this.b);
        }
    }
}

Fragman1:

public class Fragment1 extends Fragment implements MyObserver {

    private TextView tvA;
    private TextView tvB;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {

        View contentView = inflater.inflate(R.layout.fragment_basic, container, false);

        tvA = (TextView) contentView.findViewById(R.id.tv_a);
        tvB = (TextView) contentView.findViewById(R.id.tv_b);

        return contentView;
    }

    @Override
    public void onAChange(int newValue) {
        tvA.setText(String.valueOf("New value of a: " + newValue));
    }

    @Override
    public void onBChange(int newValue) {
        tvB.setText(String.valueOf("New value of b: " + newValue));
    }
}

Fragman2:

public class Fragment2 extends Fragment implements MyObserver {

    private TextView tvA;
    private TextView tvB;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {

        View contentView = inflater.inflate(R.layout.fragment_basic, container, false);

        tvA = (TextView) contentView.findViewById(R.id.tv_a);
        tvB = (TextView) contentView.findViewById(R.id.tv_b);

        return contentView;
    }

    @Override
    public void onAChange(int newValue) {
        tvA.setText(String.valueOf("New value of a: " + newValue));
    }

    @Override
    public void onBChange(int newValue) {
        tvB.setText(String.valueOf("New value of b: " + newValue));
    }
}

Adaptör:

public class MyFragmentPagerAdapter extends FragmentPagerAdapter {

    private List<Fragment> fragments;

    public MyFragmentPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
        super(fm);
        this.fragments = fragments;
    }

    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

    @Override
    public int getCount() {
        return fragments.size();
    }
}

Activity_main.xml ana düzeni:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="codeonce.thinktwice.testobserverpattern.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:id="@+id/linearLayout">


        <EditText
            android:id="@+id/et_a"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="20sp"
            android:inputType="number"
            android:hint="Type value for a"/>

        <EditText
            android:id="@+id/et_b"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="20sp"
            android:inputType="number"
            android:hint="Type value for b"/>

        <Button
            android:id="@+id/btn_ok"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20sp"
            android:layout_gravity="center_horizontal"
            android:text="OK"/>

    </LinearLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/activity_main_vp_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/linearLayout"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true">

    </android.support.v4.view.ViewPager>

</RelativeLayout>

Fragment_basic.xml parça düzeni:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center_horizontal">

    <TextView
        android:layout_marginTop="20dp"
        android:id="@+id/tv_a"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Value of a will appear here"
        android:textSize="20sp"/>

    <TextView
        android:id="@+id/tv_b"
        android:layout_marginTop="20dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Value of b will appear here"
        android:textSize="20sp"/>

</LinearLayout>

6
2018-04-14 07:13



Gözlemci deseni aşağıdaki durumlarda yardımcı olabilir mi (söz konusu)? stackoverflow.com/questions/47448453/... - Khushbu Shah


Reaktif Android'in bir parçası değil, muhtemelen bu kütüphaneyi arıyorsunuz: https://github.com/JakeWharton/RxBinding

Açılış sayfasında giriş örneği yok, bu yüzden javadoc'a bakmak zorundasınız. Bu yazı size iyi bir başlangıç ​​yapmalıdır: OnClick Event Android'den Gözlemlenebilir nasıl oluşturulur? Başlamak için Matt'in kod örneği.

RxView.clicks(myButton)
    .subscribe(new Action1<Void>() {
        @Override
        public void call(Void aVoid) {
            /* do something */
        }
    });

2
2018-03-23 17:51



Um, soru yanıltıcı olsaydı, ama tamamen yerel Gözlemlenebilir bir uygulama istiyorum, RxJS veya onunla herhangi bir diğer entegrasyon kullanmak zorunda değilsiniz. Yukarıdaki sorudaki bağlantıda da görüldüğü gibi Android'de de gözlemlenebilir özellikler sağlanmıştır. - Kaushik NP
Benim düşüncem önyargılıydı, son zamanlarda çok Reactive yapıyordum ;-) Java Gözlemciler GoF-Observer paterninin basit bir uygulamasıdır, RxJS-Observables ise Reaktif paradigmanın bir uygulamasıdır. RxJava olan RxJS'ye bir Java karşılığı var. - Benjamin Mesing