在Android中从上下文获取活动


182

这个让我难过。

我需要从自定义布局类中调用一个活动方法。问题是我不知道如何从布局中访问活动。

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. 我是否将正确的上下文传递到Profileview?
  2. 如何从上下文中获取包含活动?

Answers:


471

从中Activity,只需将this用作Context您的布局:

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

之后,您将Context在布局中拥有一个,但您将知道它实际上是您的布局,Activity可以对其进行强制转换,以便拥有所需的内容:

Activity activity = (Activity) context;

53
您不能保证所使用的上下文是活动上下文或应用程序上下文。尝试将应用程序上下文传递给DialogView,观察它崩溃,您将看到不同之处。
Sky Kelsey

6
鲍里斯(Boris),问题问是否有办法从上下文中获取活动。这是不可能的。当然可以投射,但这是不得已的方法。如果要将上下文视为活动,则不要向下转换为活动。它使代码更简单,并且在以后另一个人维​​护您的代码时更不容易出现错误。
Sky Kelsey

6
请注意,“ getApplicationContext()”而不是“ this”将不起作用。
dwbrito

1
@BorisStrandjev我不太了解您的评论。无论如何,我说过在尝试您的示例之后,我使用了getApplicationContext()而不是'this',并且该应用程序尝试强制转换App本身,因此产生强制转换错误,而不是活动。正如您回答的那样,切换到“ this”后,它起作用了。
dwbrito

1
您的链接上获得最高评价的答案均建议您质疑该问题是否有臭味。这个问题肯定很臭。OP首先声明:“我需要从自定义布局类中调用活动方法。” 适当使用接口是完全可以实现的。然后他说:“与此有关的问题是我不知道如何从布局内部访问活动。” 这是对误会的重要暗示。人们在编程中总是试图做错事,我们不应该对此视而不见。
2015年

39

这是什么,我已经成功地转换ContextActivity在片段或自定义视图的用户界面中进行操作时。它将递归解压缩ContextWrapper,如果失败则返回null。

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

这是正确的答案。其他的则不考虑ContentWrapper层次结构。
Snicolas

这是真正的答案:)
lygstate

1
@lygstate:您在应用中使用的目标API级别是什么?有什么错误?这仅在UI(活动,片段等)中有效,而在Services中不起作用。
Theo18年

31
  1. 没有
  2. 你不能

Android中有两种不同的上下文。一个用于您的应用程序(我们称其为BIG之一),另一个用于每个视图(我们将其称为活动上下文)。

linearLayout是一个视图,因此您必须调用活动上下文。要从活动中调用它,只需调用“ this”。是那么容易吗?

使用时

this.getApplicationContext();

您调用了BIG上下文,它描述了您的应用程序并且无法管理您的视图。

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

然后,在您的TaskDialogView,您可以使用这种代码获取Activity context

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

4
+1用于解释2种不同类型的上下文之间非常常见的混淆区域(就像存在2个不同的Rs一样)。Google员工需要丰富他们的词汇量。
an00b 2012年

3
顺便说一句,@ BorisStrandjev是正确的:2.是的,您可以。(无法与工作代码进行争论)
2012年

2
2.并非如此。如果上下文是Application上下文,则您的应用程序将崩溃。
StackOverflowed

静态实例?@Nepster对此imo拥有最好的解决方案
山姆,

14
创建对活动的静态引用是创建内存泄漏的最佳方法。
BladeCoder 2015年

8

如果要从自定义布局类(非活动类)中调用活动方法,则应使用interface创建委托。

它未经测试,我编码正确。但我正在传达一种实现您想要的方法。

首先创建和接口

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

1
这是正确答案,应标记为正确答案。我知道标记为正确答案的答案实际上可以回答OP的问题,但它不应该这样回答问题。事实是,像这样在视图中传递Activity并不是一种好习惯。除了通过,孩子在任何情况下都不应了解父母Context。正如Nepster所言,最佳实践是传递回调,因此,无论何时发生父级感兴趣的事情,都会使用相关数据触发回调。
达尔文

6

上下文可以是应用程序,服务,活动等。

通常,活动中视图的上下文是活动本身,因此您可能会认为可以将此上下文强制转换为活动,但实际上并不能总是这样做,因为在这种情况下上下文也可以是ContextThemeWrapper。

ContextThemeWrapper在AppCompat和Android的最新版本中大量使用(由于布局中的android:theme属性),因此我个人从不执行此强制转换。

如此简短的答案是:您无法可靠地从视图的上下文中检索活动。通过调用将Activity作为参数的方法传递给视图。


3

永远不要将getApplicationContext()与视图一起使用。

它应该始终是活动的上下文,因为视图已附加到活动。另外,您可能设置了自定义主题,并且在使用应用程序的上下文时,所有主题都将丢失。在此处阅读有关上下文的不同版本的更多信息。


3

在科特林:

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

0

Activity是Context的一种专业,因此,如果您有Context,那么您已经知道要使用的活动,并且可以简单地将a转换为c;其中a是活动,c是上下文。

Activity a = (Activity) c;

7
这很危险,因为如单独的注释中所述,上下文可能并不总是活动。

4
仅在(context instanceofActivity){// typecast}中进行类型转换
阿米特·亚达夫

0

我使用了转换活动

Activity activity = (Activity) context;

2
有不同类型的上下文。活动和应用程序可以具有上下文。仅当上下文是活动时,这才起作用。
cylov

0

这种方法应该是有帮助的。

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;

    }

希望对您有所帮助。


检查您传入的上下文是否不为null。这很可能是问题所在。
塔斯林·奥塞尼

0

如何进行实时数据回调,

class ProfileView{
    private val _profileViewClicked = MutableLiveData<ProfileView>()
    val profileViewClicked: LiveData<ProfileView> = _profileViewClicked
}

class ProfileActivity{

  override fun onCreateView(...){

    profileViewClicked.observe(viewLifecycleOwner, Observer { 
       activityMethod()
    })
  }

}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.