itsource

안드로이드에서 '콘텍스트'를 얻는 정적인 방법?

mycopycode 2023. 6. 6. 08:21
반응형

안드로이드에서 '콘텍스트'를 얻는 정적인 방법?

전류를 얻을 수 있는 방법이 있습니까?Context정적 메서드 내부의 인스턴스?

저는 'Context' 인스턴스가 변경될 때마다 저장하는 것이 싫어서 그런 방법을 찾고 있습니다.

수행할 작업:

Android 매니페스트 파일에서 다음을 선언합니다.

<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()응용프로그램 컨텍스트를 정적으로 가져옵니다.

응용프로그램 컨텍스트를 얻는 편리한 방법을 원하는 대부분의 응용프로그램은 확장된 자체 클래스를 만듭니다.

안내

먼저 다음과 같은 클래스를 프로젝트에 생성하여 이 작업을 수행할 수 있습니다.

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.xml의 태그에 클래스 이름을 지정해야 합니다.

<application 
    ...
    android:name="com.example.App" >
    ...
</application>

그런 다음 다음을 사용하여 정적 방법으로 응용 프로그램 컨텍스트를 검색할 수 있습니다.

public static void someMethod() {
    Context context = App.getContext();
}

경고

프로젝트에 위와 같은 내용을 추가하기 전에 설명서에 나와 있는 내용을 고려해야 합니다.

일반적으로 응용프로그램을 하위 분류할 필요가 없습니다.대부분의 경우 정적 싱글 버튼은 보다 모듈식으로 동일한 기능을 제공할 수 있습니다.싱글톤에 글로벌 컨텍스트가 필요한 경우(예: 브로드캐스트 수신기 등록), 이를 검색하는 함수에 처음 싱글톤을 구성할 때 내부적으로 Context.getApplicationContext()를 사용하는 컨텍스트를 지정할 수 있습니다.


반사

반사를 사용하여 응용프로그램 컨텍스트를 가져오는 다른 방법도 있습니다.Android에서 반사는 종종 경시되며 저는 개인적으로 이것이 생산에 사용되어서는 안 된다고 생각합니다.

응용 프로그램 컨텍스트를 검색하려면 숨겨진 클래스(활동)에서 메서드를 호출해야 합니다.스레드)는 API 1부터 사용할 수 있습니다.

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);
} 

해피 코딩!

애플리케이션 컨텍스트를 얻는 것에 대해 이야기하고 있다고 가정하면, @Rohit Gatol extending Application에서 제안한 대로 구현했습니다.그 때 무슨 일이 일어났는가 하면, 그러한 방식으로 검색된 컨텍스트가 항상 null이 아닐 것이라는 보장이 없다는 것입니다.필요할 때는 대개 도우미를 초기화하거나 리소스를 확보하기 위해 시간을 지체할 수 없습니다. null 사례를 처리하는 것은 도움이 되지 않습니다.문서에 명시된 바와 같이 기본적으로 Android 아키텍처에 대항하여 싸우고 있다는 것을 이해했습니다.

참고: 일반적으로 응용프로그램을 하위 분류할 필요가 없습니다.대부분의 경우 정적 싱글 버튼은 보다 모듈식으로 동일한 기능을 제공할 수 있습니다.싱글톤에 글로벌 컨텍스트가 필요한 경우(예: 브로드캐스트 수신기 등록) 싱글톤의 getInstance() 메서드를 호출할 때 Context 인수로 Context.getApplicationContext()를 포함합니다.

그리고 Dianne Hackborn이 설명했습니다.

애플리케이션이 파생될 수 있는 것으로 존재하는 유일한 이유는 1.0 이전 개발 과정에서 애플리케이션 개발자 중 한 명이 파생할 수 있는 최상위 애플리케이션 개체가 필요하다고 계속해서 저를 괴롭혔기 때문입니다. 따라서 애플리케이션 모델을 "정상"으로 전환할 수 있게 되었습니다.저는 그것에 굴복한 것을 영원히 후회할 것입니다.:)

그녀는 또한 이 문제에 대한 해결책을 제안하고 있습니다.

원하는 것이 앱의 다른 부분에서 공유할 수 있는 글로벌 상태라면 싱글톤을 사용하십시오. [...] 이것은 이러한 것들을 관리하는 방법으로 더 자연스럽게 이어집니다. 온디맨드로 초기화하는 것입니다.

그래서 제가 한 일은 애플리케이션을 확장하는 것을 없애고, 애플리케이션 컨텍스트에 대한 참조를 개인 생성자에 저장하면서 컨텍스트를 Singleton 도우미의 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 블로그에서 더 자세한 버전을 읽을 수 있습니다.

아니요, 없는 것 같아요.불행하게도, 당신은 계속 전화하고 있습니다.getApplicationContext()Activity 또의 다른하클중하나래의 다른 중 입니다.Context또한 이 질문은 다소 관련이 있습니다.

