194 votes

Obtenir une activité à partir d'un contexte dans Android

Celui-ci me laisse perplexe.

Je dois appeler une méthode d'activité à partir d'une classe de mise en page personnalisée. Le problème est que je ne sais pas comment accéder à l'activité à partir de la mise en page.

ProfilView

public class ProfileView extends LinearLayout
{
    TextView profileTitleTextView;
    ImageView profileScreenImageButton;
    boolean isEmpty;
    ProfileData data;
    String name;

    public ProfileView(Context context, AttributeSet attrs, String name, final ProfileData profileData)
    {
        super(context, attrs);
        ......
        ......
    }

    //Heres where things get complicated
    public void onClick(View v)
    {
        //Need to get the parent activity and call its method.
        ProfileActivity x = (ProfileActivity) context;
        x.activityMethod();
    }
}

ProfilActivité

public class ProfileActivityActivity extends Activity
{
    //In here I am creating multiple ProfileViews and adding them to the activity dynamically.

    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.profile_activity_main);
    }

    public void addProfilesToThisView()
    {
        ProfileData tempPd = new tempPd(.....)
        Context actvitiyContext = this.getApplicationContext();
        //Profile view needs context, null, name and a profileData
        ProfileView pv = new ProfileView(actvitiyContext, null, temp, tempPd);
        profileLayout.addView(pv);
    }
}

Comme vous pouvez le voir ci-dessus, j'instancie le profileView de manière programmatique et je passe le ActivityContext avec lui. 2 questions :

  1. Est-ce que je passe le bon contexte dans le Profileview ?
  2. Comment obtenir l'activité contenue dans le contexte ?

487voto

Boris Strandjev Points 18480

De votre Activity , il suffit de passer dans this comme le Context pour votre mise en page :

ProfileView pv = new ProfileView(this, null, temp, tempPd);

Ensuite, vous aurez un Context dans la mise en page, mais vous saurez que c'est en fait votre Activity et vous pouvez le couler pour avoir ce dont vous avez besoin :

Activity activity = (Activity) context;

59 votes

Vous ne pouvez pas être sûr que le contexte avec lequel vous travaillez est un contexte d'activité ou un contexte d'application. Essayez de passer un contexte d'application à une DialogView, regardez-la se planter, et vous verrez la différence.

7 votes

Boris, la question demande s'il existe un moyen d'obtenir une activité à partir d'un contexte. Ce n'est pas possible. Bien sûr, vous pouvez faire un casting, mais c'est en dernier recours. Si vous voulez traiter le contexte comme une activité, alors ne faites pas de downcast vers une activité. Cela permet d'obtenir un code plus simple et de réduire les risques de bogues plus tard, lorsqu'une autre personne assurera la maintenance de votre code.

6 votes

Notez que l'utilisation de "getApplicationContext()" au lieu de "this" ne fonctionnera pas.

51voto

Theo Points 2839

C'est quelque chose que j'ai utilisé avec succès pour convertir Context à Activity lors de l'utilisation de l'interface utilisateur dans des fragments ou des vues personnalisées. Il déballera le ContextWrapper de manière récursive ou retournera null s'il échoue.

public Activity getActivity(Context context)
{
    if (context == null)
    {
        return null;
    }
    else if (context instanceof ContextWrapper)
    {
        if (context instanceof Activity)
        {
            return (Activity) context;
        }
        else
        {
            return getActivity(((ContextWrapper) context).getBaseContext());
        }
    }

    return null;
}

33voto

Manitoba Points 2811
  1. Non
  2. Vous ne pouvez pas

Il existe deux contextes différents dans Android. Un pour votre application (appelons-le le BIG) et un pour chaque vue (appelons-le le contexte d'activité).

Un linearLayout est une vue, vous devez donc appeler le contexte d'activité. Pour l'appeler depuis une activité, il suffit d'appeler "this". C'est si facile, n'est-ce pas ?

Lorsque vous utilisez

this.getApplicationContext();

Vous appelez le contexte BIG, celui qui décrit votre application et qui ne peut pas gérer votre vue.

Un gros problème avec Android est qu'un contexte ne peut pas appeler votre activité. C'est un gros problème pour éviter cela lorsque quelqu'un commence le développement Android. Vous devez trouver une meilleure façon de coder votre classe (ou remplacer "Context context" par "Activity activity" et le convertir en "Context" si nécessaire).

Regards.


Juste pour mettre à jour ma réponse. Le moyen le plus simple d'obtenir votre Activity context consiste à définir une static dans votre Activity . Par exemple

public class DummyActivity extends Activity
{
    public static DummyActivity instance = null;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // Do some operations here
    }

    @Override
    public void onResume()
    {
        super.onResume();
        instance = this;
    }

    @Override
    public void onPause()
    {
        super.onPause();
        instance = null;
    }
}

Et ensuite, dans votre Task , Dialog , View vous pourriez utiliser ce genre de code pour obtenir votre Activity context :

if (DummyActivity.instance != null)
{
    // Do your operations with DummyActivity.instance
}

4 votes

+1 pour avoir expliqué une zone de confusion très courante entre les 2 différents types de contextes (tout comme il y a 2 différents types de contextes). R s). Les gens de Google doivent enrichir leur vocabulaire.

3 votes

BTW, @BorisStrandjev est correct : 2. Oui, vous pouvez . (on ne peut pas contester un code qui fonctionne)

2 votes

2. Pas vraiment. Si le contexte était celui de l'application, alors votre application se planterait.

9voto

Nepster Points 893

Si vous souhaitez appeler une méthode d'activité à partir d'une classe de mise en page personnalisée (classe non-Activity), vous devez créer un délégué en utilisant l'interface.

Ce n'est pas testé et je l'ai bien codé, mais je vous donne un moyen d'obtenir ce que vous voulez.

Tout d'abord, créez et interfacez

interface TaskCompleteListener<T> {
   public void onProfileClicked(T result);
}

public class ProfileView extends LinearLayout
{
    private TaskCompleteListener<String> callback;
    TextView profileTitleTextView;
    ImageView profileScreenImageButton;
    boolean isEmpty;
    ProfileData data;
    String name;

    public ProfileView(Context context, AttributeSet attrs, String name, final ProfileData profileData)
    {
        super(context, attrs);
        ......
        ......
    }
    public setCallBack( TaskCompleteListener<String> cb) 
    {
      this.callback = cb;
    }
    //Heres where things get complicated
    public void onClick(View v)
    {
        callback.onProfileClicked("Pass your result or any type");
    }
}

Et l'appliquer à toute activité.

et l'appeler comme

ProfileView pv = new ProfileView(actvitiyContext, null, temp, tempPd);
pv.setCallBack(new TaskCompleteListener
               {
                   public void onProfileClicked(String resultStringFromProfileView){}
               });

7voto

rjrjr Points 281

Et en Kotlin :

tailrec fun Context.activity(): Activity? = when {
  this is Activity -> this
  else -> (this as? ContextWrapper)?.baseContext?.activity()
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X