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


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.xinstance 와 X.yinstance 가 null 임을 나타냅니다 . 변수 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.