Получение активности из контекста в Android - PullRequest
162 голосов
/ 27 марта 2012

Это меня озадачило.

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

ProfileView

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

ProfileActivity

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

Как вы можетесм. выше, я создаю экземпляр profileView программно и передаю им ActivityContext.2 вопроса:

  1. Передаю ли я правильный контекст в представление профиля?
  2. Как получить содержащую активность из контекста?

Ответы [ 10 ]

444 голосов
/ 27 марта 2012

Из вашего Activity просто введите this в качестве Context для вашего макета:

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

После этого у вас будет Context в макете, но вы будете знать егона самом деле ваш Activity, и вы можете разыграть его так, чтобы у вас было то, что вам нужно:

Activity activity = (Activity) context;
29 голосов
/ 27 марта 2012
  1. Нет
  2. Вы не можете

В Android существует два разных контекста.Один для вашего приложения (назовем его БОЛЬШИМ) и один для каждого представления (назовем его контекстом активности).

linearLayout - это представление, поэтому вам нужно вызвать контекст действия.Чтобы вызвать это из действия, просто назовите это.Так просто, не правда ли?

Когда вы используете

this.getApplicationContext();

Вы вызываете БОЛЬШОЙ контекст, который описывает ваше приложение и не может управлять вашим представлением.

AБольшая проблема с Android в том, что контекст не может вызвать вашу активность.Это большая проблема, чтобы избежать этого, когда кто-то начинает разработку Android.Вы должны найти лучший способ кодировать свой класс (или заменить «Контекст контекста» на «Активность действия» и при необходимости преобразовать его в «Контекст»).

С уважением.


Просто чтобы обновить мой ответ.Самый простой способ получить ваш Activity context - это определить экземпляр static в вашем Activity.Например,

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

А затем в ваших Task, Dialog, View вы можете использовать такой код для получения Activity context:

if (DummyActivity.instance != null)
{
    // Do your operations with DummyActivity.instance
}
26 голосов
/ 13 сентября 2017

Это то, что я успешно использовал для преобразования Context в Activity при работе в пользовательском интерфейсе в фрагментах или пользовательских представлениях.Он будет распаковывать ContextWrapper рекурсивно или вернет ноль в случае сбоя.

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;
}
8 голосов
/ 21 мая 2015

Если вы хотите вызывать метод действия из пользовательского класса макета (не класса деятельности). Вы должны создать делегата с использованием интерфейса.

Это не проверено, и я правильно его кодировал. но я передаю способ достичь того, что вы хотите.

Прежде всего создать и интерфейс

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

И внедрить это в любое действие.

и назовите это как

ProfileView pv = new ProfileView(actvitiyContext, null, temp, tempPd);
pv.setCallBack(new TaskCompleteListener
               {
                   public void onProfileClicked(String resultStringFromProfileView){}
               });
6 голосов
/ 05 июня 2015

Контекст может быть приложением, службой, действием и т. Д.

Обычно контекст представлений в действии - это само действие, поэтому вы можете подумать, что можете просто привести этот контекст к действию, но на самом делеВы не всегда можете сделать это, потому что в данном случае контекст также может быть ContextThemeWrapper.

ContextThemeWrapper широко используется в последних версиях AppCompat и Android (благодаря атрибуту android: theme в макетах), поэтомуЛично я бы никогда не выполнил это приведение.

Итак, короткий ответ таков: вы не можете надежно извлечь действие из контекста в представлении.Передайте Activity в представление, вызвав для него метод, который принимает Activity в качестве параметра.

2 голосов
/ 14 февраля 2017

Никогда не используйте getApplicationContext () с представлениями.

Это всегда должен быть контекст деятельности, так как представление привязано к деятельности. Кроме того, у вас может быть установлен пользовательский набор тем, и при использовании контекста приложения все темы будут потеряны. Подробнее о различных версиях контекстов здесь .

1 голос
/ 13 октября 2016

Я использовал конвертировать Активность

Activity activity = (Activity) context;
0 голосов
/ 29 июня 2019

А в Котлине:

tailrec fun Context.activity(): Activity? = when {
  this is Activity -> this
  else -> (this as? ContextWrapper)?.baseContext?.activity()
}
0 голосов
/ 04 января 2018

Этот метод должен быть полезным ..!

public Activity getActivityByContext(Context context){

if(context == null){
    return null;
    }

else if((context instanceof ContextWrapper) && (context instanceof Activity)){
        return (Activity) context;
    }

else if(context instanceof ContextWrapper){
        return getActivity(((ContextWrapper) context).getBaseContext());
    }

return null;

    }

Надеюсь, это поможет .. Веселого кодирования!

0 голосов
/ 13 февраля 2014

действие - это специализация контекста, поэтому, если у вас есть контекст, вы уже знаете, какое действие вы намереваетесь использовать, и можете просто привести a в с ;где a - это действие, а c - это контекст.

Activity a = (Activity) c;
...