Android Studio:
Не размещайте классы контекста Android в статических полях; это утечка памяти (а также нарушает работу Instant Run)
Итак, 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
?
ПРИМЕЧАНИЕ. Я думаю, что мой главный вопрос может заключаться в том, как передать контекст классу, из которого живет вызывающий метод.
android
android-studio-2.2
Джон Смит
источник
источник
Ответы:
Просто передайте его как параметр вашему методу. Нет смысла создавать статический экземпляр
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); } }
Обновление на основе комментариев к вопросу: каскадирование контекста из инициирующего действия (с помощью параметров конструктора или параметров метода) до момента, когда он вам нужен.
источник
MyClass
добавьте к нему общедоступный конструктор, точно так же, как методpublic MyClass(Context ctx) { // put this ctx somewhere to use later }
(это ваш конструктор). Теперь создайте новый экземплярMyClass
использования этого конструктора, напримерMyClass mc = new MyClass(ctx);
Просто убедитесь, что вы передаете context.getApplicationContext () или вызываете getApplicationContext () в любом контексте, который передается через методы / конструктор вашему синглтону, если вы решите сохранить его в любом поле члена.
Пример доказательства идиота (даже если кто-то передаст действие, он захватит контекст приложения и использует его для создания экземпляра синглтона):
public static synchronized RestClient getInstance(Context context) { if (mInstance == null) { mInstance = new RestClient(context.getApplicationContext()); } return mInstance; }
getApplicationContext () в соответствии с документами: «Вернуть контекст единственного глобального объекта Application текущего процесса».
Это означает, что контекст, возвращаемый "getApplicationContext ()", будет существовать на протяжении всего процесса, и поэтому не имеет значения, храните ли вы статическую ссылку на него где угодно, поскольку он всегда будет там во время выполнения вашего приложения (и переживет любые объекты / одиночные экземпляры, созданные им).
Сравните это с контекстом внутри представлений / действий, содержащих большие объемы данных, если вы просочите контекст, удерживаемый действием, система не сможет освободить этот ресурс, что явно нехорошо.
Ссылка на действие по его контексту должна существовать в том же жизненном цикле, что и само действие, в противном случае оно будет удерживать контекст в заложниках, вызывая утечку памяти (что является причиной предупреждения о линтах).
РЕДАКТИРОВАТЬ: для парня, избивающего пример из приведенных выше документов, в коде даже есть раздел комментариев о том, о чем я только что написал:
// getApplicationContext() is key, it keeps you from leaking the // Activity or BroadcastReceiver if someone passes one in.
источник
Это просто предупреждение. Не волнуйся. Если вы хотите использовать контекст приложения, вы можете сохранить его в «одноэлементном» классе, который используется для сохранения всего одноэлементного класса в вашем проекте.
источник
В вашем случае нет смысла использовать его как статическое поле, но я не думаю, что это плохо во всех случаях. Если вы сейчас, что вы делаете, вы можете иметь статическое поле с контекстом и обнулить его позже. Я создаю статический экземпляр для своего основного класса модели, который имеет контекст внутри, его контекст приложения, а не контекст активности, а также у меня есть поле статического экземпляра класса, содержащего Activity, которое я обнуляю при уничтожении. Я не вижу, что у меня утечка памяти. Так что, если какой-то умный парень думает, что я неправ, не стесняйтесь комментировать ...
Также здесь отлично работает Instant Run ...
источник
Используйте
WeakReference
для хранения контекста в классах Singleton, и предупреждение исчезнетprivate WeakReference<Context> context; //Private contructor private WidgetManager(Context context) { this.context = new WeakReference<>(context); } //Singleton public static WidgetManager getInstance(Context context) { if (null == widgetManager) { widgetManager = new WidgetManager(context); } return widgetManager; }
Теперь вы можете получить доступ к контексту, например
if (context.get() instanceof MainActivity) { ((MainActivity) context.get()).startActivityForResult(pickIntent, CODE_REQUEST_PICK_APPWIDGET); }
источник
Как правило, избегайте определения полей контекста как статические. Само предупреждение объясняет, почему: это утечка памяти. Однако прерывание мгновенного бега может быть не самой большой проблемой на планете.
Теперь есть два сценария, при которых вы получите это предупреждение. Например (самый очевидный):
public static Context ctx;
И есть еще более сложный вопрос, когда контекст заключен в класс:
public class Example{ public Context ctx; //Constructor omitted for brievety }
И этот класс где-то определяется как статический:
public static Example example;
И вы получите предупреждение.
Само решение довольно простое: не помещайте поля контекста в статические экземпляры , будь то экземпляры класса-оболочки или напрямую объявляйте его статическим.
И решение предупреждения простое: не размещайте поле статически. В вашем случае передайте контекст как экземпляр методу. Для классов, в которых выполняется несколько вызовов Context, используйте конструктор для передачи контекста (или Activity, если на то пошло) классу.
Обратите внимание, что это предупреждение, а не ошибка. Если вам по какой-либо причине нужен статический контекст, вы можете это сделать. Хотя при этом вы создаете утечку памяти.
источник
Если вы убедитесь, что это Application Context. Это действительно важно. Добавь это
@SuppressLint("StaticFieldLeak")
источник