在(自定义)view/dialog 内部访问 Activity 的最佳方法?

Best approach to access an Activity on the inside of a (custom) view/dialog?

我的应用程序中只有一个 activity。在我将我的视图和对话框静态存储在 activity 之前,这样我就可以从任何地方访问它们。但我知道这是不好的做法,因为它会导致内存泄漏。

所以我使它们成为非静态的,但现在我需要在视图层次结构的深处引用我的 activity,以访问存储在 activity 中的视图和对话框。

示例:

我的 MainActivity 有一个名为 a 的对话框和一个名为 b 的自定义视图。 b的onClick方法如何显示对话框a

或在代码中:

public class MainActivity extends Activity {
    private CustomDialog a;
    private CustomView b;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        a = new CustomDialog(this);
        b = new CustomView(this);
    }
}


public class CustomView extends Button implements OnClickListener {
    public CustomView(Context context) {
        super(context);
        setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        //wants to show dialog a
        MainActivity.a.show(); //Not possible -> a is not static
        mainActivity.a.show(); //<-- needs a reference of the activity
                               //    but where from?
    }
}

MainActivity mainActivity = (MainActivity) getContext(); 将不起作用,因为 getContext() 并不总是 activity 上下文。

更新:

我在下面发布了一个答案! 由于某些原因 Whosebug 只让我在两天内接受我自己的答案

我不知道您的视图层次结构到底是什么样的。

我将您的问题描述为: Activity A 有一个 recyclerview R,现在 R 中的每个 viewholder H 都应该能够触发 A 中的一些方法。

在这种情况下,将您的 activity 的引用传递给您的 recyclerview 适配器,然后适配器将其传递给 ViewHolder 是可行的。 然后在您的(查看者的)视图的 onClick 方法中使用它。 在这里,您可以使用“回调”模式。在 Whosebug 上有很多关于这个的帖子,例如here.

所以实施步骤是:

  1. 定义接口
  2. 让您的 activity 实现该接口
  3. 让您的适配器将接口作为构造函数参数并传递给您activity。 (在这个例子中:你必须用你的 viewHolder 重复这个步骤,从适配器传递接口)
  4. 在 onClick 方法中使用此接口方法 -> 然后这将触发您的活动方法

实现取决于实际层次结构。如果您的其他视图在片段中,那么您也可以使用(共享)ViewModel。 根据你的图片,我首先想到的是 callback-pattern 方法。

您可以在 MainActivity 中覆盖 onClick; class 定义本身可能不需要这样做。

public class MainActivity extends Activity {
    private CustomDialog a;
    private CustomView b;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        a = new CustomDialog(this);
        b = new CustomView(this);
        
        b.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                a.show();
            }
        });

    }
}

这是 android 中非常常见的模式,我不知道您的视图层次结构是什么样的,但在大多数情况下它应该有效。 我无法理解为什么 class 扩展 Button 需要实现 View.OnClickListener。在活动中创建侦听器或让 MainActivity 实施 OnClickListener.

更有意义

几分钟后这里就有一个答案被证明是正确的。 我不知道作者为什么删除它,但它有一个 link 到 答案:

private static Activity unwrap(Context context) {
    while (!(context instanceof Activity) && context instanceof ContextWrapper) {
        context = ((ContextWrapper) context).getBaseContext();
    }
    return (Activity) context;
}

因此,每次您需要 activity 时,您只需调用 Activity activity = unwrap(getContext());

我不知道它是否真的打算这样做,或者它是否是一种解决方法,但它确实起作用了(至少在我的情况下)。