5

次のクラスを作成しました。

public class AsyncHttpsClientHelper {

public static final int REMOVE_CREDIT_CARD = 1;
public static final int ENABLE_AUTORENEW = 2;
// +10 final ints...

private static AsyncHttpsClientHelper instance = null;
private static Activity activity;
// Some other variables

    private AsyncHttpsClientHelper(Context context) {
        // Initiate variables
    }

    public static AsyncHttpsClientHelper getInstance(Context context) {
        // Guarantees the same instance for this class (Singleton)
    }

    public void performNetworkTask(int networkTaskType, String value)
    {
        switch (networkTaskType)
        {
            case REMOVE_CREDIT_CARD:
            {
                CupsLog.d(TAG, "path: " + Consts.ACCOUNT_REMOVE_CREDIT_CARD_PATH);
                client.post(Consts.ACCOUNT_REMOVE_CREDIT_CARD_PATH , new JsonHttpResponseHandler() {

                 @Override
                 public void onSuccess(JSONObject result) {
                try {
                    CupsLog.d(TAG, Consts.ACCOUNT_REMOVE_CREDIT_CARD_PATH + " -> onSuccess, result: " + result.toString(3));
                    AccountService.getInstance(activity).pullAccountDetailsFromServer();
                    Toast.makeText(activity, "Your credit card was removed", Toast.LENGTH_SHORT).show();
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }

                 @Override
                 public void onFailure(Throwable arg0) {
                    CupsLog.d(TAG, "commitPaymentToServer -> onFailure");
                     BusProvider.getInstance().post(new DialogChangeEvent(DialogChangeEvent.REMOVE_CREDIT_CARD, "failed"));
                }
        });
        break;
            }
            case ENABLE_AUTORENEW:
            {
                // Do ENABLE_AUTORENEW logic
            }
            // +10 cases goes here...
        }
    }
}

このクラスはまだ完成していないので、アプリケーション全体で実行する他の 10 個のネットワーク呼び出しをここに追加する必要があります。

ネットワーク タスクの 1 つを実行するには、たとえば次の行を実行します。

AsyncHttpsClientHelper.getInstance(this).performNetworkTask(AsyncHttpsClientHelper.COMMIT_COUPON_TO_SERVER, event.getValue());

タスクが終了したら、イベントツールをEvent使用してを起動し、必要な視覚的変更をアクティビティ/フラグメント レイアウトにコミットします。SquareBus

質問:私の上司は、これは悪い習慣であり、私がそれを終えるとこのクラスは混乱するだろうと主張しています。さらに彼は、このクラスはばかげたクラスであるべきだと主張しています。彼が知っているのは、AsyncHttpClientオブジェクトを構成して返すことだけであり、それを使用して関連する 内で https タスクを実行できますActivity。基本的に彼は、https 呼び出し自体を Activity クラスに配置する必要があると述べています。私はこの方法の方が好きで、私の活動がよりクリーンで読みやすくなると思います。一方、彼は、この方法ではデバッグが難しく、このクラスはコントローラーとビューの機能の一部を組み合わせてはならないと言います。

では、誰が正しいのでしょうか? このようなクラスを作成するのは本当に悪い習慣ですか?

4

8 に答える 8

4

Android REST クライアント アプリに関する Google IO 2010 のこのプレゼンテーションを見てください。あなたの質問に対する完全な答えだと思います。

https://www.youtube.com/watch?v=xHXn3Kg2IQE

乾杯 :)

于 2014-05-22T14:06:54.820 に答える
3

アクティビティへの静的参照を保持します-これは悪い習慣です! 長時間のネットワーク操作中に電話が回転した場合はどうなりますか。

Google I/O プレゼンテーションで説明されている最も堅牢でクリーンなソリューション。

あなたのソリューションにはいくつかの欠点があります。

  • シングルトンはスレッドセーフではありません
  • アクティビティ コンテキストを使用します。簡単にメモリ リークが発生したり、デッド アクティビティ UI を呼び出したりできます。
  • UI とネットワーク呼び出しは密接にリンクされています
  • 1 つのアクティビティのみをサポートします

あなたの質問によると-はい、AsyncHttpClientを適切に呼び出すと、提案するコードがよりクリーンになります。

于 2014-05-25T14:49:48.290 に答える
0

私はあなたの上司が言ったことについて完全に同意します、それはばかげたクラスであるべきです。Helper クラスの代わりに、 ExecutorまたはWorkerのようなクラスが必要になる可能性が高くなります。結局のところ、シングルトンはほとんどの場合悪であり、最終的にはコンテキストをリークし、メモリリークを引き起こします。

より良い方法があり、自己保持を使用しFragmentsます。

これを考慮して、ヘルパークラスをFragmentシステムの接続ホルダーであり、その接続を介していくつかのタスクを実行できる自己保持クラスに変更します。また、それを失いswitch...case、タスクを何らかのクラスRunnableまたはCallableクラスのように変えます。

