Context
정적 메서드 내 에서 현재 인스턴스 를 가져 오는 방법이 있습니까?
변경 될 때마다 '컨텍스트'인스턴스를 저장하는 것을 싫어하기 때문에 그런 식으로 찾고 있습니다.
Context
경우 코드를 디자인하는 더 좋은 방법이있을 수 있습니다.
Context
정적 메서드 내 에서 현재 인스턴스 를 가져 오는 방법이 있습니까?
변경 될 때마다 '컨텍스트'인스턴스를 저장하는 것을 싫어하기 때문에 그런 식으로 찾고 있습니다.
Context
경우 코드를 디자인하는 더 좋은 방법이있을 수 있습니다.
답변:
이 작업을 수행:
Android Manifest 파일에서 다음을 선언하십시오.
<application android:name="com.xyz.MyApplication">
</application>
그런 다음 수업을 작성하십시오.
public class MyApplication extends Application {
private static Context context;
public void onCreate() {
super.onCreate();
MyApplication.context = getApplicationContext();
}
public static Context getAppContext() {
return MyApplication.context;
}
}
이제 어디서나 MyApplication.getAppContext()
응용 프로그램 컨텍스트를 정적으로 가져옵니다.
static context
변수를 volatile
? 로 선언해야 합니까?
응용 프로그램 컨텍스트를 얻는 편리한 방법을 원하는 대부분의 응용 프로그램은 확장하는 자체 클래스를 만듭니다 android.app.Application
.
안내서
먼저 다음과 같이 프로젝트에서 클래스를 작성하여이를 수행 할 수 있습니다.
import android.app.Application;
import android.content.Context;
public class App extends Application {
private static Application sApplication;
public static Application getApplication() {
return sApplication;
}
public static Context getContext() {
return getApplication().getApplicationContext();
}
@Override
public void onCreate() {
super.onCreate();
sApplication = this;
}
}
그런 다음 AndroidManifest에서 AndroidManifest.xml의 태그에 클래스 이름을 지정해야합니다.
<application
...
android:name="com.example.App" >
...
</application>
그런 다음 다음을 사용하여 정적 메소드에서 애플리케이션 컨텍스트를 검색 할 수 있습니다.
public static void someMethod() {
Context context = App.getContext();
}
경고
위와 같은 것을 프로젝트에 추가하기 전에 문서의 내용을 고려해야합니다.
일반적으로 Application을 서브 클래 싱 할 필요가 없습니다. 대부분의 상황에서 정적 싱글 톤은 더 모듈 방식으로 동일한 기능을 제공 할 수 있습니다. 싱글 톤에 글로벌 컨텍스트가 필요한 경우 (예 : 브로드 캐스트 수신기 등록) 싱글 톤을 처음 생성 할 때 내부적으로 Context.getApplicationContext ()를 사용하는 컨텍스트를 검색하는 함수를 검색 할 수 있습니다.
반사
리플렉션을 사용하여 응용 프로그램 컨텍스트를 얻는 또 다른 방법이 있습니다. 리플렉션은 종종 안드로이드에서 내려다보고 있으며 개인적으로 이것이 프로덕션에서 사용해서는 안된다고 생각합니다.
애플리케이션 컨텍스트를 검색하려면 API 1부터 사용 가능한 숨겨진 클래스 ( ActivityThread ) 에서 메소드를 호출해야합니다 .
public static Application getApplicationUsingReflection() throws Exception {
return (Application) Class.forName("android.app.ActivityThread")
.getMethod("currentApplication").invoke(null, (Object[]) null);
}
정적 방식으로 응용 프로그램 컨텍스트를 얻는 방법을 제공하는 숨겨진 클래스 ( AppGlobals ) 가 하나 더 있습니다 . 컨텍스트를 사용 ActivityThread
하므로 다음 방법과 위에 게시 된 방법 사이에는 아무런 차이가 없습니다.
public static Application getApplicationUsingReflection() throws Exception {
return (Application) Class.forName("android.app.AppGlobals")
.getMethod("getInitialApplication").invoke(null, (Object[]) null);
}
행복한 코딩!
우리가 Application Context를 얻는 것에 대해 이야기하고 있다고 가정하면 @Rohit Ghatol이 Application을 확장하여 제안한대로 구현했습니다. 그런 다음, 그런 식으로 검색된 컨텍스트가 항상 널이 아님을 보증하지 않습니다. 필요할 때 일반적으로 시간을 지연시킬 수없는 도우미를 초기화하거나 리소스를 얻으려고하기 때문입니다. null을 처리하면 도움이되지 않습니다. 그래서 나는 문서에 명시된 것처럼 기본적으로 Android 아키텍처와 싸우고 있음을 이해했습니다.
참고 : 일반적으로 Application을 서브 클래스화할 필요는 없습니다. 대부분의 상황에서 정적 싱글 톤은보다 모듈 방식으로 동일한 기능을 제공 할 수 있습니다. 싱글 톤에 글로벌 컨텍스트가 필요한 경우 (예 : 브로드 캐스트 수신자 등록) 싱글 톤의 getInstance () 메소드를 호출 할 때 Context.getApplicationContext ()를 컨텍스트 인수로 포함하십시오.
응용 프로그램이 당신이 얻을 수있는 것으로 존재하는 유일한 이유는 1.0 이전 개발 과정에서 응용 프로그램 개발자 중 한 명이 더 "정상적으로 얻을 수있는 응용 프로그램 객체를 가질 필요가 있다는 것에 대해 계속 나를 괴롭 혔기 때문입니다. "그들에게 응용 프로그램 모델을 제공하고 결국 포기했습니다. 나는 그 제안을 영원히 후회할 것입니다. :)
그녀는 또한이 문제에 대한 해결책을 제안하고 있습니다.
원하는 것이 앱의 다른 부분에서 공유 할 수있는 전역 상태 인 경우 싱글 톤을 사용하십시오. [...] 그리고 이것은보다 자연스럽게 이러한 것들을 어떻게 관리해야하는지에 따라 온 디맨드 방식으로 초기화됩니다.
그래서 내가 한 것은 Application 확장을 없애고 컨텍스트를 싱글 톤 도우미의 getInstance ()에 직접 전달하면서 개인 생성자에서 응용 프로그램 컨텍스트에 대한 참조를 저장하는 것입니다.
private static MyHelper instance;
private final Context mContext;
private MyHelper(@NonNull Context context) {
mContext = context.getApplicationContext();
}
public static MyHelper getInstance(@NonNull Context context) {
synchronized(MyHelper.class) {
if (instance == null) {
instance = new MyHelper(context);
}
return instance;
}
}
그러면 호출자는 로컬 컨텍스트를 헬퍼에게 전달합니다.
Helper.getInstance(myCtx).doSomething();
따라서이 질문에 올바르게 대답하려면 응용 프로그램 컨텍스트에 정적으로 액세스하는 방법이 있지만 모두 권장하지 않아야하며 단일 컨텍스트의 getInstance ()에 로컬 컨텍스트를 전달하는 것이 좋습니다.
관심있는 사람은 fwd blog 에서 더 자세한 버전을 읽을 수 있습니다.
getInstance(ctx)
. 당신은 GC 루트이 instance
유형의 MyHelper
개인 필드가, mContext
유형의 Context
컨텍스트를 통해 수집 된 애플리케이션 컨텍스트가 전달 된 참조를 getInstance()
. instance
는 두 번째로 설정되거나 해제되지 않으므로 GC는에서 참조하는 앱 컨텍스트를 절대로 포착하지 않습니다 instance
. 활동을 유출하지 않으므로 저렴한 IMO입니다.
this
에 정적 참조를 게시하여이를 단순화 Application.onCreate()
하여 더 나은 답변을 얻을 수 있습니다.
아니, 나는 생각하지 않습니다. 불행히도 또는의 다른 하위 클래스 중 하나 getApplicationContext()
에서 전화 를 Activity
걸었습니다 Context
. 또한 이 질문은 다소 관련이 있습니다.
다음은 UI 스레드의 어느 곳에서나 응용 프로그램 (컨텍스트) 을 얻는 문서화되지 않은 방법 입니다. 숨겨진 정적 메소드에 의존합니다 . 최소한 Android 4.x에서 작동해야합니다.ActivityThread.currentApplication()
try {
final Class<?> activityThreadClass =
Class.forName("android.app.ActivityThread");
final Method method = activityThreadClass.getMethod("currentApplication");
return (Application) method.invoke(null, (Object[]) null);
} catch (final ClassNotFoundException e) {
// handle exception
} catch (final NoSuchMethodException e) {
// handle exception
} catch (final IllegalArgumentException e) {
// handle exception
} catch (final IllegalAccessException e) {
// handle exception
} catch (final InvocationTargetException e) {
// handle exception
}
UI 스레드 외부에서 메소드를 호출하거나 애플리케이션이 스레드에 바인드되지 않은 경우이 메소드가 널을 리턴 할 수 있습니다.
응용 프로그램 코드를 변경할 수 있으면 @RohitGhatol 솔루션 을 사용하는 것이 좋습니다 .
컨텍스트를 사용하는 대상에 따라 다릅니다. 그 방법에 대한 하나 이상의 단점을 생각할 수 있습니다.
AlertDialog
with 를 만들려고 AlertDialog.Builder
하면 Application
컨텍스트가 작동하지 않습니다. 나는 현재의 상황이 필요하다고 생각합니다 Activity
...
코 틀린 방법 :
명백한:
<application android:name="MyApplication">
</application>
MyApplication.kt
class MyApplication: Application() {
override fun onCreate() {
super.onCreate()
instance = this
}
companion object {
lateinit var instance: MyApplication
private set
}
}
그런 다음 다음을 통해 속성에 액세스 할 수 있습니다 MyApplication.instance
당신이 사용하는 열려있는 경우 RoboGuice을 , 당신은 당신이 원하는 모든 클래스에 주입 된 컨텍스트를 가질 수있다. 다음은 RoboGuice 2.0으로 작성하는 방법에 대한 작은 샘플입니다 (이 글을 쓰는 시점의 베타 4).
import android.content.Context;
import android.os.Build;
import roboguice.inject.ContextSingleton;
import javax.inject.Inject;
@ContextSingleton
public class DataManager {
@Inject
public DataManager(Context context) {
Properties properties = new Properties();
properties.load(context.getResources().getAssets().open("data.properties"));
} catch (IOException e) {
}
}
}
나는 이것을 어느 시점에서 사용했다 :
ActivityThread at = ActivityThread.systemMain();
Context context = at.getSystemContext();
이것은 시스템 서비스를 얻는 데 사용하고 작업 한 유효한 컨텍스트입니다.
그러나 프레임 워크 / 기본 수정에서만 사용했으며 Android 응용 프로그램에서는 시도하지 않았습니다.
경고 당신이 알고 있어야 :이 문맥에 방송 수신기를 등록 할 때, 그것은 작동하지 않습니다 그리고 당신은 얻을 것이다 :
java.lang.SecurityException : 지정된 호출자 패키지 android가 ProcessRecord 프로세스에서 실행되고 있지 않습니다.
다음을 사용할 수 있습니다.
MainActivity.this.getApplicationContext();
MainActivity.java :
...
public class MainActivity ... {
static MainActivity ma;
...
public void onCreate(Bundle b) {
super...
ma=this;
...
다른 수업 :
public ...
public ANY_METHOD... {
Context c = MainActivity.ma.getApplicationContext();
매니페스트 파일을 수정하지 않으려는 경우 초기 활동에서 정적 변수에 컨텍스트를 수동으로 저장할 수 있습니다.
public class App {
private static Context context;
public static void setContext(Context cntxt) {
context = cntxt;
}
public static Context getContext() {
return context;
}
}
활동 (또는 활동)이 시작될 때 컨텍스트를 설정하십시오.
// MainActivity
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set Context
App.setContext(getApplicationContext());
// Other stuff
}
참고 : 다른 답변과 마찬가지로 이것은 잠재적 인 메모리 누수입니다.
이 소스 에 따르면 ContextWrapper를 확장하여 자신의 컨텍스트를 얻을 수 있습니다
public class SomeClass extends ContextWrapper {
public SomeClass(Context base) {
super(base);
}
public void someMethod() {
// notice how I can use "this" for Context
// this works because this class has it's own Context just like an Activity or Service
startActivity(this, SomeRealActivity.class);
//would require context too
File cacheDir = getCacheDir();
}
}
모든 호출을 다른 컨텍스트에 위임하는 컨텍스트 프록시 구현. 원래 컨텍스트를 변경하지 않고 동작을 수정하기 위해 서브 클래 싱 할 수 있습니다.
어떤 이유로 든 응용 프로그램 / 활동을 확장하는 것뿐만 아니라 일부 팩토리 또는 도우미 클래스에 대한 응용 프로그램 컨텍스트를 모든 클래스에서 원한다면. 앱에 다음 싱글 톤을 추가 할 수 있습니다.
public class GlobalAppContextSingleton {
private static GlobalAppContextSingleton mInstance;
private Context context;
public static GlobalAppContextSingleton getInstance() {
if (mInstance == null) mInstance = getSync();
return mInstance;
}
private static synchronized GlobalAppContextSingleton getSync() {
if (mInstance == null) mInstance =
new GlobalAppContextSingleton();
return mInstance;
}
public void initialize(Context context) {
this.context = context;
}
public Context getApplicationContext() {
return context;
}
}
그런 다음 응용 프로그램 클래스의 onCreate에서 초기화하십시오.
GlobalAppContextSingleton.getInstance().initialize(this);
전화로 어디서나 사용
GlobalAppContextSingleton.getInstance().getApplicationContext()
그러나 응용 프로그램 컨텍스트 이외의 다른 방법으로는이 방법을 권장하지 않습니다. 메모리 누수가 발생할 수 있습니다.
나는 이것을 돕기 위해 Singleton 디자인 패턴의 변형을 사용합니다.
import android.app.Activity;
import android.content.Context;
public class ApplicationContextSingleton {
private static Activity gContext;
public static void setContext( Activity activity) {
gContext = activity;
}
public static Activity getActivity() {
return gContext;
}
public static Context getContext() {
return gContext;
}
}
그런 다음 ApplicationContextSingleton.setContext( this );
내 activity.onCreate () 및 onDestroy ()ApplicationContextSingleton.setContext( null );
에서 호출합니다 .
방금 Vapor API 라는 Android 용 jQuery에서 영감을 얻은 프레임 워크를 출시 하여 앱 개발을보다 단순하게 만들었습니다.
중앙 $
파사드 클래스 는 WeakReference
(Ethan Nicholas의 멋진 Java 블로그 게시물 링크)를 Activity
호출하여 검색 할 수 있는 현재 컨텍스트를 유지합니다.
$.act()
A WeakReference
는 가비지 수집에서 원래 개체를 회수하지 못하도록 참조를 유지하므로 메모리 누수에 문제가 없어야합니다.
물론 단점은 $.act()
null을 반환 할 수 있는 위험을 감수한다는 것 입니다. 나는이 시나리오를 아직 보지 않았으므로 언급 할 가치가있는 최소한의 위험 일 것입니다.
클래스 VaporActivity
로 사용하지 않는 경우 컨텍스트를 수동으로 설정할 수도 있습니다 Activity
.
$.act(Activity);
또한 Vapor API 프레임 워크의 대부분은이 저장된 컨텍스트를 본질적으로 사용하므로 프레임 워크를 사용하기로 결정한 경우 직접 저장하지 않아도됩니다. 자세한 내용과 샘플 은 사이트 를 확인하십시오 .
나는 그것이 도움이되기를 바랍니다 :)
Rohit의 대답은 맞습니다. 그러나 AndroidStudio의 "Instant Run"은 static Context
내가 아는 한 코드에 속성이 없는 것에 달려 있습니다.
Kotlin에서 Context / App Context를 컴패니언 객체에 넣으면 여전히 경고가 발생합니다. Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run)
또는 다음과 같은 것을 사용하는 경우 :
companion object {
lateinit var instance: MyApp
}
응용 프로그램 클래스와 그 자손이 컨텍스트이기 때문에 메모리 누수를 발견하지 않기 위해 보풀을 속이는 것만으로도 App 인스턴스가 여전히 메모리 누수를 일으킬 수 있습니다.
또는 기능 인터페이스 또는 기능 속성을 사용하여 앱 컨텍스트를 얻을 수 있습니다.
간단히 객체 클래스를 생성하십시오 :
object CoreHelper {
lateinit var contextGetter: () -> Context
}
또는 nullable 유형을 사용하여보다 안전하게 사용할 수 있습니다.
object CoreHelper {
var contextGetter: (() -> Context)? = null
}
그리고 App 클래스에서 다음 줄을 추가하십시오.
class MyApp: Application() {
override fun onCreate() {
super.onCreate()
CoreHelper.contextGetter = {
this
}
}
}
매니페스트에서 앱 이름을 . MyApp
<application
android:name=".MyApp"
컨텍스트를 얻으려면 간단히 전화하십시오.
CoreHelper.contextGetter()
// or if you use the nullable version
CoreHelper.contextGetter?.invoke()
그것이 도움이되기를 바랍니다.
이런 식으로 해보십시오
import androidx.appcompat.app.AppCompatActivity; import android.content.Context; import android.os.Bundle; public class MainActivity extends AppCompatActivity { private static Context context; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); context = getApplicationContext(); } public static void getContext(View view){ Toast.makeText(context, "Got my context!", Toast.LENGTH_LONG).show(); } }