Викличте метод активності з фрагмента


318

Намагаюся викликати метод у своїй діяльності з фрагмента. Я хочу, щоб фрагмент давав дані методу та отримував дані, коли метод повертається. Я хочу досягти подібного, щоб застосувати статичний метод, але без використання статичного, оскільки це створює проблеми в діяльності.

Новинка до фрагментів, тому мені потрібно легке та педагогічне пояснення!

Дякую!

Відповіді:


820

Від фрагмента до активності:

((YourActivityClassName)getActivity()).yourPublicMethod();

Від активності до фрагменту:

FragmentManager fm = getSupportFragmentManager();

//if you added fragment via layout xml
YourFragmentClass fragment = (YourFragmentClass)fm.findFragmentById(R.id.your_fragment_id);
fragment.yourPublicMethod();

Якщо ви додали фрагмент за допомогою коду та застосували tagрядок, коли ви додали його фрагмент, використовуйте findFragmentByTagнатомість:

YourFragmentClass fragment = (YourFragmentClass)fm.findFragmentByTag("yourTag");

5
Будьте обережні, бо трапляються несподівані речі, якщо акторський склад не працює ..: S
Ewoks

48
Щоб уникнути проблеми виклику, використовуйте: Activity act = getActivity (); if (act instanceof YourActivityClassName) ((YourActivityClassName) дія) .yourPublicMethod (); }
ericharlow

@Richard: Як ми можемо виконати протилежну дію, як, наприклад, якщо нам доведеться виконати метод фрагмента всередині Діяльності?
Хіманшу

5
Це поганий дизайн і небезпечний для передачі діяльності. Фрагмент не обмежується певною діяльністю.
Авів Бен Шабат

3
@Kay Не обов’язково. Фрагменти можна використовувати як "фрагменти" будь-яких великих видів діяльності, розбитих на частини. Наприклад, створити чуйні інтерфейси користувача Я рідко використовую один і той же фрагмент і додаю його до різних хостів активності.
Річард

201

Напевно, ви повинні спробувати від'єднати фрагмент від активності, якщо ви хочете використовувати його десь в іншому місці. Це можна зробити, створивши інтерфейс, який реалізує ваша діяльність.

Отже, ви б визначили інтерфейс, наприклад:

Припустимо, наприклад, що ви хотіли надати активності String і запропонувати їй повернути цілий ряд:

public interface MyStringListener{
    public Integer computeSomething(String myString);
}

Це можна визначити у фрагменті або окремому файлі.

Тоді ви мали би свою діяльність реалізувати інтерфейс.

public class MyActivity extends FragmentActivity implements MyStringListener{

  @Override
  public Integer computeSomething(String myString){
   /** Do something with the string and return your Integer instead of 0 **/ 
   return 0;
  }

}

Тоді у вашому фрагменті у вас буде змінна MyStringListener, і ви встановите прослуховувач у фрагменті методом onAttach (Activity Activity).

public class MyFragment {

        private MyStringListener listener;

        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
            try {
                listener = (MyStringListener) context;
            } catch (ClassCastException castException) {
                /** The activity does not implement the listener. */
            }
        }

    }

редагувати (17.12.2015):onAttach(Activity activity) is deprecated, use onAttach(Context context) instead, it works as intended

Перша відповідь, безумовно, працює, але вона поєднує ваш поточний фрагмент із активністю хоста. Його найкраща практика зберігати фрагмент, від'єднаний від активності хоста, якщо ви хочете використовувати його в іншій активності.


58
Для всіх, хто дивиться на це, хоча прийнята відповідь, очевидно, працює, це кращий і безпечніший підхід з точки зору дизайну.
Пол Ріхтер

7
ця відповідь набагато краща з точки зору дизайну коду. також це не спричинить збоїв, якщо активність буде зафіксована неправильно
Девід Т.

3
+1, але я б не використав пробний лов у програмі OnAtach. Нехай провалюється. Якщо слухач необов’язковий (тобто відмова не підходить), додайте до фрагменту метод set / addListener.
ataulm

Зв'язок із протилежною стороною див. На веб-сайті: developer.android.com/training/basics/fragments/… . Використовуючи інтерфейс фрагмента (що також є безпечним способом зробити фрагмент-> активність com, як пояснено вище), ви можете викликати метод, який є у вашому фрагменті, також від вашої діяльності, якщо ви хочете вчинити дію на основі своєї фрагмента-> діяльності комм.
Керем

Фрагменти мають бути використані та встановлені в будь-якій діяльності. Що робити, якщо я маю 5 заходів, використовуючи той самий фрагмент? Відповідь Марко - правильна та хороша практика для взаємозв'язку між фрагментами та активністю-фрагмент
blockwala

51

Для розробників Kotlin

(activity as YourActivityClassName).methodName()

Для розробників Java

((YourActivityClassName) getActivity()).methodName();

це дає помилку в kotlin, якщо ми запустимо цей код .. чи є інший спосіб?
Джейк Гарбо

1
Коли я його запускаю. Я отримую нульове значення ActivityClass, я вважаю, що це не правильний спосіб зробити це в kotlin, навіть без помилок. а може, помилка?
Джейк Гарбо

@JakeGarbo Правильний шлях, інакше 12 людей не проголосували за це. Друга річ через деякий час getActivity () повертає нульову перевірку цих питань на ТАК.
Васім К. Мемон

