program story

Android에서 '컨텍스트'를 얻는 정적 방법?

inputbox 2020. 9. 28. 09:03
반응형

Android에서 '컨텍스트'를 얻는 정적 방법?


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()애플리케이션 컨텍스트를 정적으로 가져옵니다.


애플리케이션 컨텍스트를 가져 오는 편리한 메서드를 원하는 대부분의 앱은 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 ()를 사용하는 Context를 제공 할 수 있습니다.


반사

리플렉션을 사용하여 애플리케이션 컨텍스트를 얻는 또 다른 방법이 있습니다. 리플렉션은 Android에서 자주 무시되며 개인적으로 프로덕션에서 사용해서는 안된다고 생각합니다.

애플리케이션 컨텍스트를 검색하려면 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);
} 

즐거운 코딩 되세요!


우리가 응용 프로그램 컨텍스트를 얻는 것에 대해 이야기하고 있다고 가정하고, @Rohit Ghatol이 응용 프로그램을 확장하는 제안대로 구현했습니다. 그때 일어난 일은 그런 방식으로 검색된 컨텍스트가 항상 null이 아니라는 보장이 없다는 것입니다. 당신이 그것을 필요로 할 때, 그것은 보통 당신이 시간을 지체 할 수없는 도우미를 초기화하거나 자원을 얻기를 원하기 때문입니다. null 케이스를 처리하면 도움이되지 않습니다. 그래서 문서에 명시된대로 기본적으로 Android 아키텍처와 싸우고 있음을 이해했습니다.

참고 : 일반적으로 Application을 하위 클래스화할 필요가 없습니다. 대부분의 상황에서 정적 싱글 톤은 더 모듈화 된 방식으로 동일한 기능을 제공 할 수 있습니다. 싱글 톤에 전역 컨텍스트가 필요한 경우 (예 : 브로드 캐스트 수신기 등록), 싱글 톤의 getInstance () 메서드를 호출 할 때 Context.getApplicationContext ()를 Context 인수로 포함합니다.

Dianne Hackborn이 설명했습니다.

응용 프로그램이 파생 될 수있는 유일한 이유는 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 블로그 에서 더 자세한 버전을 읽을 수 있습니다.


아뇨,없는 것 같아요. 안타깝게도 .NET 의 다른 하위 클래스 중 하나 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 스레드 외부에서 메서드를 호출하거나 응용 프로그램이 스레드에 바인딩되지 않은 경우이 메서드가 null을 반환 할 수 있습니다.

응용 프로그램 코드를 변경할 수 있다면 @RohitGhatol 솔루션 을 사용하는 것이 좋습니다 .


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

AlertDialogwith 를 만들려고 AlertDialog.Builder하면 Application컨텍스트가 작동하지 않습니다. 나는 당신이 현재의 맥락이 필요하다고 믿습니다 Activity...


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 프로세스에서 실행되고 있지 않습니다.


Kotlin 방식 :

명백한:

<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를 통해 속성에 액세스 할 수 있습니다.


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

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
}

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


Kotlin

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

나는 당신이 getAppContext()방법을 위해 몸이 필요하다고 생각합니다 .

public static Context getAppContext()
   return MyApplication.context; 

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

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

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

ContextWrapper 용 JavaDoc

단순히 모든 호출을 다른 Context에 위임하는 Context의 프록시 구현입니다. 원래 컨텍스트를 변경하지 않고 동작을 수정하기 위해 서브 클래 싱 할 수 있습니다.


나는 이것을 돕기 위해 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.onCreateApplicationContextSingleton.setContext( null );들의 OnDestroy () ;


저는 앱 개발을 더 간단하게 만드는 것을 목표로하는 Vapor API 라는 Android 용 jQuery에서 영감을받은 프레임 워크를 출시했습니다 .

중앙 $파사드 클래스 는 다음 을 호출하여 검색 할 수 WeakReference있는 현재 Activity컨텍스트 에 대한 (Ethan Nicholas의 멋진 Java 블로그 게시물 링크)를 유지합니다 .

$.act()

A WeakReference maintains a reference without preventing the garbage collection reclaiming the original object, so you shouldn't have a problem with memory leaks.

The downside of course is that you run the risk that $.act() could return null. I have not come across this scenario yet though, so it's perhaps just a minimal risk, worth mentioning.

You can also set the context manually if you are not using VaporActivity as your Activity class:

$.act(Activity);

Also, much of the Vapor API framework uses this stored context inherently which might mean you needn't store it yourself at all if you decide to use the framework. Check out the site for more information and samples.

I hope that helps :)


If you for some reason want Application context in any class, not just those extending application/activity, maybe for some factory or helper classes. You can add the following singleton to your app.

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

then initialize it in your application class's onCreate with

GlobalAppContextSingleton.getInstance().initialize(this);

use it anywhere by calling

GlobalAppContextSingleton.getInstance().getApplicationContext()

I don't recommend this approach to anything but application context however. As it can cause memory leaks.


Rohit's answer seems correct. However, be aware that AndroidStudio's "Instant Run" depends on not having static Context attributes in your code, as far as I know.


So i modified the accepted answer because its causing a memory leak, this is what i came up with...

AndroidManifest.xml

    <application android:name="com.xyz.MyApplication">
...

    </application>

MyApplication.java

public class MyBakingAppContext extends Application {
    private static Object mContext;

    public void onCreate() {
        super.onCreate();
        mContext = getApplicationContext();
    }

    public static Context getAppContext() {
        return (Context)mContext;
    }
}

What i actually did is, assign a context to an object and return the object as a context(casting it to context). Hope it help.


in Kotlin, putting Context/App Context in companion object still produce warning Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run)

or if you use something like this:

    companion object {
        lateinit var instance: MyApp
    }

It's simply fooling the lint to not discover the memory leak, the App instance still can produce memory leak, since Application class and its descendant is a Context.

Alternatively, you can use functional interface or Functional properties to help you get your app context.

Simply create an object class:

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

or you could use it more safely using nullable type:

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

and in your App class add this line:


class MyApp: Application() {

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

and in your manifest declare the app name to . MyApp


    <application
            android:name=".MyApp"

When you wanna get the context simply call:

CoreHelper.contextGetter()

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

Hope it will help.

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

반응형