Chamar um método de atividade de um fragmento

318

Tentando chamar um método na minha atividade a partir de um fragmento. Eu quero que o fragmento forneça os dados do método e obtenha os dados quando o método retornar. Eu quero alcançar semelhante ao chamar um método estático, mas sem o uso de estática, pois cria problemas na atividade.

Novo em fragmentos, por isso preciso de uma explicação fácil e pedagógica!

Obrigado!

Joakim Ericsson
fonte

Respostas:

820

Do fragmento à atividade:

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

Da atividade ao fragmento:

FragmentManager fm = getSupportFragmentManager();

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

Se você adicionou fragmento via código e usou uma tagstring ao adicionar seu fragmento, use findFragmentByTag:

YourFragmentClass fragment = (YourFragmentClass)fm.findFragmentByTag("yourTag");
Richard
fonte
5
Tenha cuidado, pois coisas inesperadas acontecem se o elenco não funcionar ..: S
Ewoks
48
Para evitar o problema de conversão, use: Activity act = getActivity (); if (act instanceof YourActivityClassName) ((YourActivityClassName) age) .yourPublicMethod (); }
ericharlow 9/09/13
@ Richard: Como podemos executar uma ação oposta, como se precisamos executar o método de um fragmento dentro da Atividade?
Himanshu
5
É um design ruim e inseguro transmitir uma atividade. Um fragmento não está limitado a uma atividade específica.
Aviv Ben Shabat
3
@ Kay Não necessariamente. Fragmentos podem ser usados ​​como "fragmentos" de qualquer atividade maior dividida. Para criar interfaces de usuário responsivas, por exemplo. Eu raramente uso o mesmo fragmento e o anexo a diferentes hosts de atividades.
Richard
201

Você provavelmente deve tentar desacoplar o fragmento da atividade, caso queira usá-lo em outro lugar. Você pode fazer isso criando uma interface que sua atividade implementa.

Então você definiria uma interface como a seguinte:

Suponha, por exemplo, que você queira atribuir uma atividade à String e que ela retorne um número inteiro:

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

Isso pode ser definido no fragmento ou em um arquivo separado.

Então você teria sua atividade implementando a interface.

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;
  }

}

Em seu fragmento, você teria uma variável MyStringListener e configuraria o ouvinte no método fragment 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. */
            }
        }

    }

editar (17.12.2015):onAttach(Activity activity) is deprecated, use onAttach(Context context) instead, it works as intended

A primeira resposta definitivamente funciona, mas associa seu fragmento atual à atividade do host. É uma boa prática manter o fragmento dissociado da atividade do host, caso você queira usá-lo em outra atividade.

Marco RS
fonte
58
Para qualquer um que veja isso, embora a resposta aceita obviamente funcione, essa é a abordagem melhor e mais segura do ponto de vista do design.
Paul Richter
7
Essa resposta é muito melhor em termos de design de código. também não iria causar falhas se a actividade for escalado errado
David T.
3
+1, mas eu não usaria um try-catch no onAttach. Deixe falhar. Se o ouvinte for opcional (ou seja, falhar não é apropriado), adicione um método set / addListener ao fragmento.
ataulm
Para a comunicação do lado oposto, consulte: developer.android.com/training/basics/fragments/… . Usando a interface do fragmento (que também é a maneira segura de fazer a comunicação fragment-> activity, conforme explicado acima), você pode chamar um método que esteja no seu fragmento a partir da sua atividade, se desejar executar uma ação com base na sua fragment-> atividade comm.
Kerem
Fragmentos devem ser reutilizados e configurados em qualquer Atividade. E se eu tiver 5 atividades usando o mesmo fragmento? A resposta de Marco é a correta e uma boa prática para inter-fragmento e comunicação Activity-Fragment
blockwala
51

Para desenvolvedores do Kotlin

(activity as YourActivityClassName).methodName()

Para desenvolvedores Java

((YourActivityClassName) getActivity()).methodName();
Wasim K. Memon
fonte
dá erro no kotlin se rodarmos esse código .. existe outra maneira?
Jake Garbo
1
Quando eu corro. Eu recebo o valor nulo de ActivityClass, acho que essa não é a maneira correta de fazer isso no kotlin, mesmo sem erros. ou talvez um bug?
Jake Garbo
@JakeGarbo Sua maneira correta, caso contrário, 12 pessoas não votaram a favor. segunda coisa, algum tempo, getActivity () retorna nulo, verifique essas questões no SO.
Wasim K. Memon
@JakeGarbo Ya, eles te disseram. Se funcionou para você, aprecie-o ou encontre outro caminho ou aprenda a codificar primeiro.
Wasim K. Memon
13

Atualizar depois que eu entender mais como os fragmentos funcionam. Cada fragmento pertence a uma atividade pai. Então, basta usar:

getActivity().whatever

De dentro do fragmento. É uma resposta melhor porque você evita lançamentos supérfluos. Se você não pode evitar os lançamentos com esta solução, use o abaixo.

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

o que você precisa fazer é lançar na atividade externa

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

a criação de uma nova instância confundirá o quadro do Android e não poderá reconhecê-lo. Veja também :

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

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

sivi
fonte
9

Embora eu goste completamente da resposta de Marco, acho justo ressaltar que você também pode usar uma estrutura baseada em publicação / assinatura para obter o mesmo resultado, por exemplo, se você for com o barramento de eventos, poderá fazer o seguinte

fragmento:

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

Atividade:

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

}
A.Alqadomi
fonte
5

No kotlin você pode chamar o método de atividade do fragmento como abaixo:

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

Para acessar uma função declarada em sua Atividade através do seu fragmento, use uma interface, conforme mostrado na resposta por marco.

Para acessar uma função declarada em seu Fragmento por meio de sua atividade, você pode usá-la se não tiver uma tag ou um id

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


}

Este é o 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);
    }
}

Esta resposta é para noobs como eu. Tenha um bom dia.

alta velocidade
fonte
1

Esta é da classe Fragment ...

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

Este código da classe de atividade ...

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

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

Eu tentei com todos os métodos mostrados neste segmento e nenhum funcionou para mim, tente este. Funcionou para mim.

((MainActivity) getContext().getApplicationContext()).Method();
Sergio Velásquez
fonte
0

Eu tenho procurado a melhor maneira de fazer isso, pois nem todos os métodos que queremos chamar estão localizados no fragmento com o mesmo pai da atividade.

No seu fragmento

public void methodExemple(View view){

        // your code here

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

Na sua atividade

new ExempleFragment().methodExemple(context); 
Maravilho Singa
fonte
0

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

Exemplo: ((SessionActivity)getActivity()).changeFragment();

Nota: o nome da classe deve estar em público

Harsha Vardhan Reddy N
fonte
0
((your_activity) getActivity).method_name()

Onde your_activityé o nome da sua atividade e method_name()o nome do método que você deseja chamar.

BIJAY_JHA
fonte
0

Para Kotlin, experimente

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
fonte