【问题标题】:Is it safe to use this way to pass context to non-context classes使用这种方式将上下文传递给非上下文类是否安全
【发布时间】:2015-08-12 10:45:50
【问题描述】:

我已经阅读了几篇关于将上下文传递给适配器或其他内容的文章,并且我制作了某种上下文容器来获取应用程序上下文:

import android.content.Context;

public class ContextHolder {
    private static ContextHolder ourInstance = new ContextHolder();
    private Context context;

    public static ContextHolder getInstance() {
        return ourInstance;
    }

    private ContextHolder() {
        context = null;
    }

    public void setContext(Context context){
        this.context = context;
    }

    public Context getApplicationContext(){
        return context;
    }
}

然后在 MainActivity 我创建 ContextHolder 对象并像这样设置上下文:

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ContextHolder contextHolder = ContextHolder.getInstance();
        contextHolder.setContext(this.getApplicationContext());
    }

在其他一些类中,我需要使用 contex:

ContextHolder contextHolder = ContextHolder.getInstance();
Resources resources = contextHolder.getApplicationContext().getResources();

问题是,我做对了吗? 它会导致内存泄漏或其他讨厌的东西吗?

【问题讨论】:

  • 这会泄露上下文。不过,您可以在 ContextHolder 中使用 Wea​​kReference。
  • 应用上下文不是贯穿整个应用生命周期吗?
  • 哦,是的。我的错。第二眼看到你使用了ApplicationContext。没关系我的评论。

标签: java android android-context


【解决方案1】:

在 MainActivity 我正在创建 ContextHolder

但是为了什么? Activity 已经是 Context 的子类:

java.lang.Object
  ↳ android.content.Context
    ↳ android.content.ContextWrapper
      ↳ android.view.ContextThemeWrapper
        ↳ android.app.Activity

所以你可以使用this(或MainActivity.this)。更不用说 contextHolder 变量,您将持有者对象放在所示代码中是本地范围的,并且仅在 onCreate() 中可见。

它会导致内存泄漏或其他讨厌的东西吗?

我建议使用 LeakCanary 来捕获代码中的所有内存泄漏。见:https://github.com/square/leakcanary

在其他一些类中,我需要使用 contex:

ContextHolder contextHolder = ContextHolder.getInstance();
Resources resources = contextHolder.getApplicationContext().getResources();

这都是不必要的和过度设计的。如果您只需要获取应用程序上下文,子类Application 类:

class MyApplication extends Application {
    protected static Context mContext;

    @Override
    public void onCreate() {
       super.onCreate();

       mContext = this;
    }

    public static Context getAppContext() {
       return mContext;
    }
}

在 Manifest 中将其设置为您的应用应用程序类:

<application
    android:name=".MyApplication"
    ...

然后,当您需要上下文时,您无法通过其他方式获得,只需调用:

MyApplication.getAppContext();

【讨论】:

    【解决方案2】:

    我认为您保存对应用程序上下文的引用的方法很好。正如docs 所说:

    通常不需要子类化应用程序。在大多数情况下,静态单例可以以更加模块化的方式提供相同的功能。

    因此,只是为了获取对应用程序上下文的引用,您不应继承 Application 类。

    在您的情况下,您应该在第一个活动的 onCreate 方法中初始化您的单例,以便您应该将 this.getApplicationContext() 传递给您的单例以保持。例如:

    public class ContextHolder {
        private static ContextHolder ourInstance;
        private Context context;
    
        public static ContextHolder getInstance() {
            return ourInstance;
        }
    
        public static void init(Context context){
            ourInstance = new ContextHolder(context);
        }
    
        private ContextHolder(Context context) {
            this.context = context;
        }
    
        public Context getApplicationContext(){
            return context;
        }
    }
    

    在您的第一个 Activity 的 onCreate 中:

    ContextHolder.init(getApplicationContext());
    

    【讨论】:

    • 虽然仅为上下文持有者扩展 Application 对象可能看起来很奇怪,但您“通常不需要继承 Application”这不是真的。显然我所有的应用程序都不正常......无论如何,拥有 ContextHolder 模块化也没有直接好处(更不用说这种方法需要隐式初始化。基本上没有这个类。
    • @MarcinOrlowski 你是绝对正确的。然而,由 OP 选择最适合他的目的。在我看来,OP 的方法(即单例类)比你的更好,因为它更符合 separation of concerns 和职责分离原则。另外我认为这个类在运行时没有太多的重载。
    • 当然,我们可以忽略开销。我现在正在讨论实施。关键是在这种方法中,您必须隐式初始化单例。您将在哪里执行此操作 - 在 MainActivity onCreate 中?好的,但是如果您参加其他活动怎么办?你会重新初始化它吗?不,重复的代码,很容易假设它应该已经初始化。现在 - 如果您的应用程序被杀死然后用户稍后返回它,那么它将被重新创建怎么办。当被问及上下文时,持有者会返回什么? null,因为它根本不会被初始化-> NPE。您总是可以将应用程序扩展到那里的初始化持有者:)))
    • @MarcinOrlowski 我没有考虑到这一点(Android 杀死应用程序)。现在,我应该承认,你的方式比我的好。感谢 Marcin 的这一点。 +1
    猜你喜欢
    • 1970-01-01
    • 2018-07-10
    • 2019-09-10
    • 1970-01-01
    • 2020-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多