어디서나 응용 프로그램 컨텍스트를 사용하십니까?


476

Android 앱에서 다음 접근 방식에 문제가 있습니까?

public class MyApp extends android.app.Application {

    private static MyApp instance;

    public MyApp() {
        instance = this;
    }

    public static Context getContext() {
        return instance;
    }

}

컨텍스트가 필요한 곳이라면 어디에서나 전달하십시오 (예 : SQLiteOpenHelper).


23
이를 구현하는 다른 사람들을 위해 자세히 설명하기 위해 <application>다음 속성 정의를 포함하도록 AndroidManifest.xml 파일 의 노드 를 수정할 수 있습니다 android:name="MyApp". MyApp은 매니페스트가 참조하는 것과 동일한 패키지에 있어야합니다.
Matt Huggins

6
SQLiteOpenHelper에 컨텍스트를 제공하는 문제를 해결하는 가장 좋은 방법! 싱글 톤 "SQLiteManager"를 구현했으며 "F는 싱글 톤에 대한 컨텍스트를 어떻게 얻습니까?"
누군가 어딘가에

8
슈퍼 인터페이스 중 하나를 통해 애플리케이션을 반환한다는 것을 알기 때문에 MyApp 내에 추가 메소드를 제공하면 사용할 수 없습니다. getContext ()는 대신 MyApp의 리턴 유형을 가져야하며, 나중에 추가 된 메소드와 ContextWrapper 및 Context의 모든 메소드를 사용할 수 있습니다.

5
goo.gl/uKcFn 도 참조하십시오 -비슷한 게시물과 관련된 또 다른 답변입니다. c'tor가 아닌 onCreate에서 정적 변수를 더 잘 설정하십시오.
AlikElzin-kilaka

1
@ChuongPham 만약 프레임 워크가 당신의 앱을 죽였다면 null 컨텍스트에 접근하는 것이 없을 것입니다.
Kevin Krumwiede

답변:


413

이 방법에는 몇 가지 잠재적 인 문제가 있지만, 많은 경우 (예 : 예) 잘 작동합니다.

특히을 GUI요구하는 모든 것을 다룰 때는 조심 해야합니다 Context. 예를 들어 응용 프로그램 컨텍스트를 응용 프로그램으로 전달 LayoutInflater하면 예외가 발생합니다. 일반적으로, 당신의 접근 방식이 우수합니다 : 그것은을 사용하는 것이 좋은 방법입니다 Activity's Context그 내에서 Activity, 그리고 Application Context의 범위를 벗어나는 상황에 맞는 전달할 때 Activity하는 메모리 누수를 방지를 .

또한,로 다른 사용자의 패턴에 당신이 전화의 바로 가기를 사용할 수 있습니다 getApplicationContext()A의 Context응용 프로그램 컨텍스트를 얻기 위해 (예 : 활동으로) 개체를.


22
감동적인 답변 감사합니다. 콘텐츠 제공 업체와 함께 가고 싶지 않기 때문에 지속성 계층에만이 방법을 사용한다고 생각합니다. 응용 프로그램 자체에서 컨텍스트를 얻는 대신 컨텍스트가 제공 될 것으로 예상되는 방식으로 SQLiteOpenHelper를 설계 한 동기가 무엇인지 궁금합니다. 추신 그리고 당신의 책은 훌륭합니다!
yanchenko 2016 년

7
응용 프로그램 컨텍스트를 사용하여 LayoutInflator저에게 효과적이었습니다. 지난 3 년 동안 바뀌었을 것입니다.
Jacob Phillips

5
@JacobPhillips 활동 컨텍스트없이 LayoutInflator를 사용하면 해당 활동의 스타일이 누락됩니다. 따라서 어떤 의미에서는 작동하지만 다른 의미로는 작동하지 않습니다.
Mark

1
@MarkCarter 어플리케이션 컨텍스트를 사용하면 액티비티 스타일이 누락 될 것입니까?
Jacob Phillips

1
@JacobPhillips 예, 모든 액티비티는 다른 방식으로 스타일이 지정 될 수 있으므로 애플리케이션 컨텍스트에 스타일을 지정할 수 없습니다.
Mark

28

내 경험상이 접근법은 필요하지 않아야합니다. 무엇이든 컨텍스트가 필요한 경우 일반적으로 View.getContext () 호출을 통해 얻을 수 있으며 얻은 컨텍스트를 사용하여 Context.getApplicationContext ()Context호출 하여 컨텍스트 를 가져올 수 있습니다. 컨텍스트 를 가져 오려고하면 언제든지 Activity.getApplication () 을 호출 할 수 있으며 호출에 필요한 대로 전달할 수 있어야 합니다 .ApplicationApplicationActivityContextSQLiteOpenHelper()

