문제

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

public class MyApp extends android.app.Application {

    private static MyApp instance;

    public MyApp() {
        instance = this;
    }

    public static Context getContext() {
        return instance;
    }

}

모든 곳에 전달합니다(예:SQLiteOpenHelper) 컨텍스트가 필요한 경우(물론 누출되지 않는 경우)?

도움이 되었습니까?

해결책

이 접근 방식에는 몇 가지 잠재적인 문제가 있지만 많은 상황(예: 예)에서는 잘 작동합니다.

특히, 다음과 같은 문제를 다룰 때는 주의해야 합니다. GUI 그것은 Context.예를 들어, 애플리케이션 컨텍스트를 LayoutInflater 예외가 발생합니다.일반적으로 귀하의 접근 방식은 훌륭합니다.다음을 사용하는 것이 좋습니다. Activity's Context 그 안에 Activity, 그리고 Application Context 범위를 벗어나는 컨텍스트를 전달할 때 Activity 에게 메모리 누수 방지.

또한 대안 귀하의 패턴에 따라 전화 바로 가기를 사용할 수 있습니다 getApplicationContext()Context 객체(예: 활동)를 사용하여 애플리케이션 컨텍스트를 가져옵니다.

다른 팁

내 경험상 이 접근 방식은 필요하지 않습니다.어떤 것에 대한 컨텍스트가 필요한 경우 일반적으로 호출을 통해 얻을 수 있습니다. View.getContext() 그리고 Context 거기에서 전화하면 돼 Context.getApplicationContext() 얻기 위해 Application 문맥.당신이 그것을 얻으려고 노력하고 있다면 Application 이것의 맥락을 Activity 언제든지 전화해도 돼 Activity.getApplication() 이는 다음과 같이 전달될 수 있어야 합니다. Context 통화에 필요한 SQLiteOpenHelper().

전반적으로 이 상황에 대한 귀하의 접근 방식에는 문제가 없는 것 같습니다. Context 공식 페이지에 설명된 대로 어디에서나 메모리가 누출되지 않는지 확인하세요. Google Android 개발자 블로그.

어떤 사람들은 다음과 같이 질문했습니다. 싱글톤이 어떻게 널 포인터를 반환할 수 있나요?나는 그 질문에 대답하고 있습니다.(코드를 올려야 하기 때문에 댓글로 답변을 드릴 수 없습니다.)

두 이벤트 사이에 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.x인스턴스 그리고 X.y인스턴스 ~이다 없는;변수가 있기 때문에 null입니다. X.x인스턴스 답변 Y.y인스턴스 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인 경우 인스턴스를 생성한다는 것입니다.하지만 프로그래머는 만들 수 없습니다. 그만큼 시스템이 결정하기 전의 Android 애플리케이션 개체입니다.

업데이트

초기화된 정적 필드가 발생하는 또 다른 수수께끼의 예 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

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

응용 프로그램 컨텍스트를 가져오기 위해 래퍼를 생성하려고 하는데 "null" 포인터.

내가 이해한 바에 따르면 통화에 대한 더 나은 접근 방식은 두 가지 중 하나입니다.Context.getApplicationContext() 또는 Activity.getApplication().

신청 종류:

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

이는 좋은 접근 방식입니다.나 자신도 그것을 사용합니다.나는 단지 재정의하는 것을 제안하고 싶습니다 onCreate 생성자를 사용하는 대신 싱글톤을 설정합니다.

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

개인적으로 나는 문서에 다음과 같이 말하는 것이 잘못되었다고 생각합니다. 일반적으로 애플리케이션을 하위 클래스로 분류할 필요가 없습니다..나는 그 반대가 사실이라고 생각합니다.항상 Application을 하위 클래스로 분류해야 합니다.

저는 생성자에서 시스템 서비스를 얻기 위해 Application Context를 사용할 것입니다.이는 테스트를 용이하게 하고 구성의 이점을 제공합니다.

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

}

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

Android는 기본 생성자를 사용합니다.

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

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

나는 동일한 접근 방식을 사용하고 있습니다. 싱글톤을 좀 더 잘 작성하는 것이 좋습니다.

public static MyApp getInstance() {

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

    return instance;
}

하지만 저는 어디에서나 사용하는 것이 아니라 getContext() 그리고 getApplicationContext() 내가 할 수 있는 곳!

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top