Передача `Context` везде кажется беспорядочной – создавать классы для обработки различных взаимодействий с контекстом?

Есть множество вопросов, которые касаются Context , какой контекст использовать, и как его хранить и т. Д. Но я чувствую себя грязным каждый раз, когда я передаю его объекту, или создаю статический или синглтон, который обеспечивает ему доступ. Я не уверен, какой запах я получаю, но он определенно пахнет.

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

Пример альтернативы (с отсутствием кода для удобочитаемости):

 // in activity.onCreate(): StateStorer ss = new StateStorer (getApplicationContext()); RememberMe obj = new RememberMe(ss); ss.restore(); // in activity.onDestroy() ss.save(); // the "proxy" class StateStorer { List<StateStorerListener> listeners; Context mContext; public StateStorer(Context context){ mContext = context; } public SharedPreferences getSharedPreferences(String tag){ return mContext.getSharedPreferences(tag, 0); } public save(){ // tell listeners to save } public restore(){ // tell listeners to restore } } // an example class that needs to save state class RememberMe { public String TAG = "RememberMe"; public StateStorer mSs; public RememberMe (StateStorer ss){ mSs = ss; ss.addListener(this) } // this class would implement the StateStorer's listener interface, // and when the StateStorer tells it to save or restore, it will use the // StateStorer's methods to access the SharedPreferences object public void onRestore(){ SharedPreferences sp = sSs.getSharedPreferences(TAG); // restore from prefs here } } 

Существуют ли какие-либо принципы ООП, против которых это идет? Или запахи, что он исправляет? Я просто не могу решить.

Всякий раз, когда вы передаете экземпляр Context в другой класс, подумайте,

« Возможно ли, что этот класс будет жить дольше, чем Context который я передаю ему? »

Если ответ отрицательный, не беспокойтесь. Если да, подумайте, почему .

Например, View s, когда он используется обычно, никогда не будет дольше, чем ваша Activity . Как только Activity получит сбор мусора, ваш View получит сбор мусора, поэтому вам не о чем беспокоиться.

Синглтоны, однако, живут дольше и будут вытеснять Context . То есть, когда Activity предполагается собирать мусор, это не будет, потому что синглтон все еще имеет ссылку на него.

На ум приходит пара решений:

  • Используйте getApplicationContext() для одиночных getApplicationContext() . Этот тип Context живет до тех пор, пока ваше приложение живет – таким образом, пока ваш синглтон живет.
  • Используйте WeakReference s. Это гарантирует, что вы не будете поддерживать активную ссылку на свой Context и избегайте утечки. Однако вам придется компенсировать возможную недействительность Context .

Очевидно, что вам необходимо понять основы сбора мусора. Вот статья об этом .


Что касается кода примера, который вы указали, я не вижу разницы в передаче этого экземпляра, кроме как передавать фактический Context . В обоих случаях вы ссылаетесь на Context . На самом деле, класс StateStorer кажется одиночным, и, как и вы, должен быть предоставлен ApplicationContext .

Вы также часто увидите, что синглеты, когда они предоставляются Context , вызывают getApplicationContext() чтобы избежать таких ошибок:

 public static MySingleton getInstance(final Context context) { if(sInstance == null) { sInstance = new MySingleton(context.getApplicationContext()); } return sInstance; } 

Похоже на аккуратный код. Но зачем проходить все эти сложные движения, чтобы передать контекст? Мне кажется, теперь вы переходите на другой класс (ваш класс RememberMe), и это так же плохо или хорошо, как передача контекста. Поэтому я не вижу в этом преимущества.