現在アプリでVolleyを使用していて、それ関連はextends Applicationしたクラスにまとめてあります。
この度Google Analyicsを導入することになり公式を参考に取り組んでいるのですが、それ用のTrackerの取得をVolley同様extends Applicationしたクラスに書くよう書かれています。
Volley関連はシングルトンがよく、Analytics関連はContextが使えるシングルトンがよいからどちらもextends Applicationしたクラスに定義することを望んているのだと思いますが、そのクラスは2つも作れないと思います。

実際に私が定義しているVolley関連のクラスにはContextを使用しているコードはなさそうだったので、サンプルによくあるコードのようにextends Applicationしたクラスにしなくても普通のシングルトンでよかったかもしれませんが、今更の変更はテスターの負担増になるので避けたいと思っています。
ですが、Volley関連とAnalytics関連を同一ではなく別クラスで管理したいと考えています。

そこでAnalytics関連のクラスの設計について以下の3パターンを考えたのですが、どれが良いでしょうか?
もしくは他の設計の方が良いでしょうか?

  1. 普通のシングルトンで定義してTrackerを取得するメソッドの引数にContextを渡す
    公式のサンプルのような同一のトラッカーを使い回すことを考えると、2回目以降は無駄にContextを渡していることになる。
  2. Volley関連のクラスのみでインスタンスを生成するようにした擬似シングルトンで定義する
    生成時にContextを渡してTrackerを作るので無駄にContextを渡すなんてことはないが、設計としていまいちでは。
  3. Volley関連のクラスをextendsしたクラスを定義する
    そうすればextends Applicationと同義にはなるとは思うが、このような設計はやってはいけない気がする。



追記

現在のApplicationクラスの実装は次のようになっています。
(package宣言は消しています。)


import android.app.Application;
import android.graphics.Bitmap;
import android.util.LruCache;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;

import de.greenrobot.event.EventBus;

/**
 * キューでリクエストを管理するためのクラス.
* * Applicationを拡張して作ったシングルトンクラス。 * * @see android.app.Application Application */ public class AppController extends Application { public static final String TAG = AppController.class.getSimpleName(); private RequestQueue mRequestQueue; private ImageLoader mImageLoader; private static AppController sInstance; /** * AndroidManifest.xmlのandroid:name項目によりインスタンスが作成されて呼び出される. */ @Override public void onCreate() { super.onCreate(); sInstance = this; } /** * シングルトロンクラスのためのインスタンス取得用メソッド. * * @return このクラスのインスタンス */ public static synchronized AppController getInstance() { return sInstance; } /** * リクエストキューを取得するためのメソッド. * * @return リクエストキュー */ private RequestQueue getRequestQueue() { if (mRequestQueue == null) { mRequestQueue = Volley.newRequestQueue(getApplicationContext()); } return mRequestQueue; } /** * イメージローダーを取得するためのメソッド. * * @return イメージローダー */ public ImageLoader getImageLoader() { if (mRequestQueue == null) { mRequestQueue = Volley.newRequestQueue(getApplicationContext()); } if (mImageLoader == null) { mImageLoader = new ImageLoader(mRequestQueue, new ImageLruCache()); } return mImageLoader; } /** * 画像をキャッシュするためのクラス. */ public static class ImageLruCache implements ImageLoader.ImageCache { private LruCache mMemoryCache; public ImageLruCache() { int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); int cacheSize = maxMemory / 8; mMemoryCache = new LruCache(cacheSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { return bitmap.getByteCount() / 1024; } }; } @Override public Bitmap getBitmap(String url) { return mMemoryCache.get(url); } @Override public void putBitmap(String url, Bitmap bitmap) { mMemoryCache.put(url, bitmap); } } /** * リクエストをキューに追加するためのメソッド. * * @param req 行う処理を定義したリクエスト * @param */ public void addToRequestQueue(Request req) { req.setTag(TAG); getRequestQueue().add(req); } /** * 保留中のリクエストをキャンセルするためのメソッド. * * @param tag キャンセルしたい保留中のリクエストのタグ */ public void cancelPendingRequests(Object tag) { if (mRequestQueue != null) { mRequestQueue.cancelAll(tag); } } /** * Volleyのエラー時に呼び出すメソッド. * * @param error Volleyのエラー内容 */ public void onErrorResponse(VolleyError error) { if (error.networkResponse == null) { EventBus.getDefault().post(new UserEvent(UserEvent.Id.CONNECTION_ERROR, "")); } else { EventBus.getDefault().post(new UserEvent(UserEvent.Id.CONNECTION_ERROR, String.valueOf(error.networkResponse.statusCode))); } } }