Вызов метода действия из фрагмента.

318

Пытаюсь вызвать метод в моей деятельности из фрагмента. Я хочу, чтобы фрагмент дал данные метода и получить данные при возврате метода. Я хочу добиться аналогичного вызова статического метода, но без использования статического, потому что это создает проблемы в деятельности.

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

Спасибо!

Йоаким Эрикссон
источник

Ответы:

821

От фрагмента к деятельности:

((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) act) .yourPublicMethod (); }
ericharlow
@Richard: Как мы можем выполнить противоположное действие, например, если мы должны выполнить метод фрагмента внутри Activity?
Химаншу
5
Это плохой дизайн и небезопасно разыгрывать Activity. Фрагмент не ограничен определенной деятельностью.
Авив Бен Шабат
3
@ Кей Не обязательно. Фрагменты могут быть использованы в качестве «фрагментов» любых более крупных действий, разбитых на части. Например, для создания адаптивных интерфейсов. Я редко использую один и тот же фрагмент и прикрепляю его к различным хостам активности.
Ричард
201

Вероятно, вам следует попытаться отделить фрагмент от действия, если вы хотите использовать его где-то еще. Вы можете сделать это, создав интерфейс, который реализует ваша деятельность.

Таким образом, вы бы определили интерфейс следующим образом:

Предположим, например, что вы хотите присвоить активности строку и вернуть целое число:

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, но я бы не стал использовать try-catch в onAttach. Пусть это не удастся. Если прослушиватель является необязательным (то есть сбой не подходит), добавьте метод set / addListener к фрагменту.
'32
Информацию о противоположной стороне см. На сайте developer.android.com/training/basics/fragments/… . Используя интерфейс фрагмента (который также является безопасным способом выполнения фрагмента-> активность комм., Как описано выше), вы также можете вызвать метод, который находится в вашем фрагменте из вашей активности, если вы хотите выполнить действие, основанное на вашем фрагменте-> активности комм.
Керем
Фрагменты предназначены для повторного использования и установки в любом действии. Что если у меня есть 5 действий, использующих один и тот же фрагмент? Ответ Марко является правильным и хорошей практикой для взаимодействия между фрагментами и фрагментами деятельности
blockwala
51

Для разработчиков Kotlin

(activity as YourActivityClassName).methodName()

Для разработчиков Java

((YourActivityClassName) getActivity()).methodName();
Васим К. Мемон
источник
выдает ошибку в kotlin, если мы запускаем этот код .. есть ли другой способ?
Джейк Гарбо
1
Когда я запускаю это. Я получаю нулевое значение ActivityClass, я думаю, что это не правильный способ сделать это в kotlin, даже без ошибок. или может быть ошибка?
Джейк Гарбо
@JakeGarbo Правильный путь, иначе за него не проголосовали 12 человек. Второе, что когда-то getActivity () возвращает null, проверяет эти вопросы на SO.
Васим К. Мемон
@JakeGarbo Да, они тебе сказали. Если это сработало для вас, тогда оцените это или найдите другой способ или научитесь сначала кодировать.
Васим К. Мемон
13

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

getActivity().whatever

Изнутри фрагмент. Это лучший ответ, потому что вы избегаете лишних бросков. Если вы не можете избежать бросков с помощью этого решения, используйте приведенный ниже.

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

что вам нужно сделать, это бросить на внешнюю деятельность

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

создание нового экземпляра приведет в замешательство рамку Android и не сможет ее распознать. смотрите также :

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

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

SiVi
источник
9

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

фрагмент:

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

Деятельность:

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

}
A.Alqadomi
источник
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

Это класс From 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

Я искал лучший способ сделать это, так как не каждый метод, который мы хотим вызвать, находится во Fragment с тем же родителем Activity.

В вашем фрагменте

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()имя метода, который вы хотите вызвать.

BIJAY_JHA
источник
0

Для Kotlin попробуйте

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)
    }
}
Infomaster
источник