私がこの答えを書いたのは、Androidが比較的新しい'09年であり、Android開発には確立されていない領域が数多くありました。この投稿の最後に長い付録を追加し、いくつかの批判に対処し、アプリケーションをサブクラス化するのではなく、シングルトンを使用する場合の哲学的な不一致を詳しく説明しました。自己責任でお読みください。
元の回答:
発生しているより一般的な問題は、いくつかのアクティビティとアプリケーションのすべての部分で状態を保存する方法です。静的変数(たとえば、シングルトン)は、これを実現する一般的なJavaの方法です。ただし、Androidでよりエレガントな方法は、状態をアプリケーションコンテキストに関連付けることです。
ご存じのとおり、各アクティビティはコンテキストでもあります。コンテキストは、広い意味での実行環境に関する情報です。アプリケーションにはコンテキストもあり、Androidはアプリケーション全体で単一のインスタンスとして存在することを保証します。
これを行う方法は、android.app.Applicationの独自のサブクラスを作成し、マニフェストのアプリケーションタグでそのクラスを指定することです。これで、Androidは自動的にそのクラスのインスタンスを作成し、アプリケーション全体で利用できるようにします。メソッドcontext
を使用して、どこからでもアクセスできますContext.getApplicationContext()
(まったく同じ効果を持つActivity
メソッドも提供されますgetApplication()
)。以下は、非常に簡略化された例ですが、注意事項があります。
class MyApp extends Application {
private String myState;
public String getState(){
return myState;
}
public void setState(String s){
myState = s;
}
}
class Blah extends Activity {
@Override
public void onCreate(Bundle b){
...
MyApp appState = ((MyApp)getApplicationContext());
String state = appState.getState();
...
}
}
これは基本的に静的変数またはシングルトンを使用するのと同じ効果がありますが、既存のAndroidフレームワークに非常によく統合されます。これはプロセス間で機能しないことに注意してください(アプリが複数のプロセスを持つまれなものの1つである必要があります)。
上記の例から注意すべき点があります。代わりに次のようなことをしたとしましょう:
class MyApp extends Application {
private String myState = /* complicated and slow initialization */;
public String getState(){
return myState;
}
}
この遅い初期化(ディスクのヒット、ネットワークのヒット、ブロッキングなど)は、アプリケーションがインスタンス化されるたびに実行されます。あなたは、まあ、これはプロセスのために一度だけです、そして私はとにかく費用を支払わなければならないでしょう、そうですか?たとえば、ダイアンハックボーンが以下で言及しているように、バックグラウンドブロードキャストイベントを処理するためだけに、プロセスをインスタンス化することは完全に可能です。ブロードキャスト処理でこの状態が必要ない場合は、一連の複雑で低速な操作を何もせずに実行した可能性があります。遅延インスタンス化は、ここでのゲームの名前です。以下は、アプリケーションの使用法が少し複雑な方法で、最も単純な使用法以外の場合に適しています。
class MyApp extends Application {
private MyStateManager myStateManager = new MyStateManager();
public MyStateManager getStateManager(){
return myStateManager ;
}
}
class MyStateManager {
MyStateManager() {
/* this should be fast */
}
String getState() {
/* if necessary, perform blocking calls here */
/* make sure to deal with any multithreading/synchronicity issues */
...
return state;
}
}
class Blah extends Activity {
@Override
public void onCreate(Bundle b){
...
MyStateManager stateManager = ((MyApp)getApplicationContext()).getStateManager();
String state = stateManager.getState();
...
}
}
ここでは、より洗練されたソリューションとしてシングルトンを使用するよりもアプリケーションサブクラス化を好みますが、アプリケーションサブクラスに状態を関連付けることのパフォーマンスとマルチスレッド化の影響をまったく考えないよりも、開発者が本当に必要な場合はシングルトンを使用したいと思います。
注1:また、アンチカフェがコメントしたように、アプリケーションのオーバーライドをアプリケーションに正しく関連付けるためには、マニフェストファイルにタグが必要です。繰り返しますが、詳細についてはAndroidのドキュメントをご覧ください。例:
<application
android:name="my.application.MyApp"
android:icon="..."
android:label="...">
</application>
注2: user608578は、ネイティブオブジェクトのライフサイクルの管理でこれがどのように機能するかを以下で尋ねます。私は、Androidでネイティブコードを少しでも使用することにスピードが足りず、それが私のソリューションとどのように相互作用するかについて答える資格がありません。誰かがこれに対する答えを持っている場合、私はそれらを信用し、最大限の可視性のためにこの投稿に情報を入れていく所存です。
補遺:
一部の人々が指摘したように、これは永続的な状態の解決策ではありません。おそらく元の答えでもっと強調すべきだったでしょう。つまり、これは、アプリケーションのライフタイム全体で保持されることを意図したユーザーまたはその他の情報を保存するためのソリューションではありません。したがって、ディスクに永続化する必要があるものはすべてアプリケーションサブクラスを介して保存してはならないため、アプリケーションがいつでも強制終了されることなどについて、以下のほとんどの批判を検討します。これは、一時的で簡単に再作成できるアプリケーションの状態(ユーザーがログインしているかどうかなど)と、単一のインスタンス(アプリケーションネットワークマネージャーなど)であるコンポーネント(シングルトンではない!)を保存するためのソリューションです。
Dayermanは、Reto MeierとDianne Hackbornとの興味深い会話を指摘するのに十分親切でした。そこでは、アプリケーションのサブクラスの使用はシングルトンパターンを支持するために推奨されていません。ソマティックはまた、このようなことを以前に指摘しましたが、私は当時はそれを見ていませんでした。Androidプラットフォームの保守におけるRetoとDianneの役割のため、私は誠意をもって彼らのアドバイスを無視することを勧めることはできません。彼らが言うことは、行きます。アプリケーションのサブクラスよりもシングルトンを優先することに関して表明された意見には同意しません。私の意見の相違では、このStackExchangeのシングルトン設計パターンの説明で最もよく説明されている概念を利用します。、この回答で用語を定義する必要がないようにします。続行する前にリンクをざっと読むことを強くお勧めします。ポイントごと:
ダイアンは、「アプリケーションからサブクラス化する理由はありません。シングルトンを作成することと同じです...」この最初の主張は正しくありません。これには主に2つの理由があります。1)Applicationクラスは、アプリケーション開発者により良いライフタイム保証を提供します。アプリケーションの寿命があることが保証されています。シングルトンは、アプリケーションの存続期間に明示的に結び付けられているわけではありません(実際にはそうですが)。これはあなたの平均的なアプリケーション開発者にとっては問題ではないかもしれませんが、これはまさにAndroid APIが提供すべき契約のタイプであり、関連するライフタイムを最小化することにより、Androidシステムにより多くの柔軟性を提供すると私は主張しますデータ。2)Applicationクラスは、アプリケーション開発者に状態の単一インスタンスホルダーを提供します。これは、状態のシングルトンホルダーとは大きく異なります。違いのリストについては、上記のシングルトンの説明リンクを参照してください。
Dianne氏は続けます。「アプリケーションオブジェクトが、独立したアプリケーションロジックであるべきもののこの大きな絡み合った混乱になっていることがわかると、将来、後悔することになるでしょう。」これは間違いなく間違いではありませんが、アプリケーションサブクラスではなくシングルトンを選択する理由にはなりません。ダイアンの主張はどれも、シングルトンを使用することがアプリケーションサブクラスよりも優れているという理由を提供していません。彼女が確立しようとしているのは、シングルトンを使用することはアプリケーションサブクラスよりも悪くないということです。
彼女は続けます、「そしてこれはあなたがこれらのものを管理する方法にもっと自然につながります-オンデマンドでそれらを初期化します。」これは、Applicationサブクラスを使用してオンデマンドで初期化できない理由がないことを無視しています。再び違いはありません。
Dianneは「フレームワーク自体が、ロードされたリソースのキャッシュやオブジェクトのプールなど、アプリ用に維持しているすべての小さな共有データ用の膨大な量のシングルトンを備えています。シングルトンを使用してもうまくいかない、または正当な代替手段ではないことについては、私は主張していません。シングルトンは、アプリケーションサブクラスを使用するよりもAndroidシステムとの強い契約を提供しておらず、シングルトンを使用すると、一般に柔軟性のない設計を指し示すため、簡単に変更できず、将来多くの問題が発生すると私は主張しています。私見、Android APIが開発者アプリケーションに提供する強力な契約は、Androidでのプログラミングの最も魅力的で楽しい側面の1つであり、Androidプラットフォームを今日の成功へと導いた開発者の早期採用につながりました。
ダイアンも以下のようにコメントしており、アプリケーションサブクラスを使用することの追加のマイナス面について言及しているため、パフォーマンスの低いコードを書くことを奨励したり、簡単にすることができます。これは非常に真実であり、ここでperfを検討することの重要性を強調するためにこの回答を編集し、アプリケーションのサブクラス化を使用している場合は正しいアプローチをとります。ダイアンが述べているように、プロセスがバックグラウンドブロードキャストでのみロードされている場合でも、プロセスがロードされるたびにアプリケーションクラスがインスタンス化されることを覚えておくことが重要です(アプリケーションが複数のプロセスで実行されている場合、一度に複数回可能です!)。イベント。したがって、Applicationクラスを、処理を行う場所としてではなく、アプリケーションの共有コンポーネントへのポインタのリポジトリとして使用することが重要です。
以前のStackExchangeリンクから盗んだ次のシングルトンの欠点のリストを残しておきます。
- 抽象クラスまたはインターフェースクラスを使用できない。
- サブクラス化できない;
- アプリケーション全体の高い結合(変更が難しい);
- テストが難しい(単体テストでは偽造/模擬できません);
- 変更可能な状態の場合は並列化が困難です(大規模なロックが必要)。
そして私自身のものを追加してください:
- Android(またはその他のほとんど)の開発には適さない、不明確で管理できない生涯契約。