-
[Android] Context, ContextWrapper, ContextImpl ์ดํดAndroid 2021. 11. 21. 22:48๋ฐ์ํ
Context
์๋๋ก์ด๋ ๊ฐ๋ฐ์ ํด๋ณธ ์ฌ๋์ด๋ผ๋ฉด Context์ ๋ํด์๋ ์ผํ ์๊ณ ์์ ๊ฒ์ ๋๋ค. ์ ๋ ๋จ์ํ ์์ด๋ก ํด์ํ์ฌ ๋ฌธ๋งฅ, ๋จ๋ฝ์ ์๋ฏธ๋ก์ ์ปดํฌ๋ํธ๋ค์ ๋ํ ๊ธฐ๋ณธ ์ ๋ณด๋ค์ ๋ด๊ณ ์๋ ํด๋์ค๋ผ๊ณ ์๊ฐํ์ต๋๋ค. ๊ฐ๋ฐํ๋ ์ค์๋ Context๊ฐ ๋ง์ด ํ์ํ๊ฒ ๋๋๋ฐ this(Activity), getContext, getApplicationContext์ ๋ํ ์ดํด์์ด ๋์ ํด๋ณด๊ณ ๋๋ ๊ฒ์ ์ค์ ํ ๋๋ ๋ง์์ต๋๋ค. ๊ทธ๋ฌ๋ค๊ฐ ๋ฉด์ ์์ ๋๋ต์ ๋ชปํ ๋๊ฐ ๋ง์๊ณ ๋๋ฒ๊น ํ๋๋ฐ ์ค๋์๊ฐ์ด ๊ฑธ๋ฆฐ๋ค๋ ๊ฒ์ ๋๋ผ๊ณ ์ฒ์ฒํ ์ ๋๋ก ๋ฐฐ์๋ณด๊ณ ์ ๊ณต๋ถ๋ฅผ ํ๊ณ ๊ธ์ ์ฐ๊ฒ ๋์์ต๋๋ค.
๊ณต์๋ฌธ์์์ ์ค๋ช ํ๊ธฐ๋ก Context๋ ์๋๋ก์ด๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ๊ฒฝ ์ ๋ณด์ ๋ํ ์ธํฐํ์ด์ค๋ก, ์์์ ์ถ์๋ฉ์๋๋ก ์ด๋ค์ง ์ถ์ ํด๋์ค์ ๋๋ค. ์ด ๋์ ํ๊ฒฝ ์ ๋ณด๋ ์ ํ๋ฆฌ์ผ์ด์ ํจํค์ง ์ด๋ฆ, ๋ฆฌ์์ค ์ ๋ณด ๋ฑ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์คํ๋๊ณ ์๋ ํ๊ฒฝ ์์๋ค์ ๋ํ๋ ๋๋ค. ์ค์ ๋ก Context ๋ค์ ๊ตฌํํ๋ ํด๋์ค๋ ContextImpl ํด๋์ค๋ก ์ฃผ๋ก ์๋๋ก์ด๋ ์์คํ ์์ ์ ๊ณต๋ฐ์ต๋๋ค.
https://developer.android.com/reference/android/content/Context
Context๋ฅผ ํตํด์ ์กํฐ๋นํฐ๋ฅผ ์์ํ๋ค๊ฑฐ๋, ๋ธ๋ก๋์บ์คํธ๋ฅผ ๋ฐ์์ํฌ ์๋ ์๊ณ , ์๋น์ค๋ฅผ ์คํ์ํฌ ์๋ ์์ต๋๋ค. ๋ํ, ๋ฆฌ์์ค๋ค์ ์ ๊ทผํ ๋๋ Context๊ฐ ํ์ํ๊ฒ ๋ฉ๋๋ค.
ContextImpl
์ถ์ํด๋์ค์ธ Context๋ฅผ ์ค์ ๊ตฌํํ ํด๋์ค๋ก ์ฑ์์ ์ง์ ์ฌ์ฉํ ์ ์๋ ํด๋์ค๋ ์๋์ง๋ง, ์์ค์ฝ๋๋ ๊ณต๊ฐ๋์ด ์์ด์ ํ์ธํ ์ ์์ต๋๋ค. ContextImpl์ ์๋๋ก์ด๋ ์์คํ ์์ ์ ๊ณต๋ฐ์ ์ ์์ต๋๋ค.
http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/java/android/app/ContextImpl.java#120
ContextWrapper
ContextWrapper๋ Context๋ฅผ ์ง์ ์์ํ ํด๋์ค๋ก ์ด๋ฆ์ฒ๋ผ Context๋ฅผ ๋ํํ์ฌ Context์ ๊ด๋ จ๋ ํธ์ถ์ ๋ชจ๋ ๋ด๋นํ์ฌ ์ฒ๋ฆฌํ๊ฒ ๋ฉ๋๋ค.
public class ContextWrapper extends Context { @UnsupportedAppUsage Context mBase; public ContextWrapper(Context base) { mBase = base; } /** * Set the base context for this ContextWrapper. All calls will then be * delegated to the base context. Throws * IllegalStateException if a base context has already been set. * * @param base The new base context for this wrapper. */ protected void attachBaseContext(Context base) { if (mBase != null) { throw new IllegalStateException("Base context already set"); } mBase = base; } /** * @return the base context as set by the constructor or setBaseContext */ public Context getBaseContext() { return mBase; } @Override public AssetManager getAssets() { return mBase.getAssets(); } @Override public Resources getResources() { return mBase.getResources(); } ... }
์ ์ฝ๋๋ ContextWrapper์ ํด๋์ค๋ก ContextWrapper(Context base) ์์ฑ์๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์์ฑ์์ attachBaseContext ๋ฉ์๋์์๋ Context๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ๊ณ ์๋๋ฐ ์ด ๋ ๋์ ๋๋ ๊ฒ์ Context์ ๊ตฌํ์ฒด์ธ ContextImpl ์ธ์คํด์ค๊ฐ ์ ๋ฌ๋ฉ๋๋ค. ์ฝ๋๋ฅผ ์์ธํ ์ดํด๋ณด๋ฉด ContextWrapper๋ ์ค์ ๋ก ContextImpl์ ๋ฉ์๋๋ฅผ ๋์ ํธ์ถํด์ฃผ๋ ์ญํ ์ ํ๊ฒ ๋ฉ๋๋ค.
Context, ContextWrapper, ContextImpl, ์ปดํฌ๋ํธ๋ค์ ํด๋์ค ๋ค์ด์ด๊ทธ๋จ์ ๋๋ค. Context๋ฅผ ์ง์ ์์ํ ํด๋์ค๋ ContextWrapper์ด๊ณ , ContextWrapper๋ฅผ ์์ํ ๊ฒ์ Activity, Service, Application ์ ๋๋ค. Activity, Service, Application์ ๊ธฐ๋ณธ ์์ฑ์๋ฅผ ์ฌ์ฉํ์ง ์๊ณ attachBaseContext๋ฅผ ์ฌ์ฉํ์ฌ Context๋ฅผ ์ค์ ํฉ๋๋ค. ํด๋น ์ปดํฌ๋ํธ๋ค์ attach ๋ฉ์๋๋ฅผ ์คํํ๋ฉด ๋ด๋ถ์์ attachBaseContext๋ฅผ ์คํํ๊ฒ ๋ฉ๋๋ค.
@UnsupportedAppUsage final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) { attachBaseContext(context); ... }
์ ์ฝ๋๋ Activity์ attach ๋ฉ์๋๋ก ContextImpl์ด ์๋๋ก์ด๋ ์์คํ ์ ์ํด ์ ๊ณต๋ฐ๊ณ attach ๋ฉ์๋๋ฅผ ํตํด์ ContextWrapper์ ContextImpl ์ธ์คํด์ค๊ฐ ๋์ ๋๋ค๊ณ ๋ณผ ์ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ContextWrapper๋ ContextImpl์ Proxy ํํ๋ก ๊ตฌํํ์ฌ ๋ณธ์ฐ์ ContextImpl ํด๋์ค์ ๋ณ๊ฒฝ์์ด ์ํ๋ ๊ธฐ๋ฅ, ๋์๋ค์ ์ฌ์ ์๋ ํ ์ ์์ต๋๋ค.
ContextImpl ์ดํด
ContextWrapper์ ์ ๋ฌ๋ ContextImpl์ ๋ํด์ ์์ธํ ์์๋ณด์๋ฉด Activity, Service, Application ์ปดํฌ๋ํธ์์๋ ๊ฐ๊ฐ ์๋๋ก์ด๋ ์์คํ ์์ ์ ๊ณต๋ฐ์ ContextImpl์ ๋ํํ๊ณ ์๊ณ , getBaseContext๋ ์ ๊ณต๋ฐ์ ContextImpl ์ธ์คํด์ค๋ฅผ ๋ฐํํฉ๋๋ค. ๋ํ getApplicationContext๋ฅผ ํธ์ถํ๋ฉด ContextImpl์ getApplicationContext๊ฐ ํธ์ถ๋๊ณ ContextImpl์ ์๋ ActivityThread์ getApplication ํจ์๋ฅผ ํธ์ถํ๊ฒ ๋ฉ๋๋ค.
class ContextImpl extends Context { private final static String TAG = "ContextImpl"; private final static boolean DEBUG = false; /** * Map from package name, to preference name, to cached preferences. */ private static ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>> sSharedPrefs; final ActivityThread mMainThread; private ContextImpl(ContextImpl container, ActivityThread mainThread, LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted, Display display, Configuration overrideConfiguration, int createDisplayWithId) { mOuterContext = this; mMainThread = mainThread; ... } @Override public Context getApplicationContext() { return (mPackageInfo != null) ? mPackageInfo.getApplication() : mMainThread.getApplication(); } }
์ ๋ฆฌํ์๋ฉด Activity, Service, Application ๋ชจ๋ ๋ด๋ถ์ ์ผ๋ก ActivityThread์์ ์ปดํฌ๋ํธ๊ฐ ์์๋๊ณ , attach ๋ฉ์๋์์ ActivityThread์ ContextImpl ์ธ์คํด์ค๋ฅผ ๋ฐ๊ฒ ๋ฉ๋๋ค. attach ๋ฉ์๋์์ ๋ ๋ค์ attachBaseContext ๋ฉ์๋๊ฐ ํธ์ถ๋ฉ๋๋ค. ๋ฐ๋ผ์ getBaseContext๋ฅผ ํธ์ถํ๋ฉด ContextImpl ์ธ์คํด์ค๊ฐ ๋ฐํ๋๊ณ getApplicationContext๋ฅผ ํธ์ถํ๋ฉด AcitivtyThread์ Application ์ธ์คํด์ค๊ฐ ๋ฐํ๋ฉ๋๋ค. Application ์ปดํฌ๋ํธ ๋ํ ContextWrapper๋ฅผ ์์ํ๊ณ ์๊ธฐ ๋๋ฌธ์ ์๋๋ก์ด๋ ์์คํ ์์ ์ ๊ณต๋ฐ์ ContextImpl์ ๋ฐํํ๊ฒ ๋๊ณ Application ์ธ์คํด์ค๋ ์ฑ์์ 1๊ฐ ๋ฐ์ ์๊ธฐ ๋๋ฌธ์ ํญ์ ๋์ผํ ์ธ์คํด์ค์ ๋๋ค.
ContextImpl ๋ฉ์๋
Context๋ฅผ ์ด์ฉํ์ฌ ์กํฐ๋นํฐ ์์ํ๊ฑฐ๋, ๋ธ๋ก๋์บ์คํธ ๋ฐ์์ํค๊ฑฐ๋, ์๋น์ค ์คํํ๋๋ฐ ์ด๋ ContextImpl์ ๋ฉ์๋๋ฅผ ์ด์ฉํฉ๋๋ค. ๊ธฐ๋ฅ๋ณ๋ก ํฌํผ(helper), ํผ๋ฏธ์ , ์์คํ ์๋น์ค ์ ๊ทผ ๊ด๋ จํ 3๊ฐ์ ๊ทธ๋ฃน์ผ๋ก ๋๋ ์ ์์ต๋๋ค.
- ์ฑ ํจํค์ง ์ ๋ณด๋ฅผ ์ ๊ณตํ๊ฑฐ๋, SharedPreference ์ค์ ํ์ผ, ๋ฐ์ดํฐ ๋ฒ ์ด์ค ๋ฑ์ ์ฌ์ฉํ๊ธฐ ์ํ ํฌํผ(helper) ๋ฉ์๋๊ฐ ์กด์ฌํฉ๋๋ค
- Acitivity, BroadcastReceiver, Service ๊ฐ์ ์ปดํฌ๋ํธ ์์ํ๋ ๋ฉ์๋์ Permission Check ๋ฉ์๋๋ค์ด ์กด์ฌํฉ๋๋ค.
- ActivityManagerService๋ฅผ ํฌํจํ ์์คํ ์๋น์ค์ ์ ๊ทผํ๊ธฐ ์ํด getSystemService ๋ฉ์๋๊ฐ ์กด์ฌํฉ๋๋ค. ContextImpl ํด๋์ค๊ฐ ๋ก๋ฉ๋ ๋, ์์คํ ์๋น์ค๋ฅผ ๋งคํํ๊ณ getSystemService๋ฅผ ์ฌ์ฉํ์ฌ ๋งคํ๋ ์๋น์ค๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์์คํ ์๋น์ค๊ฐ NOTIFICATION_SERVICE์ ๊ฐ์ด ์์๋ช ์ผ๋ก ๋งคํ๋์ด ์์ด Context๊ฐ ์ ๋ฌ๋๋ ํด๋์ค๋ ๋ฉ์๋๋ผ๋ฉด ์ด๋์๋ getSystemService๋ฅผ ์ฌ์ฉํ์ฌ ์์คํ ์๋น์ค๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
๋ค์ํ Context ํํ
- Activity ์ธ์คํด์ค ์์ (this)
- getBaseContext ๋ฅผ ํตํด ๊ฐ์ ธ์ค๋ ContextImpl ์ธ์คํด์ค
- getApplicationContext๋ฅผ ํตํด ๊ฐ์ ธ์ค๋ Application ์ธ์คํด์ค
3๊ฐ์ ์ธ์คํด์ค๋ ๋ชจ๋ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ์ ๋๋ก ์์ง ๋ชปํ๊ณ ์บ์คํ ์ ํ๊ฒ ๋๋ฉด ClassCastException์ด ๋ฐ์ํ๊ฒ ๋ฉ๋๋ค. Activity๋ Context์ ์์ ํด๋์ค์ด๊ณ ContextImpl๋ Context์ ์์ ํด๋์ค์ง๋ง, ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ์บ์คํ ์ ํจ๋ถ๋ฌ ํ๋ฉด ์๋ฉ๋๋ค.
Activity์ onCreate์์ setContetView๋ฅผ ํตํด ํ๋ฉด์ ๋ณด์ฌ์ง๋ View๋ฅผ ์ค์ ํ๊ฒ ๋ฉ๋๋ค.
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView textView = findViewById(R.id.textView); Log.d(TAG, "1st = "+(textView.getContext() == this)); Log.d(TAG, "2nd = "+(textView.getContext() == getBaseContext())); Log.d(TAG, "3rd = "+(textView.getContext() == getApplicationContext())); Log.d(TAG, "4th = "+(textView.getContext() == getApplication())); }
View ์์ฑ์์ Context ๊ฐ ํ์ํ๋ฐ ์ด Context๋ฅผ ์ด๋์ ์๋์ง ํ์คํ ์์์ผํฉ๋๋ค. ์ ์ฝ๋์์๋ ์ฒซ ๋ฒ์งธ ๊ฒฝ์ฐ๋ง true๊ฐ ๋ฐํํ๊ฒ ๋๋๋ฐ View์ ์ฐ๊ด์ฑ์ด ๊ฐ์ฅ ํฐ Activity๋ผ๊ณ ์ ์ถํ ์๋ ์์ต๋๋ค. ํ์ง๋ง ์ ํํ๊ฒ ์ดํด๋ฅผ ํ์๋ฉด, setContentView ๋ AppCompatActivity ํด๋์ค์ setContentView ๋ฅผ ํธ์ถํ๊ณ ๋ด๋ถ์์ AppCompatDelegate์ setContentView๋ฅผ ํธ์ถํฉ๋๋ค. AppCompatDelegate ์ด๊ธฐํ์์ Activity ์์ ์ด ํ๋ผ๋ฏธํฐ๋ก ๋ค์ด๊ฐ๊ธฐ ๋๋ฌธ์ 1๋ฒ์์ true๊ฐ ๋๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
@NonNull public AppCompatDelegate getDelegate() { if (mDelegate == null) { mDelegate = AppCompatDelegate.create(this, this); } return mDelegate; }
Context ์ฌ์ฉ ์ฃผ์์
Context ์ฌ์ฉ ์์๋ ๋ผ์ดํ ์ฌ์ดํด์ ์ ์๊ฐํด์ ์ฌ์ฉํ์ฌ์ผ ํฉ๋๋ค. ApplicationContext๋ ์ฑ๊ธํค์ผ๋ก ์ฑ์์ 1๊ฐ์ ์ธ์คํด์ค๋ฐ์ ์๊ธฐ ๋๋ฌธ์ ์ฑ๊ธํค ์ค๋ธ์ ํธ๋ ์ ์ญ์ผ๋ก ์ฌ์ฉํ๋ ํด๋์ค ๊ฐ์ ๊ฒฝ์ฐ์ ์ฌ์ฉํ๋ฉด ์ข์ต๋๋ค. ํ์ง๋ง Activity์ Context๋ฅผ ์ฑ๊ธํค ์ค๋ธ์ ํธ์ ์ฐธ๊ณ ํ๊ฒ ๋๋ฉด Activity๊ฐ onDestroy๊น์ง ๊ฐ์ง๋ง Context๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ null์ด ๋์ง ์์ GC์ ๋์์ด ๋์ง ์์ต๋๋ค. ์ฆ, Activity ๊ฐ ํ๊ดด๋์์ง๋ง ์ฑ๊ธํค์์ ์ฐธ์กฐ๋๊ณ ์์ด ๋ฉ๋ชจ๋ฆฌ๋ฆญ์ด ๋ฐ์ํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ Activity, Service, Application์ ๋ผ์ดํ ์ฌ์ดํด์ ์ ํ์ ํ๊ณ Context๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
์ฐธ๊ณ
- ์๋ค๋ก์ด๋ ํ๋ก๊ทธ๋๋ฐ Next Step p71 ~ p76
๋ฐ์ํ'Android' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Android] Room ์ดํด ๋ฐ ํ์ฉ (0) 2022.01.01 [Android] SQLite, SQLiteOpenHelper, Local DB ์ดํด (0) 2021.11.30 [Android] Preference, Shared Preference? (0) 2021.11.19 [Android] Thread, Handler, Looper, Message Queue ๋ค๋ฃจ๊ธฐ (0) 2021.11.11 [Android] Activity๋? Activity LifeCycle ์๋ฒฝ ์ดํด (0) 2021.11.03