Android 의 Context 추상 류 에 대한 자세 한 설명
(1)응용 프로그램 환경의 정보,즉 문맥 을 묘사 합 니 다.
(2)이 종 류 는 추상(abstract class)류 로 Android 는 이 추상 류 의 구체 적 인 실현 류 를 제공 합 니 다(다음 에 우 리 는 ContextIml 류 라 고 말 할 것 입 니 다).
(3)이 를 통 해 우 리 는 응용 프로그램의 자원 과 종 류 를 얻 을 수 있 고 응용 단계 의 조작 도 포함한다.예 를 들 어 Activity 를 시작 하고 방송 을 보 내 며 Intent 정 보 를 받 아들 이 는 등 이다.
따라서 우 리 는 이 Context 대상 을 이용 하여 응용 단계 작업(application-level operations)을 구축 할 수 있 습 니 다.
1.Context 관련 유형의 계승 관계
관련 클래스 소개:
Context 클래스 경로:/frameworks/base/core/java/android/content/context.java
설명:추상 류,통용 되 는 API 를 제공 합 니 다.소스 코드(부분)는 다음 과 같 습 니 다.
public abstract class Context {
...
public abstract Object getSystemService(String name); //
public abstract void startActivity(Intent intent); // Intent Activity
public abstract ComponentName startService(Intent service); // Service
// SharedPreferences
public abstract SharedPreferences getSharedPreferences(String name,int mode);
...
}
ContextIml.java 클래스 경로:/frameworks/base/core/java/android/app/contextImpl.java
설명:이 Context 류 의 실현 류 는 ContextIml 이 고 이 류 는 Context 류 의 기능 을 실현 했다.이 함수 의 대부분 기능 은 속성 mPackage Info 를 직접 호출 하여 완성 하 는 것 입 니 다.이 점 은 우리 가 나중에 말 할 것 입 니 다. 소스 코드(부분)는 다음 과 같 습 니 다.
/**
* Common implementation of Context API, which provides the base
* context object for Activity and other application components.
*/
class ContextImpl extends Context{
// Application mPackageInfo
/*package*/ ActivityThread.PackageInfo mPackageInfo;
@Override
public Object getSystemService(String name){
...
else if (ACTIVITY_SERVICE.equals(name)) {
return getActivityManager();
}
else if (INPUT_METHOD_SERVICE.equals(name)) {
return InputMethodManager.getInstance(this);
}
}
@Override
public void startActivity(Intent intent) {
...
// Activity
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null, null, intent, -1);
}
}
ContextWrapper 클래스 경로:\\frameworks\base\core\\java\\android\\content\ContextWrapper.java설명:그 명칭 과 같이 이 종 류 는 Context 류 에 대한 포장 일 뿐 이 며,이러한 구조 함 수 는 진정한 Context 인용,즉 ContextIml 대상 을 포함한다.소스 코드(부분)는 다음 과 같 습 니 다.
public class ContextWrapper extends Context {
Context mBase; // ContextIml , Application、Service、Activity
// Application、Service、Activity, mBase
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent); // mBase
}
}
ContextThemeWrapper 클래스 경로:/frameworks/base/core/java/android/view/contextThemeWrapper.java설명:이 클래스 내부 에는 테마(Theme)와 관련 된 인터페이스,즉 android:theme 속성 이 지정 한 것 이 포함 되 어 있 습 니 다.Activity 만 테마 가 필요 하고 Service 는 테마 가 필요 하지 않 기 때문에 Service 는 ContextWrapper 류 에 직접 계승 합 니 다.
소스 코드(부분)는 다음 과 같 습 니 다.
public class ContextThemeWrapper extends ContextWrapper {
// ContextIml , Application、Service、Activity
private Context mBase;
//mBase
public ContextThemeWrapper(Context base, int themeres) {
super(base);
mBase = base;
mThemeResource = themeres;
}
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
mBase = newBase;
}
}
Activity 류,Service 류,Application 류 는 본질 적 으로 Context 서브 클래스 이 므 로 더 많은 정 보 는 소스 코드 를 참고 하여 이해 할 수 있 습 니 다.2.Context 인 스 턴 스 를 언제 만 듭 니까?
Context 의 계승 관 계 를 숙지 한 후에 우 리 는 응용 프로그램 이 어떤 상황 에서 Context 대상 을 만들어 야 하 는 지 분석 할 것 이다.응용 프로그램 이 Context 인 스 턴 스 를 만 드 는 경 우 는 다음 과 같은 몇 가지 상황 이 있 습 니 다.
(1)애플 리 케 이 션 대상 을 만 들 때 전체 애플 리 케 이 션 은 하나의 애플 리 케 이 션 대상 이다.
(2)서비스 대상 을 만 들 때
(3)Activity 대상 을 만 들 때
따라서 응용 프로그램 앱 이 공유 하 는 Context 수량 공식 은 다음 과 같다.
총 Context 실례 개수=Service 개수+Activity 개수+1(Application 에 대응 하 는 Context 실례)
Context 를 만 들 시기:
1.애플 리 케 이 션 대상 을 만 들 시기
모든 프로그램 은 처음 시작 할 때 애플 리 케 이 션 대상 을 먼저 만 듭 니 다.응용 프로그램 이 Activity(startActivity)프로 세 스 를 시작 하 는 것 에 대해 잘 알 고 있다 면 응용 프로그램 을 만 들 때 handleBindApplication()방법 에서 이 함 수 는 Activity Thread.자바 류 에 있 습 니 다.다음 과 같 습 니 다.
// Application ContextIml
private final void handleBindApplication(AppBindData data){
...
/// Application
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
...
}
public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {
...
try {
java.lang.ClassLoader cl = getClassLoader();
ContextImpl appContext = new ContextImpl(); // ContextImpl
appContext.init(this, null, mActivityThread); // ContextIml
/// Application
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app); // Application ContextImpl
}
...
}
2.Activity 대상 을 만 들 시기 startActivity()나 startActivity ForResult()를 통 해 Activity 를 시작 할 것 을 요청 할 때 시스템 에서 새로운 Activity 대상 이 필요 할 때 handle LaunchActivity()방법 을 되 돌려 줍 니 다.이 방법 은 performLaunchActivity()방법 을 호출 하여 Activity 인 스 턴 스 를 만 들 고 onCreate(),onStart()방법 등 을 되 돌려 줍 니 다.함 수 는 모두 Activity Thread.자바 류 에 있 습 니 다.다음 과 같 습 니 다.
// Activity ContextIml
private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {
...
Activity a = performLaunchActivity(r, customIntent); // Activity
}
private final Activity performLaunchActivity(ActivityRecord r, Intent customIntent) {
...
Activity activity = null;
try {
// Activity
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
}
if (activity != null) {
ContextImpl appContext = new ContextImpl(); // Activity
appContext.init(r.packageInfo, r.token, this); // ContextIml
appContext.setOuterContext(activity); // Activity ContextImpl
...
}
...
}
3.Service 대상 을 만 들 시기startService 나 bindService 를 통 해 시스템 이 Service 인 스 턴 스 를 새로 만들어 야 한 다 는 것 을 감지 하면 handle CreateService()방법 을 되 돌려 관련 데이터 작업 을 완성 합 니 다.handle CreateService()함 수 는 Activity Thread.자바 류 에 있 습 니 다.다음 과 같 습 니 다.
// Service ContextIml
private final void handleCreateService(CreateServiceData data){
...
// Service
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
}
...
ContextImpl context = new ContextImpl(); // ContextImpl
context.init(packageInfo, null, this); // ContextIml
// Application
Application app = packageInfo.makeApplication(false, mInstrumentation);
// Service ContextImpl
context.setOuterContext(service);
...
}
또한 강조해 야 할 것 은 ContextImp 에 대한 분석 을 통 해 알 수 있 듯 이 그 방법의 대부분 조작 은 그 속성 mPackageInfo(이 속성 류)를 직접 호출 하 는 것 이다.
Package Info)와 관련 된 방법 으로 왔 습 니 다.이 는 ContextImp 는 경량급 류 이 고 Package Info 가 진정한 중량급 류 라 는 것 을 의미한다.하나의 앱 에 있 는...
모든 ContextIml 인 스 턴 스 는 같은 package Info 대상 에 대응 합 니 다.
3.Context 를 이용 하여 Shared Preferences 류 가 져 오기
Context 를 이용 하여 Shared Preferences 류 를 얻 는 방법 을 분석 합 니 다.Shared Preferences 류 는 모두 가 사용 한 적 이 있 을 것 입 니 다.일반 획득 자 입 니 다.
법 은 getShared Preferences()방법 을 호출 하여 관련 정보 에 따라 Shared Preferences 대상 을 얻 는 것 이다.구체 적 인 절 차 는 다음 과 같다.
1.호출 getShared Preferences()에서 해당 하 는 파일 을 가 져 옵 니 다.이 함 수 는 다음 과 같은 기능 을 수행 합 니 다.
//Context , xml
private static final HashMap<File, SharedPreferencesImpl> sSharedPrefs =
new HashMap<File, SharedPreferencesImpl>();
@Override
public SharedPreferences getSharedPreferences(String name, int mode){
// SharedPreferencesImpl , HashMap
SharedPreferencesImpl sp;
File f = getSharedPrefsFile(name); // ,
synchronized (sSharedPrefs) { // , SharedPreferences
sp = sSharedPrefs.get(f);
if (sp != null && !sp.hasFileChanged()) {
//Log.i(TAG, "Returning existing prefs " + name + ": " + sp);
return sp;
}
}
// xml , map
Map map = null;
if (f.exists() && f.canRead()) {
try {
str = new FileInputStream(f);
map = XmlUtils.readMapXml(str);
str.close();
}
...
}
synchronized (sSharedPrefs) {
if (sp != null) {
//Log.i(TAG, "Updating existing prefs " + name + " " + sp + ": " + map);
sp.replace(map); //
} else {
sp = sSharedPrefs.get(f);
if (sp == null) {
// SharedPreferencesImpl ,
sp = new SharedPreferencesImpl(f, mode, map);
sSharedPrefs.put(f, sp);
}
}
return sp;
}
}
2.Shared Preferences 는 인터페이스 에 불과 합 니 다.xml 파일 을 조작 하 는 방법 을 정 의 했 습 니 다.이 종 류 는 Shared Preferences Impl 입 니 다.이 종 류 는 ContextIml 의 내부 클래스 입 니 다.이 종 류 는 다음 과 같 습 니 다.
//soga, Context ContextIml
//SharedPreferences , SharedPreferencesImpl
private static final class SharedPreferencesImpl implements SharedPreferences{
private Map mMap; // ,
// key value
public String getString(String key, String defValue) {
synchronized (this) {
String v = (String)mMap.get(key);
return v != null ? v : defValue;
}
}
...
// SharedPreferencesImpl Edito ,
public final class EditorImpl implements Editor {
private final Map<String, Object> mModified = Maps.newHashMap(); //
}
}
기본적으로 Shared Preferences 대상 을 가 져 오 는 것 이 이렇게 왔 습 니 다.
4.임의의 위치 에서 응용 프로그램 Context 가 져 오기
1.임의의 위치 에서 프로그램 Context 가 져 오기
Android 프로그램 에서 자원 에 접근 할 때 Context 를 제공 해 야 합 니 다.일반적으로 각종 component(Activity,Provider 등)에서 만 api 를 편리 하 게 사용 하여 Context 를 가 져 올 수 있 습 니 다.프로 그래 밍 을 좋아 하 는 사람들 은 도구 류 를 작성 하면 코드 재 활용 을 효과적으로 실현 할 수 있다 는 것 을 잘 알 고 있 습 니 다.안 드 로 이 드 에서 일부 도구 류 의 작성 은 당 혹 스 럽 습 니 다.예 를 들 어 도구 류 에서 Shared Preferences 를 얻 으 려 면 Context 의 지원 이 필요 합 니 다.
Context 로 인 한 번 거 로 움 을 해결 하기 위해 서 는 애플 리 케 이 션 류 를 사용자 정의 하여 이 기능 을 실현 할 수 있 습 니 다.
import android.app.Application;
public class ContextUtil extends Application {
private static ContextUtil instance;
public static ContextUtil getInstance() {
return instance;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
instance = this;
}
}
그리고 manifest 에2.context 주의사항:
안 드 로 이 드 에서 context 는 많은 작업 을 할 수 있 지만 가장 중요 한 기능 은 자원 을 불 러 오고 방문 하 는 것 입 니 다.안 드 로 이 드 에는 두 가지 context 가 있 는데 하 나 는 application context 이 고 하 나 는 activity context 입 니 다.보통 우 리 는 각 종류 와 방법 간 에 activity context 를 전달 합 니 다.
예 를 들 어 activity 의 onCreate:
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this); // context view control
label.setText("Leaks are bad");
setContentView(label);
}
activity context 를 view 에 전달 하 는 것 은 view 가 activity 를 가리 키 는 인용 을 가지 고 activity 가 차지 하 는 자원:view hierachy,resource 등 을 참조 하 는 것 을 의미한다.이렇게 하면 context 에서 메모리 가 유출 되면 많은 메모리 가 유출 된다.
여기 서 유출 된 것 은 gc 가 activity 의 메모 리 를 회수 할 방법 이 없다 는 뜻 이다.
Leaking an entire activity 는 쉬 운 일이 다.
화면 이 회전 할 때 시스템 은 현재 activity 를 없 애고 상태 정 보 를 저장 하 며 새 것 을 만 듭 니 다.
예 를 들 어 우 리 는 응용 프로그램 을 썼 습 니 다.그것 은 큰 그림 을 불 러 와 야 합 니 다.우 리 는 화면 을 회전 할 때마다 이 그림 을 없 애고 다시 불 러 오 는 것 을 원 하지 않 습 니 다.이 요 구 를 실현 하 는 간단 한 아 이 디 어 는 정적 인 Drawable 을 정의 하 는 것 입 니 다.그러면 Activity 클래스 가 만들어 서 메모리 에 저장 합 니 다.
유사 성 구현:
public class myactivity extends Activity {
private static Drawable sBackground;
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);//drawable attached to a view
setContentView(label);
}
}
이 절 차 는 보기 에는 매우 간단 하지만 문제 가 매우 크다.화면 이 회전 할 때 leak(즉 gc 는 activity 를 없 앨 수 없습니다)가 있 습 니 다.우리 가 방금 말 했 듯 이 화면 이 회전 할 때 시스템 은 현재 activity 를 소각 합 니 다.그러나 drawable 이 view 와 연 결 된 후에 drawable 은 view 의 reference,즉 sBackground 는 label 의 인용 을 저장 하고 label 은 activity 의 인용 을 저장 합 니 다.drawable 이 소각 할 수 없 는 이상 인용 과 간접 인용 은 모두 소각 할 수 없습니다.그러면 시스템 은 현재 activity 를 소각 할 방법 이 없어 서 메모리 가 유출 되 었 습 니 다.gc 는 이러한 유형의 메모리 유출 에 대해 무력 합 니 다.
이러한 메모리 유출 을 피 하 는 방법 은 activity 의 모든 대상 의 수명 주기 가 activity 보다 길 어 지지 않도록 하 는 것 입 니 다.대상 이 activity 에 대한 인용 으로 인해 activity 가 정상적으로 소각 되 지 않도록 하 는 것 입 니 다.애플 리 케 이 션 context 를 사용 할 수 있 습 니 다.applicationcontext 는 application 의 일생 을 수반 하여 activity 의 수명 주기 와 무관 합 니 다.applicationcontext 는 Context.getapplicationContext 또는 Activity.getApplication 방법 으로 얻 을 수 있 습 니 다.
context 와 관련 된 메모리 유출 을 피하 고 다음 과 같은 몇 가 지 를 기억 하 십시오.
(1)생명주기 가 긴 대상 이 activity context 를 인용 하지 않도록 합 니 다.즉,activity 를 인용 하 는 대상 은 activity 자체 의 생명주기 와 같 아야 합 니 다.
(2)수명 주기 가 긴 대상 에 대해 서 는 애플 리 케 이 션 context 를 사용 할 수 있 습 니 다.
(3)비 정적 인 내부 클래스 를 피하 고 정적 클래스 를 사용 하여 생명주기 문 제 를 피하 고 내부 클래스 가 외부 대상 에 대한 인용 으로 인 한 생명주기 변화 에 주의해 야 한다.
3.다른 가방 의 Context 가 져 오기
Android 에는 Context 라 는 개념 이 있 으 니 모두 가 알 고 있 을 것 이다.Context 는 많은 일 을 할 수 있 습 니 다.activity 를 열 고 방송 을 보 내 며 이 가방 의 폴 더 와 데이터 베 이 스 를 열 고 classLoader 를 얻 으 며 자원 을 얻 을 수 있 습 니 다.만약 우리 가 가방 의 Context 대상 을 얻 었 다 면,우 리 는 기본적으로 이 가방 이 자신 이 할 수 있 는 대부분의 일 을 할 수 있 을 것 이다.
Context 는 createPackage Context 방법 이 있 습 니 다.다른 가방 의 컨 텍스트 를 만 들 수 있 습 니 다.이 인 스 턴 스 는 그 자체 의 Context 인 스 턴 스 와 다 르 지만 기능 은 같 습 니 다.
이 방법 은 두 개의 인자 가 있다.
(1)packageName 패키지 이름,Context 패키지 이름 을 가 져 옵 니 다.
(2)flags 표지 위치,CONTEXTINCLUDE_CODE 와 CONTEXTIGNORE_SECURITY 두 가지 옵션.CONTEXT_INCLUDE_코드 를 포함 한 이 가방 안의 코드 를 실행 할 수 있다 는 뜻 이다.CONTEXT_IGNORE_SECURITY 는 보안 경 고 를 무시 하고 이 표 지 를 추가 하지 않 으 면 일부 기능 이 사용 되 지 않 아 안전 경고 가 발생 한 다 는 뜻 이다.
다음은 작은 예 를 들 어 다른 가방 안의 어떤 종류의 방법 을 실행 합 니 다.또 다른 가방 의 가방 이름 은 chroya.demo,클래스 이름 Main,방법 이름 print 입 니 다.코드 는 다음 과 같 습 니 다.
package chroya.demo;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
class Main extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void print(String msg) {
Log.d("Main", "msg:"+ msg);
}
}
package chroya.demo;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
class Main extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void print(String msg) {
Log.d("Main", "msg:"+ msg);
}
}
이 가방 의 Main print 방법 을 호출 하 는 코드 블록 은 다음 과 같 습 니 다.
Context c = createPackageContext("chroya.demo", Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
//
Class clazz = c.getClassLoader().loadClass("chroya.demo.Main");
//
Object owner = clazz.newInstance();
// print ,
Object obj = clazz.getMethod("print", String.class).invoke(owner,"Hello");
Context c = createPackageContext("chroya.demo", Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
//
Class clazz = c.getClassLoader().loadClass("chroya.demo.Main");
//
Object owner = clazz.newInstance();
// print ,
Object obj = clazz.getMethod("print", String.class).invoke(owner, "Hello");
ok,이렇게 해서 우 리 는 chroya.demo 가방 의 Main 류 print 방법 을 호출 하여 결 과 를 실행 하고 Hello 를 인쇄 했 습 니 다.이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.