これで、クラスのような Fragment ベースのエグゼキュータと、実行できる一連のタスクができました。このアプローチにより、次の利点が得られます。

  • フラグメントは自己保持されるため、シングルトンのように動作します。
  • このフラグメントはアクティビティ間で使用できますが、これはシングルトンを使用する場合にはできません。
  • フラグメント自体は Android コンポーネントであるため、Android は必要なときにいつでもコンテキストを提供するため、コンテキストやメモリのリークを心配する必要はありません。
  • タスクの一部が実行されているときに現在のコンテキスト (ユーザーがホームボタンを使用したとしましょう) を失ったとしても、別のコンテキストが利用可能になるまで単純に待つことができます (一部のアクティビティにフラグメントが再接続されます)。

ちなみに、ServiceFragments の代わりに a を使用することもできます。同じ原則ですが、Service-Activity 通信によって別の複雑なレイヤーが追加されるため、実装が少し難しくなる可能性があります。

于 2014-05-28T00:55:41.577 に答える
0

次の質問に答えてください。

  1. クラスの各メソッドでいくつかのロジックを繰り返す必要がありますか? はいの場合 - コードの重複を防ぐために、おそらくより多くのクラスに分割する必要があります。
  2. クラスには、顧客向けの出力 (ビュー)、内部ビジネス ロジック (コントローラー)、およびデータ アクセス/永続ロジック (モデル) の両方がありますか? これらの両方が必要な場合は、おそらく順番に分割することをお勧めします。プレゼンテーションをビジネス ロジックおよびデータ アクセス (MVC) から分離します。
  3. あなたのクラスには、他のユースケース/統合などで役立つ可能性があるロジックが含まれていますか? はいの場合は、このロジックを別のクラスにすることをお勧めします (実際のクラスのプロパティとして継承または含める)。
于 2014-06-01T12:58:38.227 に答える
0

ネットワーク関連のタスクには、次のアプローチを試してください。

1.HttpHelper http オブジェクトを初期化し、http リクエストを実行するためのヘルパー メソッドを記述するクラスを作成します。

2.すべての http リクエストに対して個別に作成しAsyncTask、このクラスから HttpHelper を初期化してネットワーク操作を実行すると、次の 2 つのメリットがあります。

a)コードが読みやすく、モジュール化されているため、保守とデバッグが容易になります。

b)ネットワーク要求は独立しているため、アプリケーション内のどこでもこのクラスを自由に利用できます。

3. AsyncTask Interfaceから戻って通信する場合、Handlerを使用するか、アクティビティ オブジェクトを直接渡すことができますが、この方法ではコンテキストがリークされ、メモリ リークが発生する可能性があります。

于 2014-05-31T06:18:45.353 に答える
0

コードをより読みやすく、保守しやすくすることは常に良い習慣です。責任をカプセル化することは、両方を行う最良の方法の 1 つです。

上司への適切な議論は次のとおりです。ビューとサーバー間の接続はビューで開始し、サーバーで終了しますが、それを完了する(そして責任を負う)のはこのクラスです。Activityサーバーまたはサーバーにとって、それがどのように行われたかは問題ではなく、結果のみが重要です。


私が提案するあなたが共有したコードに基づくいくつかの変更:

  • コンストラクターを削除し、getInstance()
  • メソッドを作成しinitiator()て開始するAsyncHttpClientGsonおよびその他のパラメーター
  • ヘルパーを拡張し、独自の特定のクラスを実装する他のクラスを作成しますperformNetworkTask()(特定のメソッド名も持つことができ、また持つべきです)。
  • performNetworkTask()静的に使用する
  • コールバックの処理を開始します (ビューがこれを担当します)。

次のようになります。

public class HttpsClientAsyncHelper {
   Acitivity activity;
   AsyncHttpClient client;
   Gson gson;

   // Other params

   public static void initiator(Context context)
   {
       activity = (Activity) context;
       client = new AsyncHttpClient().setCookieStore(CookieUtil.getInstance(activity)
                                .getPersistentCookieStore());
       gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
                               .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
                               .create();
   }

   // Other methods
}

そして、次のようなクラスをさらに 10 個作成します。

public class RemoveCreditCardAsyncTask extends HttpsClientAsyncHelper {

   public static void performNetworkTask(Context context)
   {
       initiator();
       // Do what you did in this specific case
   }
}

使用法:

 RemoveCreditCardAsyncTask.performNetworkTask(this);
 // specific method names
 AutoRenewAsyncTask.enableAutoRenew(this);
 AutoRenewAsyncTask.disableAutoRenew(this);
 // even more specific
 AutoRenewAsyncTask.enable(this);
 AutoRenewAsyncTask.disable(this);

Network私は、 my とのすべての通信を処理する、さらに一般的なクラスでこれを自分で実践しWebServiceます。

serverPostRequest(String controller, String action, JSONObject jsonParameters) throws Exception {}

fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {} 

おまけ:あなたにとっておそらく便利な方法:

public static boolean isAvailable(Context context)
{
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();

    return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
于 2014-05-25T23:37:40.137 に答える