Android : 片段和观察者
Android : Fragment and Observer
主要目标是更新主要来自其自身的片段信息class。
主要activity:
public class MainActivity extends AppCompatActivity {
final Handler GUIHandler = new Handler();
final Runnable r = new Runnable()
{
public void run()
{
updateFragments();
GUIHandler.postDelayed(this, 1000);
}
};
@Override
protected void onPause() {
super.onPause();
GUIHandler.removeCallbacks(r);
}
@Override
protected void onResume() {
super.onResume();
GUIHandler.postDelayed(r, 600);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mViewPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new PagerAdapter(getSupportFragmentManager(), tabLayout.getTabCount());
mViewPager.setAdapter(mPagerAdapter);
...
}
private void updateFragments() {
mPagerAdapter.updateFragments();
}
PagerAdapter:
public class PagerAdapter extends FragmentStatePagerAdapter {
int mNumOfTabs;
private Observable mObservers = new FragmentObserver();
public PagerAdapter(FragmentManager fm, int NumOfTabs) {
super(fm);
this.mNumOfTabs = NumOfTabs;
}
@Override
public Fragment getItem(int position) {
mObservers.deleteObservers(); // Clear existing observers.
switch (position) {
case 0:
FragmentWeather weatherTab = new FragmentWeather();
weatherTab.setActivity(mActivity);
if(weatherTab instanceof Observer)
mObservers.addObserver((Observer) weatherTab);
return weatherTab;
case 1:
FragmentMemo tab2 = new FragmentMemo();
return tab2;
case 2:
FragmentHardware tab3 = new FragmentHardware();
return tab3;
default:
return null;
}
}
public void updateFragments() {
mObservers.notifyObservers();
}
}
FragmentObserver
public class FragmentObserver extends Observable {
@Override
public void notifyObservers() {
setChanged(); // Set the changed flag to true, otherwise observers won't be notified.
super.notifyObservers();
Log.d("Observer", "Sending notification");
}
}
片段天气:
public class FragmentWeather extends Fragment implements Observer {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
...
return layout;
}
public void setTemperatures(){
Log.d("Android", "setTemperatures is called");
}
@Override
public void update(Observable observable, Object data) {
setTemperatures();
}
}
现在的问题是,在应用程序开始时创建片段时,PagerAdapter::getItem()
不会被调用。这意味着 WeatherFragment
不会与 mObservers
相关联。如果我滑动到第三个视图然后向后滑动,一切正常。如何对其进行重组以使其发挥作用?
这一行:
mObservers.deleteObservers(); // Clear existing observers.
正在删除所有观察者,但是方法 getItem
被调用了几次,这意味着只有最后一次它调用任何东西都留在那里。 删除这一行。
此外,下面的代码是一个非常糟糕的模式,它会多次出错:
case 0:
FragmentWeather weatherTab = new FragmentWeather();
weatherTab.setActivity(mActivity);
if(weatherTab instanceof Observer)
mObservers.addObserver((Observer) weatherTab);
return weatherTab;
那是因为系统会在必要时重新创建片段,所以 setActivity
毫无意义,addObserver
也是如此。系统需要 destroy/recreate 片段的那一刻,你就会有那些旧片段的内存泄漏,旧的 activity,而新的不会有 activity 并且赢了不要在旁观者身上。
这里最好的情况是依赖片段的自然回调。下面是一个示例(ps.: 是用心输入的,我相信可能会有一些错误,但你会明白的)
public interface ObservableGetter{
public Observable getObservable();
}
public void MyFragment extends Fragment implements Observer {
@Override onAttach(Activity activity){
super.onAtttach(activity);
if(activity instanceof ObservableGetter){
((ObservableGetter)activity).getObservable().
addObserver(this);
}
}
@Overrude onDetach(){
Activity activity = getActivity();
if(activity instanceof ObservableGetter){
((ObservableGetter)activity).getObservable().
removeObserver(this);
}
super.onDetach();
}
}
然后你可以让 activity 实现 ObservableGetter 并在其上安装 Observable。
那么您的 adapter
代码将是:
case 0:
return new FragmentWeather();
其余所有逻辑都使用常规回调。
希望对您有所帮助ps。
主要目标是更新主要来自其自身的片段信息class。
主要activity:
public class MainActivity extends AppCompatActivity {
final Handler GUIHandler = new Handler();
final Runnable r = new Runnable()
{
public void run()
{
updateFragments();
GUIHandler.postDelayed(this, 1000);
}
};
@Override
protected void onPause() {
super.onPause();
GUIHandler.removeCallbacks(r);
}
@Override
protected void onResume() {
super.onResume();
GUIHandler.postDelayed(r, 600);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mViewPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new PagerAdapter(getSupportFragmentManager(), tabLayout.getTabCount());
mViewPager.setAdapter(mPagerAdapter);
...
}
private void updateFragments() {
mPagerAdapter.updateFragments();
}
PagerAdapter:
public class PagerAdapter extends FragmentStatePagerAdapter {
int mNumOfTabs;
private Observable mObservers = new FragmentObserver();
public PagerAdapter(FragmentManager fm, int NumOfTabs) {
super(fm);
this.mNumOfTabs = NumOfTabs;
}
@Override
public Fragment getItem(int position) {
mObservers.deleteObservers(); // Clear existing observers.
switch (position) {
case 0:
FragmentWeather weatherTab = new FragmentWeather();
weatherTab.setActivity(mActivity);
if(weatherTab instanceof Observer)
mObservers.addObserver((Observer) weatherTab);
return weatherTab;
case 1:
FragmentMemo tab2 = new FragmentMemo();
return tab2;
case 2:
FragmentHardware tab3 = new FragmentHardware();
return tab3;
default:
return null;
}
}
public void updateFragments() {
mObservers.notifyObservers();
}
}
FragmentObserver
public class FragmentObserver extends Observable {
@Override
public void notifyObservers() {
setChanged(); // Set the changed flag to true, otherwise observers won't be notified.
super.notifyObservers();
Log.d("Observer", "Sending notification");
}
}
片段天气:
public class FragmentWeather extends Fragment implements Observer {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
...
return layout;
}
public void setTemperatures(){
Log.d("Android", "setTemperatures is called");
}
@Override
public void update(Observable observable, Object data) {
setTemperatures();
}
}
现在的问题是,在应用程序开始时创建片段时,PagerAdapter::getItem()
不会被调用。这意味着 WeatherFragment
不会与 mObservers
相关联。如果我滑动到第三个视图然后向后滑动,一切正常。如何对其进行重组以使其发挥作用?
这一行:
mObservers.deleteObservers(); // Clear existing observers.
正在删除所有观察者,但是方法 getItem
被调用了几次,这意味着只有最后一次它调用任何东西都留在那里。 删除这一行。
此外,下面的代码是一个非常糟糕的模式,它会多次出错:
case 0:
FragmentWeather weatherTab = new FragmentWeather();
weatherTab.setActivity(mActivity);
if(weatherTab instanceof Observer)
mObservers.addObserver((Observer) weatherTab);
return weatherTab;
那是因为系统会在必要时重新创建片段,所以 setActivity
毫无意义,addObserver
也是如此。系统需要 destroy/recreate 片段的那一刻,你就会有那些旧片段的内存泄漏,旧的 activity,而新的不会有 activity 并且赢了不要在旁观者身上。
这里最好的情况是依赖片段的自然回调。下面是一个示例(ps.: 是用心输入的,我相信可能会有一些错误,但你会明白的)
public interface ObservableGetter{
public Observable getObservable();
}
public void MyFragment extends Fragment implements Observer {
@Override onAttach(Activity activity){
super.onAtttach(activity);
if(activity instanceof ObservableGetter){
((ObservableGetter)activity).getObservable().
addObserver(this);
}
}
@Overrude onDetach(){
Activity activity = getActivity();
if(activity instanceof ObservableGetter){
((ObservableGetter)activity).getObservable().
removeObserver(this);
}
super.onDetach();
}
}
然后你可以让 activity 实现 ObservableGetter 并在其上安装 Observable。
那么您的 adapter
代码将是:
case 0:
return new FragmentWeather();
其余所有逻辑都使用常规回调。
希望对您有所帮助ps。