전반적 으로이 상황에 대한 접근 방식에는 문제가없는 것 같지만 처리 할 때 Context공식 Google Android 개발자 블로그 에 설명 된 것처럼 메모리 누수가 없는지 확인하십시오 .


13

어떤 사람들은 싱글 톤이 어떻게 널 포인터를 반환 할 수 있습니까? 나는 그 질문에 대답하고있다. (코드를 게시해야하므로 의견에 답할 수 없습니다.)

두 이벤트 사이에 null을 반환 할 수 있습니다. (1) 클래스가로드되고 (2)이 클래스의 객체가 생성됩니다. 예를 들면 다음과 같습니다.

class X {
    static X xinstance;
    static Y yinstance = Y.yinstance;
    X() {xinstance=this;}
}
class Y {
    static X xinstance = X.xinstance;
    static Y yinstance;
    Y() {yinstance=this;}
}

public class A {
    public static void main(String[] p) {
    X x = new X();
    Y y = new Y();
    System.out.println("x:"+X.xinstance+" y:"+Y.yinstance);
    System.out.println("x:"+Y.xinstance+" y:"+X.yinstance);
    }
}

코드를 실행 해 봅시다 :

$ javac A.java 
$ java A
x:X@a63599 y:Y@9036e
x:null y:null

두 번째 줄은 Y.xinstanceX.yinstancenull 임을 나타냅니다 . 변수 X.xinstance ans Y.yinstance 가 null 일 때 읽혀 지기 때문에 null입니다.

이 문제를 해결할 수 있습니까? 예,

class X {
    static Y y = Y.getInstance();
    static X theinstance;
    static X getInstance() {if(theinstance==null) {theinstance = new X();} return theinstance;}
}
class Y {
    static X x = X.getInstance();
    static Y theinstance;
    static Y getInstance() {if(theinstance==null) {theinstance = new Y();} return theinstance;}
}

public class A {
    public static void main(String[] p) {
    System.out.println("x:"+X.getInstance()+" y:"+Y.getInstance());
    System.out.println("x:"+Y.x+" y:"+X.y);
    }
}

이 코드는 이상이 없음을 보여줍니다.

$ javac A.java 
$ java A
x:X@1c059f6 y:Y@152506e
x:X@1c059f6 y:Y@152506e

그러나 이것은 Android Application객체 의 옵션이 아닙니다 . 프로그래머는 생성 시간을 제어하지 않습니다.

다시 한 번 : 첫 번째 예제와 두 번째 예제의 차이점은 두 번째 예제는 정적 포인터가 널인 경우 인스턴스를 작성한다는 것입니다. 그러나 프로그래머는 만들 수 없습니다 시스템이 그것을 할하기로 결정하기 전에 안드로이드 응용 프로그램 개체를.

최신 정보

초기화 된 정적 필드가 발생하는 또 하나의 수수께끼 예 null입니다.

Main.java :

enum MyEnum {
    FIRST,SECOND;
    private static String prefix="<", suffix=">";
    String myName;
    MyEnum() {
        myName = makeMyName();
    }
    String makeMyName() {
        return prefix + name() + suffix;
    }
    String getMyName() {
        return myName;
    }
}
public class Main {
    public static void main(String args[]) {
        System.out.println("first: "+MyEnum.FIRST+" second: "+MyEnum.SECOND);
        System.out.println("first: "+MyEnum.FIRST.makeMyName()+" second: "+MyEnum.SECOND.makeMyName());
        System.out.println("first: "+MyEnum.FIRST.getMyName()+" second: "+MyEnum.SECOND.getMyName());
    }
}

그리고 당신은 얻을 :

$ javac Main.java
$ java Main
first: FIRST second: SECOND
first: <FIRST> second: <SECOND>
first: nullFIRSTnull second: nullSECONDnull

정적 변수 선언을 한 줄 위로 이동할 수 없으며 코드는 컴파일되지 않습니다.


3
유용한 예; 그런 구멍이 있다는 것을 아는 것이 좋습니다. 내가 이것에서 벗어난 것은 클래스의 정적 초기화 중에 그러한 정적 변수를 참조하지 않아야한다는 것입니다.
ToolmakerSteve

10

응용 프로그램 클래스 :

import android.app.Application;
import android.content.Context;

public class MyApplication extends Application {

    private static Context mContext;

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

    public static Context getAppContext() {
        return mContext;
    }

}

AndroidManifest에서 애플리케이션을 선언하십시오.

<application android:name=".MyApplication"
    ...
/>

용법:

MyApplication.getAppContext()

