这个问题难倒了我。

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

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

我是否将正确的上下文传递到Profileview? 我如何从上下文获得包含活动?


当前回答

当在片段或自定义视图的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;
}

其他回答

对于kotlin用户-

val activity = context as Activity

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

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

首先创建和接口

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

Kotlin机器人速记扩展版本的西奥的解决方案

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

以上用法在此解释

永远不要对视图使用getApplicationContext()。

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

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

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