MainActivity
で定義された値に完全に依存する多くのフラグメントでNavigation View
を実装したい。 MainActivityの変数にアクセスできることを知っています他のフラグメントからMainActivityで定義されたメソッドを使用して値を取得ですが、ここでのキャッチはMainActivityの変数の値がchange(AsyncThreadで実行されます)。ここで、コードを変更して、フラグメントが値を更新するに基づいてフラグメント自体の何らかのイベントを使用するか、SharedPreference
を使用します。ただし、SharedPreferencesを使用したくはありません。また、値の変更を不必要に何度もチェックする必要もありません。
RxJSでは、非同期で実行され、コンベアベルトと同様の方法で動作するObservableを使用しています。 official docs:Observable を少し調べてみると、Androidで同様の何かが利用可能であるという疑念が確認されましたが、適切なチュートリアルや実装方法の説明が見つかりませんでした。だから、ObservableがAndroidで、それが非同期で、そのベースがRxJS実装に類似している場合、いいえ、わかりません。)での動作を明確にする簡単なコードスニペットを探しています。 RxJS実装が必要)
テストケース:
MainActivity : int a, b (need observable for both variables)
Frag1 : int a1 , b1, a1changed(),b1changed()
Frag2 : int a2 , b2, a2Changed(), b2changed()
MainActivityには整数が含まれており、その値が変更されると、フラグメント全体の対応する整数に反映され、通知されている変更の各フラグメントに対して個別の関数が呼び出されます。
Activity
と1つのFragment
を使用した簡単な例を示しますが、他のフラグメントでも同じです。
最初に、観察したい値を表すクラスを作成する必要があります。この場合、単純なint
であるため、このint
を含むクラスを作成し、Observable
( Serializable
を実装して、アクティビティとフラグメント間の交換を簡素化します):
...
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を使用します(アクティビティレイアウトには、Button
の表示に使用されるFrameLayout
と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);
}
});
}
}
最後に、値の変更をリッスンする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);
}
}
私はあなたの変数にあなたの変数と同じ名前を付けようとします、それがあなたを助けることを願っています。
Android (Java.util.Observable)のObservableの使用に関する良い例があります:https://andhradroid.wordpress.com/2012/04/05/object-observer-pattern-in-Android/
そして、JavaでのObserverパターンの使用に関する別の例:http://www.journaldev.com/1739/observer-design-pattern-in-Java 。
一般的に、2つの方法があります。
私は2番目の方法がより好きです、例えば:(申し訳ありませんが、それが機能することを確認したいので、完全な例を作成します)
オブザーバブル:
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);
}
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);
}
}
}
フラグメント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>
Reactiveは、Androidの一部ではありませんが、おそらくこのライブラリを探しています: https://github.com/JakeWharton/RxBinding
ランディングページには入門的な例がないため、javadocを確認する必要があります。この投稿では、良いスタートを切ることができます。 OnClick Event AndroidからObservableを作成する方法? 開始するためのMattのコードサンプルを次に示します。
RxView.clicks(myButton)
.subscribe(new Action1<Void>() {
@Override
public void call(Void aVoid) {
/* do something */
}
});
Androidは現在、目的に合わせてLiveDataを備えたViewModelを提供しています。ビューモデルは、ライフサイクル(フラグメント、アクティビティ)でオブジェクトにバインドされ、このオブジェクトが存続する限り存続します。あなたの場合は、すべてのフラグメントからアクセスできるアクティビティにバインドされたビューモデルを作成します。
アクティビティ内の2つ以上のフラグメントが互いに通信する必要があることは非常に一般的です。ユーザーがリストからアイテムを選択するフラグメントと、選択したアイテムのコンテンツを表示する別のフラグメントがある、マスター/ディテールフラグメントの一般的なケースを想像してください。両方のフラグメントが何らかのインターフェース記述を定義する必要があり、所有者アクティビティが2つを結合する必要があるため、このケースは決して簡単ではありません。さらに、両方のフラグメントは、他のフラグメントがまだ作成または表示されないシナリオを処理する必要があります。
この一般的な問題点は、ViewModelオブジェクトを使用して対処できます。これらのフラグメントは、アクティビティスコープを使用してこの通信を処理するViewModelを共有できます。
フラグメント間でデータを共有するためにビューモデルを使用するには、以下を行う必要があります。
ここに中心的なコードスニペットがあります from Android documentation マスター詳細ビューにViewModelを使用する方法:
class SharedViewModel : ViewModel() {
val selected = MutableLiveData<Item>()
fun select(item: Item) {
selected.value = item
}
}
class MasterFragment : Fragment() {
private lateinit var itemSelector: Selector
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this).get(SharedViewModel::class.Java)
} ?: throw Exception("Invalid Activity")
itemSelector.setOnClickListener { item ->
// Update the UI
}
}
}
class DetailFragment : Fragment() {
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this).get(SharedViewModel::class.Java)
} ?: throw Exception("Invalid Activity")
model.selected.observe(this, Observer<Item> { item ->
// Update the UI
})
}
}