Llamar a un método de actividad desde un fragmento


318

Tratando de llamar a un método en mi actividad desde un fragmento. Quiero que el fragmento proporcione los datos del método y obtenga los datos cuando regrese el método. Quiero lograr una llamada similar a un método estático, pero sin el uso de estática porque crea problemas en la actividad.

¡Nuevo en fragmentos así que necesito una explicación fácil y pedagógica!

¡Gracias!

Respuestas:


820

Del fragmento a la actividad:

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

De actividad a fragmento:

FragmentManager fm = getSupportFragmentManager();

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

Si agregó un fragmento a través del código y usó una tagcadena cuando agregó el fragmento, use findFragmentByTagen su lugar:

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

55
Tenga cuidado porque suceden cosas inesperadas si el elenco no funciona ...: S
Ewoks

48
Para evitar el problema de conversión, use: Activity act = getActivity (); if (act instanceof YourActivityClassName) ((YourActivityClassName) act) .yourPublicMethod (); }
ericharlow

@ Richard: ¿Cómo podemos realizar acciones opuestas, como, si tenemos que realizar un método de fragmento dentro de la Actividad?
Himanshu

55
Es un mal diseño y no es seguro lanzar una Actividad. Un fragmento no está limitado a una actividad específica.
Aviv Ben Shabat

3
@Kay No necesariamente. Los fragmentos se pueden usar como "fragmentos" de cualquier actividad más grande dividida. Para crear interfaces de usuario receptivas, por ejemplo. Raramente uso el mismo fragmento y lo adjunto a diferentes hosts de actividad.
Richard

201

Probablemente debería intentar desacoplar el fragmento de la actividad en caso de que quiera usarlo en otro lugar. Puede hacer esto creando una interfaz que implemente su actividad.

Entonces definiría una interfaz como la siguiente:

Supongamos, por ejemplo, que desea asignar a la actividad una Cadena y hacer que devuelva un Entero:

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

Esto se puede definir en el fragmento o en un archivo separado.

Entonces, su actividad implementaría la interfaz.

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

}

Luego, en su fragmento, tendría una variable MyStringListener y establecería el oyente en el método fragmentado onAttach (Actividad de actividad).

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

La primera respuesta definitivamente funciona, pero combina su fragmento actual con la actividad del host. Es una buena práctica mantener el fragmento desacoplado de la actividad del host en caso de que desee utilizarlo en otra actividad.


58
Para cualquiera que esté mirando esto, aunque la respuesta aceptada obviamente funciona, este es el mejor y más seguro enfoque desde una perspectiva de diseño.
Paul Richter

77
Esta respuesta es mucho mejor en términos de diseño de código. tampoco causaría fallas si la actividad se lanza mal
David T.

3
+1 pero no usaría un try-catch en onAttach. Deja que falle. Si el oyente es opcional (es decir, la falla no es apropiada), agregue un método set / addListener al fragmento.
ataulm

Para la comunicación del lado opuesto, consulte: developer.android.com/training/basics/fragments/… . Usando la interfaz del fragmento (que también es la forma segura de hacer fragmentos-> actividad de comunicación como se explicó anteriormente) puede llamar a un método que está en su fragmento de su actividad también si desea tomar una acción basada en su fragmento-> actividad com.
Kerem

Los fragmentos están destinados a ser reutilizados y configurados en cualquier actividad. ¿Qué pasa si tengo 5 actividades usando el mismo Fragmento? La respuesta de Marco es la correcta y una buena práctica para la comunicación entre fragmentos y Actividad-Fragmento
blockwala

51

Para desarrolladores de Kotlin

(activity as YourActivityClassName).methodName()

Para desarrolladores de Java

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

da error en kotlin si ejecutamos este código ... ¿hay alguna otra manera?
Jake Garbo

1
Cuando lo corro. Obtengo un valor nulo de ActivityClass, creo que esta no es la forma correcta de hacer esto en kotlin, incluso sin ningún error. o tal vez un error?
Jake Garbo el

@JakeGarbo De la manera adecuada, de lo contrario, 12 personas no lo han votado. Lo segundo que alguna vez getActivity () devuelve nulo comprueba esas preguntas en SO.
Wasim K. Memon

@JakeGarbo Ya te lo dijeron. SI funcionó para usted, entonces aprecie o encuentre otra forma o aprenda a codificar primero.
Wasim K. Memon

13

Actualización después de que entiendo más cómo funcionan los fragmentos. Cada fragmento pertenece a una actividad principal. Así que solo usa:

getActivity().whatever

Desde dentro del fragmento. Es una mejor respuesta porque evita los moldes superfluos. Si no puede evitar los moldes con esta solución, use el siguiente.

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

lo que tienes que hacer es lanzar a la actividad exterior

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

crear una nueva instancia confundirá el marco de Android y no podrá reconocerlo. ver también :

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

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


9

Aunque me gusta completamente la respuesta de Marco, creo que es justo señalar que también puede usar un marco basado en publicación / suscripción para lograr el mismo resultado, por ejemplo, si va con el bus de eventos, puede hacer lo siguiente

fragmento :

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

Actividad:

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

}

5

En kotlin puede llamar al método de actividad desde un fragmento como el siguiente:

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

2

Para acceder a una función declarada en su Actividad a través de su fragmento, utilice una interfaz, como se muestra en la respuesta de marco.

Para acceder a una función declarada en su Fragmento a través de su actividad, puede usar esto si no tiene una etiqueta o una identificación

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


}

Esta es la 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 respuesta es para novatos como yo. Tenga un buen día.


1

Esta es de la clase Fragmento ...

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

Este código de la clase de actividad ...

 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

He intentado con todos los métodos que se muestran en este hilo y ninguno funcionó para mí, prueba este. Funcionó para mi.

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

0

He estado buscando la mejor manera de hacerlo, ya que no todos los métodos a los que queremos llamar se encuentran en Fragmento con la misma Actividad principal.

En tu fragmento

public void methodExemple(View view){

        // your code here

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

En su actividad

new ExempleFragment().methodExemple(context); 

0

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

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

Nota: el nombre de la clase debe estar en público


0
((your_activity) getActivity).method_name()

¿Dónde your_activityestá el nombre de su actividad y method_name()el nombre del método al que desea llamar?


0

Para Kotlin pruébalo

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)
    }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.