@JakeGarbo Я вони вам сказали. ЯКЩО це працювало для вас, тоді оцініть це або знайдіть інший спосіб або навчіться кодувати спочатку.
Васим К. Мемон

13

Оновлення після того, як я більше зрозумію, як працюють фрагменти. Кожен фрагмент належить до батьківської діяльності. Тому просто використовуйте:

getActivity().whatever

Зсередини фрагмента. Це краща відповідь, тому що ви уникаєте надмірних ролей. Якщо ви не можете уникнути кастингу за допомогою цього рішення, використовуйте наведене нижче.

=============

що вам потрібно зробити - це привернути увагу до зовнішньої діяльності

((MainActivity) getActivity()).Method();

створення нового екземпляра буде заплутати кадр андроїда, і він не зможе розпізнати його. дивитися також :

https://stackoverflow.com/a/12014834/1984636

https://stackoverflow.com/a/2042829/1984636


9

Хоча мені цілком подобається відповідь Марко, я думаю, що справедливо зазначити, що ви також можете використовувати рамку публікації / підписки, щоб досягти такого ж результату, наприклад, якщо ви йдете з шиною подій, ви можете зробити наступне

фрагмент:

EventBus.getDefault().post(new DoSomeActionEvent()); 

Діяльність:

 @Subscribe
onSomeActionEventRecieved(DoSomeActionEvent doSomeActionEvent){
//Do something

}

5

У kotlin ви можете викликати метод активності з фрагмента, як показано нижче:

var mainActivity: MainActivity = activity as MainActivity
        mainActivity.showToast() //Calling show toast method of activity

2

Для доступу до функції, оголошеної у вашій діяльності через фрагмент, будь ласка, використовуйте інтерфейс, як показано у відповіді marco.

Для доступу до функції, оголошеної у вашому фрагменті через вашу діяльність, ви можете використовувати цю функцію, якщо у вас немає тегу чи ідентифікатора

private void setupViewPager(ViewPager viewPager) {
    //fragmentOne,fragmentTwo and fragmentThree are all global variables
    fragmentOne= new FragmentOne();
    fragmentTwo= new FragmentTwo();
    fragmentThree = new FragmentThree();

    viewPagerAdapteradapter = new ViewPagerAdapter(getSupportFragmentManager());
    viewPagerAdapteradapter.addFragment(fragmentOne, "Frag1");
    viewPagerAdapteradapter.addFragment(fragmentTwo, "Frag2");
    viewPagerAdapteradapter.addFragment(fragmentThree, "Frag3");

    //viewPager has to be instantiated when you create the activity:
    //ViewPager viewPager = (ViewPager)findViewById(R.id.pager);
    //setupViewPager(viewPager);
    //Where R.id.pager is the id of the viewPager defined in your activity's xml page.

    viewPager.setAdapter(viewPagerAdapteradapter);


    //frag1 and frag2 are also global variables
    frag1 = (FragmentOne)viewPagerAdapteradapter.mFragmentList.get(0);
    frag2 = (FragmentTwo)viewPagerAdapteradapter.mFragmentList.get(1);;


    //You can use the variable fragmentOne or frag1 to access functions declared in FragmentOne


}

Це ViewpagerAdapterClass

    class ViewPagerAdapter extends FragmentPagerAdapter {
    public final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager manager) {
        super(manager);
    }

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

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

    public void addFragment(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mFragmentTitleList.get(position);
    }
}

Ця відповідь - для таких, як я. Гарного дня.


1

Це з класу Fragment ...

((KidsStoryDashboard)getActivity()).values(title_txt,bannerImgUrl);

Цей код із класу активності ...

 public void values(String title_txts, String bannerImgUrl) {
    if (!title_txts.isEmpty()) {

//Do something to set text 
    }
    imageLoader.displayImage(bannerImgUrl, htab_header_image, doption);
}

1

Я спробував усі методи, показані в цій темі, і жоден для мене не працював, спробуйте цей. Це працювало для мене.

((MainActivity) getContext().getApplicationContext()).Method();

0

Я шукав найкращий спосіб зробити це, оскільки не кожен метод, який ми хочемо викликати, розташований у Фрагменті з тим же Батьком активності.

У вашому фрагменті

public void methodExemple(View view){

        // your code here

        Toast.makeText(view.getContext(), "Clicked clicked",Toast.LENGTH_LONG).show();
    }

У вашій діяльності

new ExempleFragment().methodExemple(context); 

0

((YourActivityName)getActivity()).functionName();

Приклад: ((SessionActivity)getActivity()).changeFragment();

Примітка. Назва класу повинна бути загальнодоступною


0
((your_activity) getActivity).method_name()

Звідки your_activityназва вашої діяльності та method_name()назва методу, який ви хочете зателефонувати.


0

Для Котліна спробуйте це

class DataForm : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        Tasks(this).getData()
    }

    fun getResponse(response: String) {
        // code
    }
}

class Tasks(private val context: Any) {
    fun getData() {

        val getContext = (context as DataForm).activity
        val getFragment = (context as DataForm)

        val responseListener = Response.Listener<String> { response ->
            getFragment.getResponse(response)
        }

        val errorListener = Response.ErrorListener { error ->
            error.printStackTrace();
        }

        val stringRequest = StringRequest(Request.Method.GET, url, responseListener, errorListener)
        Volley.newRequestQueue(getContext).add(stringRequest)
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.