【问题标题】:Context inside AsyncTaskAsyncTask 中的上下文
【发布时间】:2014-02-11 14:09:51
【问题描述】:

我目前正在尝试将我的应用授权代码放入外部类中,因此我不会在需要时重复自己并整理代码。

我遇到的问题是我似乎无法从 AsyncTask 内部访问我的 Session 变量。我很想自己尝试弄清楚以更好地了解情况,但另一个问题是LogCat 没有错误,所以我不知道出了什么问题!我的授权类如下:

public class AuthoriseMe extends AsyncTask<Object, Void, String> {

    public Context context;

    protected String doInBackground(Object... params) {

    Log.i(TAG, "I GOT HERE");
    SessionManager session = new SessionManager(context);
    Log.i(TAG, "I GOT PAST HERE");

        String authorized = "";
        HashMap<String, String> app = session.getAPPDetails();
        String appid = app.get(SessionManager.KEY_APPID);
        String secret = app.get(SessionManager.KEY_SECRET);
    }
}

我用来启动 AsyncTask 的代码如下,另一个类正在调用 authoriseMe();

public void authoriseMe() {
    AuthoriseMe authorise = new AuthoriseMe();
    authorise.execute();
}

authoriseMe() 正在被调用,因为我已经记录了该过程,但它看起来像“SessionManager session = new SessionManager(context);”这一行是问题发生的地方,好像我把那条线去掉,我的逻辑是“我过去了”。

我的 SessionManager 构造函数如下所示:

// Constructor
public SessionManager(Context context){
    this._context = context;
    pref = _context.getSharedPreferences(PREF_NAME, PRIVATE_MODE);
    editor = pref.edit();
}

据我所知,这似乎是 asyncTask 中的上下文问题。有没有办法解决?有没有人有这方面的经验?

【问题讨论】:

  • 你在哪里对你的授权说应该使用哪个上下文?看起来您只是在类中声明了上下文,但从未为其赋值?
  • asynctask 中上下文在哪里初始化?
  • 这是我的问题,外部异步任务中是否有上下文?通常我会在包含异步任务的类中分配它,但这与该流程是分开的
  • 你应该使用下面给出的答案,活动有上下文,所以你可以通过它。
  • 附带说明 - 如果您的上下文是活动上下文,请确保使用 Wea​​kReference

标签: android android-asynctask android-context


【解决方案1】:

我没有看到你初始化你的context 成员。只需添加适当的构造函数:

public AuthoriseMe(Context context) {
    this.context = context;
}

然后代替

AuthoriseMe authorise = new AuthoriseMe();

AuthoriseMe authorise = new AuthoriseMe(context);

你就完成了。或者,您可以通过调用getApplication()getApplicationContext()(请务必阅读this question)来获取上下文,这对于大多数情况来说应该足够了。

【讨论】:

  • 谢谢您,先生!仍在尝试了解上下文,尤其是在后台线程中。
  • 会导致内存泄漏
【解决方案2】:

正如其他人所说,问题只是您从未初始化或显式设置您的context 变量,因此它的值是它隐式初始化的值。 当你写:

public class AuthoriseMe extends AsyncTask<Object, Void, String> {
    public Context context;
    ...

这相当于:

public class AuthoriseMe extends AsyncTask<Object, Void, String> {
    public Context context = null;
    ...

(当你创建一个新的 AuthoriseMe 对象时,会在它的构造函数执行之前发生 null 影响) 所以你看到在你当前的代码中它会保持null,因此你的问题。

更重要的是,请记住

  1. Android Context 是高度有状态的并且有生命周期,所以
    • 您希望尽可能避免泄漏它们(内存方面)
    • 如果您尝试使用生命周期已经结束(即已被销毁)的Context,您很可能会遇到麻烦
  2. AsyncTask 生命周期独立独立于任何 Activity 或其他 Context 生命周期,即您的 AuthorizeMe 任务很可能正在运行并尝试执行操作,而 @987654331 @ 它持有的已经被破坏了(这又会导致问题......),所以
    • 您应该避免持有AsyncTask 中对Context 的引用

因此,在您的情况下,您可以做的只是在您的 SessionManager 中保留对 SharedPreferences 的引用,并且不保留任何 Context 引用作为成员变量(这将是我的偏好),或者您也可以确保您引用的 Context 是应用程序上下文(此应用程序的生命周期与应用程序本身相同,因此泄漏“不是问题”)。

这是第一个解决方案的样子:

public static class AuthoriseMe extends AsyncTask<Object, Void, String> {
    private final SessionManager mSessionManager;

    public AuthoriseMe(Context context) {
        this.mSessionManager = new SessionManager(context);
    }

    protected String doInBackground(Object... params) {
        String authorized = "";
        HashMap<String, String> app = mSessionManager.getAPPDetails();
        ...
    }
}

public static class SessionManager {
    private final SharedPreferences mSharedPreferences;

    public SessionManager(Context context){
        mSharedPreferences = context.getSharedPreferences(PREF_NAME, PRIVATE_MODE);
        editor = mSharedPreferences.edit();  // I wouldn't do that here ; edit when you will really need to and commit afterwards
    }
}

SharedPreferences 也与应用程序本身具有相同的范围,因此可以保留引用。 请注意,我将AsyncTask 类设为静态,这样可以防止在不知不觉中泄漏对其嵌套对象的引用(很可能是Activity)。

PS:Java 通常不使用下划线前缀命名约定;)

【讨论】:

    猜你喜欢
    • 2010-12-27
    • 2011-11-29
    • 1970-01-01
    • 2013-05-31
    • 2011-01-08
    • 2011-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多