在安卓系统中使用 Observable

2022-09-01 06:44:56

我想实现一个具有许多片段的,这些片段完全依赖于 中定义的值。我知道可以使用 MainActivity 中定义的方法从其他 Fragments 访问 MainActivity 中的变量来获取值,但这里的问题是 MainActivity 中的变量的值可能会更改(在 AsyncThread 上运行)。现在,我要么更改代码,以便我的片段根据片段本身中的某些事件更新其值,要么使用 .但我不想使用共享首选项,也不必多次不必要地检查值的变化。Navigation ViewMainActivitySharedPreference

我知道在RxJS中,我们使用可观察的异步运行,并以类似于传送带的方式工作。通过官方文档进行了一些谷歌搜索 :Observable证实了我对Android中类似内容的怀疑,但找不到任何关于如何实现它的适当教程或解释。因此,我正在寻找一个简单的代码片段,可以清楚地说明Observable在Android中的工作方式,以及它是否是Async,以及它是否基于类似于RxJS的实现。(不,我不想要 RxJS 实现)

测试用例:

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

MainActivity 包含整数,其值在更改时应反映在片段中的相应整数中,并在注意到更改时为每个片段调用单独的函数。


答案 1

下面是一个包含 和 单个的简单示例,但与其他片段相同。ActivityFragment

首先,您需要创建一个代表要观察的值的类,在您的情况下,它很简单,因此创建一个包含此值和扩展的类(它实现以简化活动和片段之间的交换):intintObservableSerializable

...
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);
    }
}

然后在活动中使用此可观察的 int(活动布局包含 用于显示 a 和 a):ButtonFrameLayoutFragment

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);
            }
        });
    }
}

最后,创建一个侦听值变化的函数:Fragment

...
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);
    }
}

我试图将我的变量命名为与你的相同,我希望它能帮助你。


答案 2

这里有一个关于使用Android的Observable(java.util.Observable)的很好的例子:https://andhradroid.wordpress.com/2012/04/05/object-observer-pattern-in-android/

另一个关于在Java中使用观察者模式的例子:http://www.journaldev.com/1739/observer-design-pattern-in-java

通常,有两种方法:

  • 使用 java.util.Observable
  • 设计您自己的可观察量(更灵活,帮助我们更深入地了解)。

我更喜欢第二种方式,例如:(对不起,我想确保它有效,所以我做了一个完整的例子)

可观察的

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

观察家:

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

主要活动:

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);
        }
    }
}

片段1:

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));
    }
}

片段2:

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));
    }
}

适配器:

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:

<?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:

<?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>

推荐