在android中从上下文获取活动

这个问题难倒了我。

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

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与它一起传入。两个问题:

  1. 我是否将正确的上下文传递到Profileview?
  2. 我如何从上下文获得包含活动?
401824 次浏览

从你的Activity中,只传入this作为布局的Context:

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

之后,你会在布局中有一个Context,但你会知道它实际上是你的Activity,你可以转换它,这样你就有了你需要的东西:

Activity activity = (Activity) context;
  1. 没有
  2. 你不能

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

linearLayout是一个视图,所以你必须调用activity context。要从活动中调用它,只需调用“this”。很简单,不是吗?

当你使用

this.getApplicationContext();

调用BIG上下文,它描述应用程序,不能管理视图。

Android的一个大问题是context不能调用你的activity。当有人开始Android开发时,要避免这种情况是很重要的。您必须找到更好的方法来编写类(或将“Context Context”替换为“Activity Activity”,并在需要时将其转换为“Context”)。

的问候。


更新一下我的答案。获得Activity context最简单的方法是在Activity中定义一个static实例。例如

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
}

Activity是Context的专门化,因此,如果你有一个Context,你已经知道你打算使用哪个Activity,并且可以简单地将< em > < / em >转换为c < em > < / em >;其中< em > < / em >是一个活动,c < em > < / em >是一个上下文。

Activity a = (Activity) c;

如果您想从自定义布局类(非活动类)中调用活动方法。您应该使用接口创建委托。

它是未经测试的,我编码它的权利。但我在传达一种实现你想要的方式。

首先创建和接口

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

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

通常情况下,Activity中视图的上下文是Activity本身,所以你可能认为你可以将这个context强制转换为Activity,但实际上你不能总是这样做,因为context在这里也可以是ContextThemeWrapper。

ContextThemeWrapper在AppCompat和Android的最新版本中被大量使用(感谢布局中的Android:theme属性),所以我个人永远不会执行这种强制转换。

所以简单的回答是:你不能可靠地从视图中的上下文中检索一个活动。通过调用以Activity为参数的方法将Activity传递给视图。

我使用convert Activity

Activity activity = (Activity) context;

永远不要在视图中使用getApplicationContext()

它应该始终是activity的上下文,因为视图是附加到activity的。此外,您可能有一个自定义主题集,当使用应用程序的上下文时,所有的主题都将丢失。阅读更多关于context 在这里的不同版本。

当在片段或自定义视图的UI中操作时,我已经成功地使用它将Context转换为Activity。它将递归地解包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;
}

这个方法应该是有用的..!

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;


}

我希望这能有所帮助。编码快乐!

在Kotlin中:

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

实时数据回调怎么样,

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


class ProfileActivity{


override fun onCreateView(...){


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


}


创建扩展函数。然后用context。getactivity()调用这个扩展函数。

fun Context.getActivity(): AppCompatActivity? {
var currentContext = this
while (currentContext is ContextWrapper) {
if (currentContext is AppCompatActivity) {
return currentContext
}
currentContext = currentContext.baseContext
}
return null
}

对于kotlin用户-

val activity = context as Activity

Kotlin android速记扩展版Theo的解决方案

private fun Context?.getParentActivity() : AppCompatActivity? = when {
this is ContextWrapper -> if (this is AppCompatActivity) this else this.baseContext.getParentActivity()
else -> null
}

上面的用法解释了在这里