Új hozzászólás Aktív témák

  • Karma
    félisten

    Ha megváltoznak az adatok, hogyan tudom elérni a fragmentet, amiben a lista van? Jelenleg így épül fel az UI:

    MainActivity így néz ki:

    <RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.attilapalf.exceptional.ui.main.MainActivity">

    <android.support.v4.view.ViewPager
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v4.view.PagerTabStrip
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="top"
    />

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

    </RelativeLayout>

    Tehát ez egy lapozható felület, 3 oldala van. Itt van a MainPagerAdapter kódja:

    public class MainPagerAdapter extends FragmentPagerAdapter {

    public MainPagerAdapter(FragmentManager fm) {
    super(fm);
    }

    @Override
    public Fragment getItem(int position) {
    switch (position) {
    case 0:
    return new MainFragment();
    case 1:
    return new ExceptionsFragment();
    case 2:
    return new FriendsFragment();
    default:
    return new MainFragment();
    }
    }

    @Override
    public int getCount() {
    return 3;
    }

    @Override
    public CharSequence getPageTitle(int position) {
    switch (position) {
    case 0:
    return "Main";
    case 1:
    return "My Exceptions";
    case 2:
    return "My Friends";
    default:
    return "unknown";
    }
    }
    }

    Az ExceptionsFragment kódja pedig itt van. A notifyDatasetChanged() metódusát szeretném valahogy meghívni a MainActivity throwMeExcClicked(View) metódusban:

    private static String makeFragmentName(int viewPagerId, int index) {
    return "android:switcher:" + viewPagerId + ":" + index;
    }


    public void throwMeExcClicked(View view) {
    Exception e = Exception.getRandomException();

    synchronized (this) {
    if (mLocation == null) {
    setLocationExceptions.add(e);

    } else {
    e.setLocation(mLocation);
    exceptionPreferences.addException(e);
    }
    }

    String fragmentTag = makeFragmentName(R.id.pager, 1);
    FragmentManager fragmentManager = getFragmentManager();
    Fragment eFrag = fragmentManager.findFragmentByTag(fragmentTag);

    // jó volna valahogy elérni az ExceptionsFragmentet!!!
    }

    Azt semmiképp se tartom jó ötletnek, hogy a MainActivity közvetlenül ismerje az ExceptionsFragment példányt. Mivel a ViewPager is virtualizál (azaz a ListViewhoz hasonlóan csak a látható vagy szomszédos viewkat tartja életben), elég kusza helyzetek alakulhatnak ki.

    Hogy ezt hogyan kerüld el, van pár lehetőség.

    Az első a klasszikus jávás Listener minta. Az activityben definiálsz egy Listener interfészt, amit a fragment megvalósít, valamint egy kis ceremóniát, hogy fel lehessen rá iratkozni. A fragment onAttach metódusában regisztrál, onDetachban pedig deregisztrál - ameddig össze van kötve, az activity tud neki jelezni. Mondjuk a konkrét activity osztályt is elfedném akkor már.

    ExceptionChangeListener.java:

    public interface ExceptionChangeListener {
    void onExceptionsChanged();
    }

    ExceptionSource.java:

    public interface ExceptionSource {
    boolean addExceptionChangeListener(ExceptionChangeListener listener);
    boolean removeExceptionChangeListener(ExceptionChangeListener listener);
    }

    MainActivity.java:

    public class MainActivity extends AppCompatActivity implements ExceptionSource {
    private final Set<ExceptionChangeListener> mListeners = new HashSet<ExceptionChangeListener>();

    ...

    public boolean addExceptionChangeListener(ExceptionChangeListener listener) {
    return mListeners.add(listener);
    }

    public boolean removeExceptionChangeListener(ExceptionChangeListener listener) {
    return mListeners.remove(listener);
    }

    ... amikor módosítottad a listát, hívd meg ezt ...

    private void notifyListeners() {
    for (ExceptionChangeListener listener : mListeners) {
    listener.onExceptionsChanged();
    }
    }
    }

    ExceptionsFragment.java:

    public class ExceptionsFragment extends Fragment implements ExceptionChangeListener {
    @Override
    public void onAttach (Activity activity) {
    super.onAttach(activity);
    if (activity instanceof ExceptionSource) {
    ((ExceptionSource)activity).addExceptionChangeListener(this);
    }
    }

    @Override
    public void onDetach() {
    if (getActivity() instanceof ExceptionSource) {
    ((ExceptionSource)getActivity()).removeExceptionChangeListener(this);
    }

    super.onDetach();
    }

    @Override
    public void onExceptionsChanged() {
    adapter.notifyDataSetChanged();
    }
    }

    Huh, ez elég hosszú lett. A másik kettőbe inkább nem megyek bele így nyilvánosan kód szinten.

    A második az lenne, hogy a fragmented onAttach/onDetach időben egy BroadcastReceivert indít el, az activity pedig Intenteket dobál, ha változás van. Ez lehet közvetlenül a sendBroadcast metódussal, vagy LocalBroadcastManagerrel. Lazább csatolás, de elég sok ceremónia.

    A harmadik pedig egy event bus bevezetése (pl. Otto), ahol a logika ugyanaz mint a másodikban, csak kevesebb extra kód (eltekintve a lib dependenciától). Én így 2015-ben egyébként ezt az utat javaslom.

Új hozzászólás Aktív témák