Как получить активность хостинга из вида?

187

У меня есть Activityс 3 EditTextс и пользовательский вид, который действует специализированная клавиатура для добавления информации в EditTextс.

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

Есть ли способ сослаться на родительское действие и сфокусироваться на текущем, EditTextне передавая действие в представление?

Mandroid
источник
7
Правильный ответ - гомино.
djunod

Ответы:

305

Я только что вытащил этот исходный код из MediaRouter в официальную библиотеку поддержки, и пока он работает нормально:

private Activity getActivity() {
    Context context = getContext();
    while (context instanceof ContextWrapper) {
        if (context instanceof Activity) {
            return (Activity)context;
        }
        context = ((ContextWrapper)context).getBaseContext();
    }
    return null;
}
Gomino
источник
13
пока? почему пока?
Якоб Эрикссон
9
Это просто способ всплыть через весь базовый контекст, пока не будет найдено действие, или выйти из цикла, когда найден корневой контекст. Потому что корневой контекст будет иметь нулевой baseContext, ведущий к концу цикла.
Гомино
1
Очень хорошо ! Я заменил ((Activity) getContext ()) на getActivity (), и он отлично работает .... Спасибо
Кристиан
как уже было сказано, getContext () не всегда может представлять объект Activity, если ваш View не вызывается из контекста Activity. Например, это не работает для пользовательских представлений.
Tohid
@AbhinavSaxena Не могли бы вы привести пример, когда этот код не будет работать? Даже если сам метод возвращает ноль, он никогда не должен туда попасть.
Tiago
168

следующие методы могут помочь вам

  1. Activity host = (Activity) view.getContext(); и
  2. view.isFocused()
Dira
источник
35
Только не забывайте, что getContext()не всегда может возвращать объект Activity, если ваш View не вызывается из контекста Activity. Обязательно планируйте это заранее и предоставьте соответствующий запасной вариант.
Джунейт
1
@WordPressDeveloper - Как можно создать представление без активности? Вы имеете ввиду удаленный просмотр? Существуют ли другие случаи представлений, созданных вне Действия?
Алик Эльзин-килака
1
@kilaka Виджеты, фрагменты, RemoteViews, LayoutInflaters - все это случаи, когда вы можете создать представление, не привязанное к Activity.
Джунейт
4
@WordPressDeveloper - Когда вы создаете представление во фрагменте, его контекст остается активным. Фрагменты могут находиться только в Деятельности.
АликЭльзин-килака
24
Это довольно опасный актерский состав. Существует большая вероятность (если вы используете appcompat), что контекст, который вы получили, обернут, приведя что-то вроде a ContextThemeWrapperк Activityброску a ClassCastException. Вам понадобится способ развернуть базовый контекст (который должен быть Activity), который сам по себе опасен, поскольку существует нативная версия и версия v7 ContextThemeWrapper.
Алекс
12

Мне нравится это решение написано на Kotlin

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

Использование в Viewклассе

context.activity()

Декомпилированный код:

public static final Activity activity(Context context) {
    while (!(context instanceof Activity)) {
        if (!(context instanceof ContextWrapper)) {
            context = null;
        }
        ContextWrapper contextWrapper = (ContextWrapper) context;
        if (contextWrapper == null) {
            return null;
        }
        context = contextWrapper.getBaseContext();
        if (context == null) {
            return null;
        }
    }
    return (Activity) context;
}
Влад
источник
1
спасибо, действительно ценю это за это хорошее сканирование на kotlin
mochadwi
8

Я взял Gomino «s ответ и изменить его , чтобы полностью соответствовать в myUtils.java , так что я могу использовать его везде , где и всякий раз , когда мне нужно. Надеюсь, кто-то найдет это полезным :)

abstract class myUtils {
    public static Activity getActivity(View view) {
        Context context = view.getContext();
        while (context instanceof ContextWrapper) {
            if (context instanceof Activity) {
                return (Activity)context;
            }
            context = ((ContextWrapper)context).getBaseContext();
        }
        return null;
    }
}
brownieGirl
источник
Это не эффективный ответ, так как есть шансы получить значение NULL, как возвращается из этой функции. Мой ответ применим повсеместно, хотя благодаря некоторой тяжелой работе и пониманию: stackoverflow.com/a/51077569/787399
Абхинав Саксена
-1

В Android 7+ представление больше не имеет доступа к вложенному действию, поэтому view.getContext()больше не может быть приведено к действию.

Вместо этого приведенный ниже код работает в Android 7+ и 6:

private static Activity getActivity(final View view) {
    return (Activity) view.findViewById(android.R.id.content).getContext();
}
Себас Л.Г.
источник
6
«В Android 7+ вид не имеет доступа к охватывающему деятельности больше, так view.getContext () не может быть приведен к деятельности» Любые ссылки?
Простой товарищ
@SimpleFellow, как упомянуто в других комментариях, getContextвероятно, вернет a, ContextThemeWrapperтак что представление больше не имеет прямого доступа к действию. Вместо этого вам придется рекурсивно искать в родительских контекстах, пока вы не найдете родительское действие или не воспользуетесь методом, который я предоставил в этом ответе.
Себас LG
-1

Свойство расширения Kotlin для View для извлечения родительской активности:

val View.activity: Activity?
get() {
    var ctx = context
    while (true) {
        if (!ContextWrapper::class.java.isInstance(ctx)) {
            return null
        }
        if (Activity::class.java.isInstance(ctx)) {
            return ctx as Activity
        }
        ctx = (ctx as ContextWrapper).baseContext
    }
}
Федир Цапана
источник
Вы могли бы заменить два ifс whenи isInstance()с !is ContextWrapperилиis Activity
Дэвид Мигель
Согласно @Gomino корневой контекст будет иметь нулевой baseContext. Таким образом, ваша реализация может вызвать исключение ClassCastException в этом случае
Дэвид Мигель
Это старое решение. Лучше использовать решение @Vlad
Федир Цапана,
-1

@Override public boolean shouldOverrideUrlLoading (представление WebView, запрос WebResourceRequest) {if (request.getUrl (). GetHost (). StartWith ("pay.google.com")) {Intent intent = new Intent (Intent.ACTION_VIEW, request.getUrl ()); view.getContext () startActivity (намерение). вернуть истину; } ... ...}

Tomcolins Cox Violet CHilton c
источник
1
Привет и добро пожаловать в Stack Overflow. пожалуйста, объясните свой ответ больше, чем просто пример кода; посмотрите на другие ответы, например.
Итамар Мушкин