Предупреждение: Не размещайте классы контекста Android в статических полях; это утечка памяти (а также разрывы мгновенного запуска)



Android Studio:




не размещайте классы контекста Android в статических полях; это
утечка памяти (а также разрывы мгновенного запуска)




Итак, 2 вопроса:


#1 Как вы называете a startService из статического метода без статической переменной контекста?

#2 Как вы отправляете localBroadcast из статического метода (то же самое)?



примеры:



public static void log(int iLogLevel, String sRequest, String sData) {
if(iLogLevel > 0) {

Intent intent = new Intent(mContext, LogService.class);
intent.putExtra("UPDATE_MAIN_ACTIVITY_VIEW", "UPDATE_MAIN_ACTIVITY_VIEW");
mContext.startService(intent);
}
}


или



        Intent intent = new Intent(MAIN_ACTIVITY_RECEIVER_INTENT);
intent.putExtra(MAIN_ACTIVITY_REQUEST_FOR_UPDATE, sRequest));
intent.putExtra(MAIN_ACTIVITY_DATA_FOR_VIEW, sData);
intent.putExtra(MAIN_ACTIVITY_LOG_LEVEL, iLogLevel);
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);


что было бы правильно способ сделать это без использования mContext?



примечание: Я думаю, что мой главный вопрос может заключаться в том, как передать контекст классу, из которого живет вызывающий метод.

749   5  

5 ответов:

просто передайте его в качестве параметра в метод. Нет смысла создавать статический экземпляр Context исключительно с целью запуска Intent.

вот как должен выглядеть ваш метод:

public static void log(int iLogLevel, String sRequest, String sData, Context ctx) {
    if(iLogLevel > 0) {

        Intent intent = new Intent(ctx, LogService.class);
        intent1.putExtra("UPDATE_MAIN_ACTIVITY_VIEW", "UPDATE_MAIN_ACTIVITY_VIEW");
        ctx.startService(intent);
    }
}

обновление из комментариев к вопросу: Каскадируйте контекст из инициирующей активности (через параметры конструктора или параметры метода) прямо до точки, в которой он вам нужен.

просто убедитесь, что вы передаете контекст.getApplicationContext() или вызов getApplicationContext () в любом контексте, который передается через методы/конструктор в ваш синглтон, если вы решили сохранить его в любом поле члена.

пример доказательства идиота (даже если кто-то передаст в действие, он захватит контекст приложения и использует его для создания экземпляра синглтона):

public static synchronized RestClient getInstance(Context context) {
    if (mInstance == null) {
        mInstance = new RestClient(context.getApplicationContext());
    }
    return mInstance;
}

getApplicationContext () согласно документам: " возврат контекста единого, глобального Объект приложения текущего процесса."

это означает, что контекст, возвращаемый "getApplicationContext ()", будет жить через весь процесс, и поэтому не имеет значения, сохраняете ли вы статическую ссылку на него в любом месте, поскольку он всегда будет там во время выполнения вашего приложения (и переживет любые объекты/синглеты, созданные им).

сравнить, что в контексте внутри мнения/деятельность по проведению больших объемов данных, если вы утечка в контексте проводимых деятельность, система не сможет освободить тот ресурс, который явно не хорош.

ссылка на действие по его контексту должна жить в том же жизненном цикле, что и сама активность, иначе она будет держать контекст заложником, вызывая утечку памяти (что является причиной предупреждения lint).

EDIT: для парня, избивающего пример из документов выше, есть даже раздел комментариев в коде о том, что я только что написал о компании:

    // getApplicationContext() is key, it keeps you from leaking the
    // Activity or BroadcastReceiver if someone passes one in.

Это просто предупреждение. Не волнуйся. Если вы хотите использовать контекст приложения, вы можете сохранить его в классе "singleton", который используется для сохранения всего класса singleton в вашем проекте.

в вашем случае это не имеет смысла иметь его в качестве статического поля, но я не думаю, что это плохо во всех случаях. Если вы сейчас что вы делаете, вы можете иметь статическое поле, которое имеет контекст и обнулить его позже. Я создаю статический экземпляр для моего основного класса модели, который имеет контекст внутри, его контекст приложения, а не контекст действия, а также у меня есть статическое поле экземпляра класса, содержащее действие, которое я обнуляю при уничтожении. Я не вижу, что у меня есть утечка памяти. Так что если какой-то умный парень думает, что я неправильно не стесняйтесь комментировать...

также мгновенный запуск работает нормально...

как правило, избегайте определения полей контекста как статических. Само предупреждение объясняет, почему: это утечка памяти. Нарушение мгновенного запуска мая не самая большая проблема на планете, хотя.

Теперь есть два сценария, где вы получите это предупреждение. Например (самый очевидный):

public static Context ctx;

и тогда есть немного более сложный, где контекст завернут в класс:

public class Example{
    public Context ctx;
    //Constructor omitted for brievety 
}

и этот класс определяется как статика где-то:

public static Example example;

и вы получите предупреждение.

само решение довольно простое: не помещайте поля контекста в статические экземпляры, будь то класс обертывания или объявление его статическим напрямую.

и решение для предупреждения просто: не размещайте поле статически. В вашем случае передайте контекст как экземпляр метода. Для классов, где выполняется несколько контекстных вызовов, используйте конструктор для передачи контекст (или деятельность) в классе.

обратите внимание, что это предупреждение, а не ошибку. Должны ли вы по какой-либо причине нужно статический контекст, вы можете это сделать. Хотя вы создаете утечку памяти, когда вы это делаете.

Comments

    Ничего не найдено.