UI 스레드의 모든 위치에서 응용 프로그램(콘텍스트)을 가져오는 문서화되지 않은 방법은 다음과 같습니다.숨겨진 정적 방법에 의존합니다.ActivityThread.currentApplication()안드로이드 4.x에서는 작동해야 합니다.

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 스레드 외부에서 메서드를 호출하거나 응용 프로그램이 스레드에 바인딩되지 않은 경우 이 메서드가 null을 반환할 수 있습니다.

애플리케이션 코드를 변경할 수 있다면 @RohitGatol의 솔루션을 사용하는 것이 더 좋습니다.

코틀린 방식:

매니페스트:

<application android:name="MyApplication">

</application>

마이어플리케이션.kt

class MyApplication: Application() {

    override fun onCreate() {
        super.onCreate()
        instance = this
    }

    companion object {
        lateinit var instance: MyApplication
            private set
    }
}

그런 다음 다음 다음을 통해 자산에 액세스할 수 있습니다.MyApplication.instance

컨텍스트를 사용하는 용도에 따라 다릅니다.저는 그 방법에 대한 적어도 한 가지 단점을 생각할 수 있습니다.

당신이 생경우는려하성을 만들려고 한다면.AlertDialog와 함께AlertDialog.Builder,Application컨텍스트가 작동하지 않습니다.현재 상황에 대한 맥락이 필요하다고 생각합니다.Activity...

코틀린

open class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        mInstance = this
    }

    companion object {
        lateinit var mInstance: MyApp
        fun getContext(): Context? {
            return mInstance.applicationContext
        }
    }
}

다음과 같은 컨텍스트 가져오기

MyApp.mInstance

또는

MyApp.getContext()

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();

이것은 시스템 서비스를 받을 때 사용하고 작업한 유효한 컨텍스트입니다.

하지만 프레임워크/베이스 수정에만 사용했고 안드로이드 앱에서는 사용하지 않았습니다.

반드시 알아야 하는 경고:이 컨텍스트에서 브로드캐스트 수신기를 등록하면 이 기능이 작동하지 않으며 다음과 같은 정보를 얻을 수 있습니다.

자바.java.java보안.예외: 지정된 호출자 패키지 안드로이드가 프로세스 레코드에서 실행되고 있지 않습니다.

매니페스트 파일을 수정하지 않으려면 초기 활동에서 수동으로 정적 변수에 컨텍스트를 저장할 수 있습니다.

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
}

참고: 다른 모든 답변과 마찬가지로 잠재적인 메모리 누수입니다.

Context Kotlin은 컨텍스트/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
    }

애플리케이션 클래스와 해당 하위 클래스가 컨텍스트이기 때문에 메모리 누수를 발견하지 못하는 것은 린트를 속이는 것일 뿐입니다. 앱은 여전히 메모리 누수를 생성할 수 있습니다.

또는 기능 인터페이스 또는 기능 속성을 사용하여 앱 컨텍스트를 가져올 수 있습니다.

객체 클래스를 만듭니다.

object CoreHelper {
    lateinit var contextGetter: () -> Context
}

또는 null 가능한 유형을 사용하여 보다 안전하게 사용할 수 있습니다.

object CoreHelper {
    var contextGetter: (() -> Context)? = null
}

앱 클래스에 다음 행을 추가합니다.


class MyApp: Application() {

    override fun onCreate() {
        super.onCreate()
        CoreHelper.contextGetter = {
            this
        }
    }
}

에서 앱 을 그고당매신트앱서이선언다니합름을에리니스페의▁the로 합니다.. MyApp


    <application
            android:name=".MyApp"

상황을 파악하려면 다음과 같이 전화하십시오.

CoreHelper.contextGetter()

// or if you use the nullable version
CoreHelper.contextGetter?.invoke()

도움이 되길 바랍니다.

소스에 따르면 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();
    }
}

컨텍스트 래퍼용 JavaDoc

모든 호출을 다른 컨텍스트에 위임하는 컨텍스트의 프록시 구현.원래 컨텍스트를 변경하지 않고 동작을 수정하도록 하위 분류할 수 있습니다.

다음을 사용할 수 있습니다.

MainActivity.this.getApplicationContext();

기본 활동.java:

...
public class MainActivity ... {
    static MainActivity ma;
...
    public void onCreate(Bundle b) {
         super...
         ma=this;
         ...

다른 클래스:

public ...
    public ANY_METHOD... {
         Context c = MainActivity.ma.getApplicationContext();

제 생각에 당신은 시체가 필요할 것 같습니다.getAppContext()방법:

public static Context getAppContext()
   return MyApplication.context; 

어떤 이유로 응용프로그램/활동을 확장하는 클래스뿐만 아니라 일부 공장 또는 도우미 클래스의 응용프로그램 컨텍스트를 원하는 경우.다음 싱글톤을 앱에 추가할 수 있습니다.

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;
    }
}

그런 다음 응용 프로그램 클래스의 에서 초기화합니다.

GlobalAppContextSingleton.getInstance().initialize(this);

전화로 어디든 사용하세요.

GlobalAppContextSingleton.getInstance().getApplicationContext()

그러나 애플리케이션 컨텍스트 이외에는 이러한 접근 방식을 권장하지 않습니다.메모리 누수의 원인이 될 수 있기 때문입니다.

저는 이것을 돕기 위해 싱글턴 디자인 패턴의 변형을 사용합니다.

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 );활동에서.Create()에.ApplicationContextSingleton.setContext( null );in Destroy();

