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
に 避けるメモリリーク .
また、パターンのalternativeとして、Context
オブジェクトでgetApplicationContext()
を呼び出すショートカットを使用することができます。アプリケーションコンテキストを取得します。
私の経験では、この方法は必要ありません。何かコンテキストが必要な場合は、通常 View.getContext() を呼び出して取得し、そこで取得したContext
を使用して Context.getApplicationContext() はApplication
コンテキストを取得します。あなたがApplication
からこれをActivity
コンテキストを取得しようとしているなら、あなたはいつでもコールに必要なContext
として渡すことができるべきである Activity.getApplication() を呼び出すことができますSQLiteOpenHelper()
へ。
全体的にこの状況に対するあなたのアプローチには問題はないようですが、Context
を扱うときには、公式の Google Android Developers blog /で説明されているようにメモリリークしないようにしてください。 。
シングルトンがどのように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.xinstanceとX.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行上に移動することはできません。コードはコンパイルされません。
アプリケーションクラス
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()
アプリケーションコンテキストを取得するためのラッパーを作成しようとしていますが、それが "null
"ポインタを返す可能性があります。
私の理解によれば、私は2つのContext.getApplicationContext()
またはActivity.getApplication()
のいずれかを呼び出すためのより良いアプローチを推測します。
それは良いやり方です。私も自分で使います。コンストラクタを使用する代わりにonCreate
をオーバーライドしてシングルトンを設定することをお勧めします。
そしてSQLiteOpenHelper
について述べたのでonCreate ()
ではデータベースも開くことができます。
個人的には、私はドキュメンテーションが次のように言って間違っていると思います通常Applicationをサブクラス化する必要はありません。私はその反対が本当だと思います:あなたは常にApplicationをサブクラス化すべきです。
コンストラクタでシステムサービスを取得するには、アプリケーションコンテキストを使用します。これはテストからテストを楽にし、構成からの恩恵を受けます
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()
を使っています。
コンテキストを静的に定義するとメモリリークが発生します
どこにでもコンテキストを取得するための標準的な方法:
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();
他の方法ではパフォーマンスが低下し、メモリリークが発生します。
役立つことを願っています...