1
메모리 누수가 발생하기 쉽습니다. 이러면 안됩니다.
Dragas

9

응용 프로그램 컨텍스트를 얻기 위해 랩퍼를 작성하려고하며 " null"포인터를 리턴 할 가능성이 있습니다 .

내 이해에 따르면, 2 Context.getApplicationContext() 나 중 하나를 호출하는 것이 더 나은 방법이라고 생각합니다 Activity.getApplication().


13
언제 null을 반환해야합니까?
중단

25
내가 아는 정적 Context.getApplicationContext () 메소드가 없습니다. 뭔가 빠졌습니까?
dalcantara

또한 응용 프로그램에서 동일한 접근 방식을 구현하지만 SQLiteOpenHelper를 호출하면 null 포인터가 반환됩니다. 이런 상황에 대한 답.
ashutosh

2
앱 전에로드 된 contentprovider에서 SQLiteOpenHelper를 호출하는 경우에 해당됩니다.
Gunnar Bernstein

5

좋은 접근 방법입니다. 나 자신도 사용합니다. onCreate생성자를 사용하는 대신 싱글 톤을 설정 하도록 재정의 하는 것이 좋습니다 .

그리고 당신이 언급 한 이후 SQLiteOpenHelper: onCreate ()데이터베이스를 열 수도 있습니다.

개인적으로 필자 는 일반적으로 Application을 서브 클래스 화 할 필요가 없다는 말이 잘못되었다고 생각합니다 . 나는 그 반대가 사실이라고 생각한다 : 당신은 항상 Application을 서브 클래 싱해야한다.


3

응용 프로그램 컨텍스트를 사용하여 생성자에서 시스템 서비스를 가져옵니다. 이것은 테스트를 용이하게하고 컴포지션의 이점을 제공합니다

public class MyActivity extends Activity {

    private final NotificationManager notificationManager;

    public MyActivity() {
       this(MyApp.getContext().getSystemService(NOTIFICATION_SERVICE));
    }

    public MyActivity(NotificationManager notificationManager) {
       this.notificationManager = notificationManager;
    }

    // onCreate etc

}

그런 다음 테스트 클래스는 오버로드 된 생성자를 사용합니다.

안드로이드는 기본 생성자를 사용합니다.


1

나는 그것을 좋아하지만 대신 싱글 톤을 제안 할 것입니다.

package com.mobidrone;

import android.app.Application;
import android.content.Context;

public class ApplicationContext extends Application
{
    private static ApplicationContext instance = null;

    private ApplicationContext()
    {
        instance = this;
    }

    public static Context getInstance()
    {
        if (null == instance)
        {
            instance = new ApplicationContext();
        }

        return instance;
    }
}

31
android.app.application을 확장하면 이미 싱글 톤을 보장하므로 불필요합니다
Vincent

8
비 활동 수업을 원한다면 어떻게해야합니까?
Maxrunner

9
new단위 테스트를 제외하고 응용 프로그램을 직접 사용 해서는 안됩니다 . 운영 체제가 그렇게 할 것입니다. 또한 생성자가 없어야합니다. 그게 다야 onCreate.
Martin

@Vincent : 이것에 대한 링크를 게시 할 수 있습니까? 바람직 코드 - 내가 여기 물어 오전 : stackoverflow.com/questions/19365797/...
Mr_and_Mrs_D

@radzio 왜 우리는 생성자에서 그것을해서는 안됩니까?
Miha_x64

1

나는 같은 접근법을 사용하고 있는데, 싱글 톤을 조금 더 잘 작성하는 것이 좋습니다.

public static MyApp getInstance() {

    if (instance == null) {
        synchronized (MyApp.class) {
            if (instance == null) {
                instance = new MyApp ();
            }
        }
    }

    return instance;
}

그러나 나는 모든 곳에서 사용하지 않고, 사용 getContext()하고 getApplicationContext()어디에서 할 수 있습니까!


따라서 내가 이해할 수 있도록 답변을 내리는 이유를 설명하는 의견을 작성하십시오. 싱글 톤 접근법은 활동이나 뷰 본문 외부에서 유효한 컨텍스트를 얻는 데 널리 사용됩니다.
Seraphim 's

1
운영 체제가 응용 프로그램이 정확히 한 번 인스턴스화되도록 보장 할 필요가 없습니다. 어떤 경우에는 onCreate ()에서 Singelton을 설정하는 것이 좋습니다.
Martin

1
단일 스레드를 게으르게 초기화하는 스레드 안전 방법은 훌륭하지만 여기서는 필요하지 않습니다.
naXa

2
와우, 사람들이 마침내 이중 점검 잠금 사용을 중단했다고 생각했을 때 ... cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Søren Boisen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.