web-dev-qa-db-ja.com

Androidアクティビティに参加していないコンテキスト?およびその他のアクティビティのないプログラミング?

私はこれを1つの包括的な質問に変えるために本当に一生懸命努力します:

LocationManagergetLastKnownLocation()などで決定されるAndroidデバイスの都市の名前を含む文字列を取得するメソッドを作成しています。

次に、別のアクティビティで同じことをもう一度行う必要があることに気付きました。そこで、どこにでも重複するコードを書くのではなく、プログラム全体で使用できる完全に別個のクラス(LocationFinder)を作成してみませんか?

しかし、私は私を混乱させる問題に遭遇しました。たとえば、このクラス(LocationFinder)を作成した場合、実際には視覚化されていなくても、Activityを拡張する必要がありますか?このクラスが行うのは、getLastKnownCity()getCurrentCity()などのさまざまなゲッターと文字列を返すことだけです。実際にはアクティビティではないため、Activityクラスを拡張する必要はないと思いました。

しかし、私はどのコンテキストを使用しますか:

_Geocoder geocoder = new Geocoder(Context context, Locale locale)
_

これは私にそれが活動でなければならないと思いました。そこで、Activityを拡張し、コンストラクターを次のように置き換えました

_@Override
protected void onCreate(..............
_

でもどういうわけか、入れても呼ばれることはない

_String city = new LocationFinder().getLastKnownCity();
_

LocationFinderonCreate()の最初の行は

_System.out.println("HEY!")
_

そしてそれは決してそれに到達しません。 Android.internal.os.LoggingPrintStream.println()などでnullポインタを取得します。

さらに、Activityクラスから取得されるシステム定数がたくさんあります。たとえば、_LOCATION_SERVICE_に到達する必要があります。これは文字列であり、Activityを拡張しないと取得できません。確かに、私はごまかして文字列を入れることができましたが、それは間違っていると感じています。

15
bob

クラスを構築するときに、Contextを取り込んで、クラス内のローカルContextオブジェクトに割り当てるコンストラクターを作成できます。

public class LocationFinder {
     private Context myContext;
     private Geocoder geocoder;

     public LocationFinder(Context context)
     {
         myContext = context;
         geocoder = new Geocoder(myContext);
     }

}

そして、このクラスにアクセスしようとするときは、次のように初期化してください。

public class TestActivity extends Activity {
     protected void onCreate(Bundle savedInstanceState)
     {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.main);
          LocationFinder lFinder = new LocationFinder(getApplication());
     }
}

もちろん、実行するすべてのクラスからコンテキストにアクセスできるわけではありません。したがって、ビューへの参照で十分です。

LocationFinder lFinder = new LocationFinder(anyView.getApplication());
13
frogmanx

編集:可能であれば、frogmanxの答えを使用してください。これは、彼の答えが使用できない場合にのみ使用する必要があります。 (つまり、すぐにコンテキストを必要とするシングルトン。)

アクティビティではなく アプリケーション を拡張する必要があるようです。

アプリケーションを次のようにします。

_public class MyApplication extends Application {
    private static MyApplication instance;

    public MyApplication() {
        instance = this;
    }

    public static MyApplication getInstance() {
         return instance;
    }
_

次に、この属性をマニフェストのアプリケーションタグに追加します。

_ <application Android:name=".your.package.MyApplication" ... />
_

その後、どこからでもMyApplication.getInstance()を呼び出すことで、コンテキストを取得できます。

21
Alex Gittemeier
_should it extend Activity, even though it is never actually visualized?
_

いいえ。Android docs から

アクティビティは、ユーザーが実行できる単一の焦点を絞ったものです。ほとんどすべてのアクティビティはユーザーと対話するため、Activityクラスは、setContentView(View)を使用してUIを配置できるウィンドウの作成を処理します。

アクティビティは、ユーザーに表示される画面と考えてください。

しかし、Geocoder geocoder = new Geocoder(Context context、Locale locale)にどのコンテキストを使用しますか

ActivityクラスはContextを拡張し、Applicationを含む他の多くのクラスも同様です。 コンテキストは、コンテキストを拡張するクラスに関連付けられたリソースへのアクセスを提供します。

アクティビティコンテキストは、そのアクティビティに関連付けられたリソースおよび具象アクティビティクラスによって実装されたメソッドと対話するために必要な場合にのみ必要であり、使用する必要があります。そのコンテキストへのアクセスが必要な場合は、アクセスが必要なクラスに、通常はそのクラスのコンストラクターへの引数として渡します。

拡張するアクティビティの外部でアクティビティコンテキストを渡す場合は、参照のスコープとライフサイクルが拡張アクティビティ以下であることを確認してください。そうしないと、ガベージ以降にアクティビティが破棄された場合に大量のメモリがリークします。コンテキストへの参照があるため、コレクターはメモリを解放できません。

Geocoderのコンストラクターを見ると、ご存知のように、引数としてContextを使用していることがわかります。説明にコンテキストが必要な理由についての手がかりがあります。

_     Geocoder(Context context, Locale locale)
Constructs a Geocoder whose responses will be localized for the given Locale.  [1]: 
_

コンテキストが必要な理由は、プラットフォームロケールと現在のシステムロケールに関するシステム情報にアクセスするためです。

したがって、この例では、Applicationコンテキストをコンストラクターに渡すだけで、getApplicationContext()を使用して参照を取得できます。

たとえば、文字列であるLOCATION_SERVICEにアクセスする必要があります。これは、Activityを拡張しないと取得できません。

アプリケーションコンテキストから取得できます。

5
Simon