web-dev-qa-db-fra.com

Android: comment envoyer l'interface d'une activité à une autre

J'ai une interface comme celle-ci:

public interface MyInterface {
    public void aMethod();
}

Mon objet personnalisé:

public class MyObject {

    private Context context;
    private MyInterface inter;

    public MyObject(Context context) {
        this.context = context;
        this.inter = (MyInterface) this.context;
        inter.aMethod();
    }
}

Activité principale:

public class MainActivity extends Activity implements MyInterface {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyObject my = new MyObject(this);

    }

    @Override
    public void aMethod() {
        Toast.makeText(this, "done", Toast.LENGTH_SHORT).show();
    }
}  

Ici, à l'intérieur du constructeur MyObject, je peux obtenir l'interface à partir du contexte, puis communiquer avec l'activité.

Mais comment envoyer une interface d'une activité à une autre?
J'ai besoin d'appeler une méthode dans Activity1 depuis Activity2
Existe-t-il un moyen comme celui-ci?

Remarque: je ne veux pas utiliser de fragment.

25
palatok

D'abord et avant tout, c'est très mauvais:

this.inter = (MyInterface) this.context;

Si vous passez un contexte dans le constructeur qui n'implémente pas votre interface, votre application plantera et il est facile de commettre une telle erreur. Donc, vous voyez, c'est très sujet aux erreurs, implémentez-le plutôt comme ceci:

public class MyObject {

    private Context context;
    private MyInterface inter;

    public MyObject(Context context, MyInterface inter) {
        this.context = context;
        this.inter =  inter;
        inter.aMethod();
    }
}

De cette façon, c'est beaucoup plus sûr et plus propre.


Pour envoyer le Object à un autre Activity assurez-vous qu'il implémente Serializable comme ceci:

public interface MyInterface extends Serializable {
    public void aMethod();
}

Et maintenant, vous pouvez simplement ajouter l'interface en supplément au Intent qui démarre l'autre Activity:

Intent intent = new Intent(context, OtherActivity.class);
intent.putExtra("interface", inter);
startActivity(intent);

Et dans le OtherActivity vous pouvez obtenir le Object du Intent comme ceci:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Intent intent = getIntent();
    MyInterface inter = (MyInterface) intent.getSerializableExtra("interface");

    ...
}

MODIFIER:

Lorsque vous faites quelque chose comme ça dans votre Activity vous créez une classe anonyme:

OnCreateListener inter = new OnCreateListener() {

    @Override
    public void onObjCreate() {
        Log.d("pltk", "dfgbfdgh");
    }
};

Le problème avec une telle classe anonyme est qu'elle n'est pas statique, ce qui signifie que vous pouvez toujours accéder aux méthodes et aux variables de la classe dans laquelle cet écouteur est imbriqué. En interne, la raison en est que cette nouvelle classe conserve une référence à l'instance de la classe qui l'a créée, dans votre cas le Activity englobant. C'est une bonne chose et nous l'utilisons tout le temps pour OnClickListener etc. Mais dans votre cas, c'est un problème parce que vous voulez envoyer ce Object à un autre Activity. La référence interne à l'ancien Activity l'empêche d'être sérialisé et c'est une bonne chose. Si vous pouviez simplement envoyer un Object comme ça, vous créeriez des fuites de mémoire comme un fou à cause de toutes les anciennes références que le garbage collector ne peut pas collecter.

La solution est assez simple, vous pouvez soit définir la classe dans son propre fichier, soit rendre la classe statique. Statique dans ce contexte signifie que la classe est essentiellement traitée comme dans son propre fichier séparé et ne peut donc pas accéder à l'instance de la classe englobante.

Donc, pour résumer ce que vous avez à faire, vous devez soit garder la classe imbriquée et la définir comme suit:

public class YourActivity extends Activity {

    private static class OnCreateListenerImpl implements OnCreateListener {

        @Override
        public void onObjCreate() {
            Log.d("pltk", "dfgbfdgh");
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_palatok);

        OnCreateListener inter = new OnCreateListenerImpl();
        Intent in = new Intent(Palatok.this, SecondActivity.class);
        in.putExtra("ob", inter);
        startActivity(in);
    }
}

Ou vous pouvez déplacer l'implémentation dans son propre fichier séparé:

public class OnCreateListenerImpl implements OnCreateListener {

    @Override
    public void onObjCreate() {
        Log.d("pltk", "dfgbfdgh");
    }
}

Bien que la raison pour laquelle vous souhaitiez envoyer un OnCreateListener à un autre Activity m'échappe encore, cela devrait résoudre votre problème.

J'espère que je pourrais vous aider et si vous avez d'autres questions, n'hésitez pas à demander!

42
Xaver Kapeller

C'est possible, mais ce type d'interraction d'activité <-> activité entraînera des fuites de mémoire. Vous devez utiliser LocalBroadcastManager ( http://developer.Android.com/reference/Android/support/v4/content/LocalBroadcastManager.html ) à la place.

3
Stepango