web-dev-qa-db-ja.com

どこでもアプリケーションコンテキストを使用する?

Androidアプリでは、次の方法で何か問題があります。

public class MyApp extends Android.app.Application {

    private static MyApp instance;

    public MyApp() {
        instance = this;
    }

    public static Context getContext() {
        return instance;
    }

}

そして文脈が必要とされる(そしてもちろん漏れない)どこにでもそれを渡しますか(例えばSQLiteOpenHelper)?

453
yanchenko

このアプローチには潜在的な問題がいくつかありますが、多くの状況(あなたの例のような)ではうまくいくでしょう。

特に、GUIを扱うもので、Contextを扱うものを扱うときは、注意が必要です。たとえば、アプリケーションのコンテキストをLayoutInflaterに渡すと、例外が発生します。一般的に言って、あなたのアプローチは優れています:Activity'sContextの中でActivityApplication Contextの範囲を超えてコンテキストを渡す場合はActivity避けるメモリリーク .

また、パターンのalternativeとして、ContextオブジェクトでgetApplicationContext()を呼び出すショートカットを使用することができます。アプリケーションコンテキストを取得します。

400
Reto Meier

私の経験では、この方法は必要ありません。何かコンテキストが必要な場合は、通常 View.getContext() を呼び出して取得し、そこで取得したContextを使用して Context.getApplicationContext()Applicationコンテキストを取得します。あなたがApplicationからこれをActivityコンテキストを取得しようとしているなら、あなたはいつでもコールに必要なContextとして渡すことができるべきである Activity.getApplication() を呼び出すことができますSQLiteOpenHelper()へ。

全体的にこの状況に対するあなたのアプローチには問題はないようですが、Contextを扱うときには、公式の Google Android Developers blog /で説明されているようにメモリリークしないようにしてください。

28
snctln

シングルトンがどのようにnullポインタを返すことができますか?その質問です。 (コードを投稿する必要があるため、コメントで回答することはできません。)

それは2つのイベントの間に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

2行目は、Y.xinstanceX.yinstanceであることを示しています。ヌル;変数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

BUTこれはAndroidのApplicationオブジェクトのオプションではありません。プログラマーは作成時の時間を制御しません。

最初の例と2番目の例の違いは、2番目の例は静的ポインタがnullの場合にインスタンスを作成するという点です。しかし、プログラマがAndroidアプリケーションオブジェクトを作成してからシステムで決定することはできません。

UPDATE

初期化された静的フィールドが偶然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

静的変数宣言を1行上に移動することはできません。コードはコンパイルされません。

12

アプリケーションクラス

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

アプリケーションコンテキストを取得するためのラッパーを作成しようとしていますが、それが "null"ポインタを返す可能性があります。

私の理解によれば、私は2つのContext.getApplicationContext()またはActivity.getApplication()のいずれかを呼び出すためのより良いアプローチを推測します。

9
Prasanta

それは良いやり方です。私も自分で使います。コンストラクタを使用する代わりにonCreateをオーバーライドしてシングルトンを設定することをお勧めします。

そしてSQLiteOpenHelperについて述べたのでonCreate ()ではデータベースも開くことができます。

個人的には、私はドキュメンテーションが次のように言って間違っていると思います通常Applicationをサブクラス化する必要はありません。私はその反対が本当だと思います:あなたは常にApplicationをサブクラス化すべきです。

4
Martin

コンストラクタでシステムサービスを取得するには、アプリケーションコンテキストを使用します。これはテストからテストを楽にし、構成からの恩恵を受けます

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はデフォルトのコンストラクタを使用します。

3
Blundell

私はそれが好きですが、代わりにシングルトンをお勧めします:

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;
    }
}
0
Franklin Peña

私は同じアプローチを使用しています、私はもう少しシングルトンを書くことをお勧めします:

public static MyApp getInstance() {

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

    return instance;
}

しかし、私はいたるところで使っているのではなく、できる限りgetContext()getApplicationContext()を使っています。

0
Seraphim's

コンテキストを静的に定義するとメモリリークが発生します

どこにでもコンテキストを取得するための標準的な方法:

public class App extends Application {

    public static transient SoftReference<Context> contextReference;

    @Override
    public void onCreate() {
        super.onCreate();
        contextReference = new SoftReference<Context>(getApplicationContext());
    }
}

このようにして、あなたは次のようなコードのどこにでもコンテキストを持つことができます。

App.contextReference.get();

他の方法ではパフォーマンスが低下し、メモリリークが発生します。

役立つことを願っています...

0
Mr.Hosseini