저는 방금 앱 개발을 단순화하는 것을 목표로 하는 안드로이드용 jQuery에서 영감을 받은 Vapor API라는 프레임워크를 출시했습니다.

중앙 파사드 클래스는 (이단 니콜라스의 멋진 자바 블로그 게시물에 대한 링크) 최신 정보를 유지합니다.Activity호출하여 검색할 수 있는 컨텍스트:

$.act()

A WeakReference에서는 가비지 컬렉션이 원래 개체를 회수하는 것을 방지하지 않고 참조를 유지 관리하므로 메모리 누수에 문제가 없습니다.

물론 단점은 당신이 위험을 무릅쓴다는 것입니다.$.act()할 수 .하지만 저는 아직 이 시나리오를 접하지 못했기 때문에 아마도 언급할 가치가 있는 최소한의 위험일 것입니다.

사용하지 않는 경우 컨텍스트를 수동으로 설정할 수도 있습니다.Activity 명령어:

$.act(Activity);

또한 Vapor API 프레임워크의 대부분은 이 저장된 컨텍스트를 기본적으로 사용하므로 프레임워크를 사용하기로 결정한 경우 직접 저장할 필요가 전혀 없습니다.자세한 정보와 샘플은 사이트를 확인하십시오.

그게 도움이 되길 바랍니다 :)

로히트의 답은 맞는 것 같습니다., Run"은 그러나 Android Studio의 "Instant Run (즉시 실행)"이 없는 것에 static Context내가 아는 한, 당신 코드의 속성.

오늘을 위한 올바른 방법context의존성 주입을 사용하는 것입니다.예를 들어, Hilt를 사용하여 필요한 모든 위치에 컨텍스트를 주입할 수 있습니다.에게 필하다고치가 필요하다고 context일부 데이터베이스 관리자에서는 다음과 같은 방법으로 이 문제를 해결할 수 있습니다.

그라들에 힐트 추가:

implementation "com.google.dagger:hilt-android:2.35"
kapt "com.google.dagger:hilt-android-compiler:2.35"

를 " " " 로 정의합니다.@HiltAndroidApp주석(예를 들어 데이터베이스 관리자를 주입):

@HiltAndroidApp
class MyApplication : Application() {

    @Inject
    lateinit var dbManager: DBManager

    override fun onCreate() {
        super.onCreate()
        dbManager.initDB()
    }
}

관리자를 합니다.@Singleton예를 들어):

@Singleton
class DBManager @Inject constructor(
    @ApplicationContext private val context: Context
) {

    fun initDB() {
        // context is avaiable
        databaseInit(context)
    }
}

그리고 이것이 마지막입니다.DBManager메모리 누수 없이 올바른 방법으로 컨텍스트에 액세스할 수 있습니다.

얻을 수 있는 또 다른 대안context의 하위 .Application숨겨진 클래스를 사용하지 않는 개체는 ContentProvider를 사용하는 것입니다.원스 더onCreate메서드가 호출되면 컨텍스트를 사용할 수 있어야 합니다.코틀린에서 이런 일을 할 수 있습니다.

class ContextContentProvider : ContentProvider() {
    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?) = 0

    override fun getType(uri: Uri): String? = null

    override fun insert(uri: Uri, values: ContentValues?): Uri? = null

    override fun onCreate(): Boolean {
        applicationContext = context
        return true
    }

    override fun query(
        uri: Uri, projection: Array<String>?, selection: String?,
        selectionArgs: Array<String>?, sortOrder: String?
    ): Cursor? = null

    override fun update(
        uri: Uri, values: ContentValues?, selection: String?,
        selectionArgs: Array<String>?
    ) = 0

    companion object {
        private var applicationContext: Context? = null

        @JvmStatic
        fun applicationContext() = applicationContext
    }
}

든지 전화를 걸 수 .ContextContentProvider.applicationContext()방법

에다른권사합니다야용에서 .AndroidManifest.xml이미 다른 콘텐츠 공급자가 있고 콘텐츠 공급자를 내보내지 않는 경우.

<application>
    <provider
        android:name=".ContextContentProvider"
        android:authorities="${applicationId}.ContextContentProvider"
        android:enabled="true"
        android:exported="false" />
</application>

언급URL : https://stackoverflow.com/questions/2002288/static-way-to-get-context-in-android

반응형