どこでもアプリケーションコンテキストを使用しますか?
-
13-09-2019 - |
質問
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
を呼び出すショートカットを使用することができます。
他のヒント
私の経験では、このアプローチは必要ありません。あなたは何のためのコンテキストが必要な場合は、通常、<のhref =「http://developer.android.com/reference/android/view/View.html#getContext()」のrel = "nofollowをnoreferrerへの呼び出しを介してそれを得ることができます"> View.getContext()とが得Context
を使用してあなたが呼び出すことができます<のhref =" http://developer.android.com/reference/android/content/Context.html#getApplicationContext()」REL = "nofollowをnoreferrer"> Context.getApplicationContext()のはApplication
コンテキストを取得します。あなたはApplication
からこれをActivity
コンテキストを取得しようとしている場合は、常に<のhref =「http://developer.android.com/reference/android/app/Activity.html#getApplication()」のrel = "nofollowを呼び出すことができますContext
の呼び出しのために必要SQLiteOpenHelper()
として渡すことができるようにする必要がありnoreferrer "> Activity.getApplication()のます。
全体的に、このような状況のためにあなたのアプローチに問題があるとは思えませんが、Context
を扱うときだけ<のhref = "HTTP公式に説明するように、あなたがどこにもメモリリークしていないことを確認してください:// android- developers.blogspot.com/2009/01/avoiding-memory-leaks.html」のrel = "nofollowをnoreferrer"> GoogleのAndroid開発者ブログでます。
一部の人は次のように尋ねました。 シングルトンはどのようにして 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.xインスタンス そして X.yinstance は ヌル;変数が 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
物体:プログラマは、それが作成される時間を制御しません。
もう一度:最初の例と 2 番目の例の違いは、2 番目の例では静的ポインターが null の場合にインスタンスを作成することです。でもプログラマーは作れない の システムが実行を決定する前の Android アプリケーション オブジェクト。
アップデート
初期化された静的フィールドがたまたま次のような不可解な例です。 null
.
メイン.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 行上に移動することはできないことに注意してください。コードはコンパイルされません。
あなたは、アプリケーション・コンテキストを取得するためにラッパーを作成しようとしていると、それは「null
」ポインタを返す可能性がある。
私の理解あたりとして、私は2のいずれかをcall-してより良いアプローチを推測します
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 ()
ではあなたにも、データベースを開くことができます。
個人的に私は、ドキュメントは、のアプリケーションのをサブクラス化する必要は通常ありませんと言って、それが間違ってましたと思います。私は反対が本当だと思う:あなたは常に、サブクラスアプリケーションをすべきである。
。私はコンストラクタでシステムサービスを取得するためにアプリケーション・コンテキストを使用します。これは、組成物からテスト&メリットが容易になります。
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
}
Testクラスは、オーバーロードされたコンストラクタを使用することになります。
の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()
を使用し、どこにでも使用していないよ!