2012-01-07 2 views
1

私はScala/Play(サーバー側)を学び、Android(クライアント)ゲーム開発を覚えて、開発を盛り上げることに決めました。
私はAndroidでHTTPリクエストのための素敵なデザインをする方法に関する質問があります。
私が最もよく理解しているところは、抽象的なクラスAsyncTaskを拡張してHTTPリクエストを委譲することです。
オーバーライドするdoInBackgroundメソッドで異なるロジックごとにAsyncTaskの新しい拡張を行う必要がありますか?
私にとっては、それぞれのリクエストロジックにクラスを持たせるのは自然ではありませんが、むしろ1つのクラスにいくつかの一貫したメソッドをカプセル化しています。Android AsyncTaskクラスをモデリングする方法は?

私はちょっと遊び始めましたが、私はデザインに満足していません。私は、doInBackground(Object... params)のvarargsオブジェクトのデザインが嫌いです。
このデザインでは、型の安全性が失われ、paramsオブジェクトは直感的で直感的ではありません。私のコードでは何かを追求しています。

ここでは改善したいコードを示します。

public class GameActivity extends Activity { 

    private class MyCellListener implements ICellListener { 
     public void onCellSelected() { 
      ServerProxy.postSelectedCell(row, col, player.getUser());  
      ... 
      // ServerProxy.other(); 

public class ServerProxy extends AsyncTask<Object, Void, Void>{ 

    private static final String TAG = ServerProxy.class.getSimpleName(); 
    private static final String SERVER_ADDRESS = "http://127.0.0.1"; 

    // Prevent external instantiation 
    private ServerProxy(){}; 

    public static void postSelectedCell(int row, int cell, User user){ 
     List<NameValuePair> postParameters = new ArrayList<NameValuePair>(3); 
     postParameters.add(new BasicNameValuePair("row", String.valueOf(row))); 
     postParameters.add(new BasicNameValuePair("cell", String.valueOf(cell))); 
     postParameters.add(new BasicNameValuePair("userName", user.getUserName())); 
     new ServerProxy().doInBackground("setSelectedCell" , postParameters); 
    } 

// public static void postOther() { 
//  new ServerProxy().doInBackground("other" , //some parameters); 
// } 

    /** 
    * @param postParameters First object URL postfix<br/> 
    * Second parameter is post parameters inform of {@code List<NameValuePair>} 
    * @return null 
    */ 
    @SuppressWarnings("unchecked") 
    @Override 
    protected Void doInBackground(Object... params) { 

     HttpClient httpclient = new DefaultHttpClient(); 
     HttpPost httppost = new HttpPost(SERVER_ADDRESS +"/" + params[0]); 
     httppost.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false); 

     try { 
      httppost.setEntity(new UrlEncodedFormEntity((List<NameValuePair>) params[1])); 
      httpclient.execute(httppost); 
     } catch (ClientProtocolException e) { 
     Log.e(TAG,e.toString()); 
     } catch (IOException e) { 
     Log.e(TAG,e.toString()); 
     } 
     return null; 
    } 
} 

答えて

5

にちょうど最初の試みです。 1つのAsyncTaskサブクラスでpostLastName、postFirstName、postWhateverなどのメソッドを定義して、そのメソッド呼び出しをUIスレッドから実行することはできません。 AsyncTaskは、スレッドを直接処理することなく、UIを更新する必要があるバックグラウンドジョブを簡単に実行できるようにするためのものです。

HttpClientを使用しているサーバーと通信するには、サーバーの応答が返るまでHttpClient.execute()コールがブロックされます。これは、特にサーバーがビジー状態であるか、死んでいるか、セル無線がダウンしている場合、時間がかかる可能性があります。その呼び出しに時間がかかりすぎると、ユーザーのUIがユーザーに応答しなくなることはありません。あなたは何かが起こっていることをユーザーに知らせるためにスピナーを回転させたいと思っています。あなたが提供したコードを使用した場合、あなたはUIスレッド上で呼び出しているので、HttpClient.execute()呼び出しが返されるまで、あなたのUIはペイントしなければなりません。

この問題の回避策は、この呼び出しをUIスレッドから別のスレッドに移動することです。そのスレッドが応答を待ってから、完了したUIスレッドに通知し、UIスレッドを使用して新しいデータでUIを更新します。そのバックグラウンドスレッドでUIを更新させることができないのはなぜですか? UIのスレッドだけがUIを更新できるというAndroidのスレッドルールに違反するためです。

AsyncTaskを使用すると、UIスレッド(doInBackground())をオフにして、戻り値をUIスレッド(onPostExecute())にポストすることができるため、Androidのルールに違反することなくUIを安全に更新できます。 AsyncTask.execute()を呼び出す代わりにdoInBackground()またはonPostExecute()を直接呼び出さず、AsyncTaskのコードはバックグラウンドのThreadでdoInBackground()を呼び出し、終了するとUIスレッドでonPostExecute 。そうすれば、自分自身のスレッドをすべて実行することで絡み合うことはありません。

複数のリクエストを1つのサブクラスで実行するという考えは、AsyncTaskはサービスコールの2つの部分、すなわち応答を得るためのサービスコールの実行の詳細、およびその応答を使用してUIを更新します。 postFirstName()メソッドが呼び出された場合は、postLastName()を呼び出した場合のレスポンスが返された後の処理と異なる可能性があります。そしてそれが異なるということは、これらの異なる呼び出しに対して、ただ一つのAsyncTaskを定義するだけでは意味がないということです。基本クラスのコンポジションまたはサブクラス化を使用してコードを共有できますが、サーバーで実行するユニークな操作ごとにサブクラスを作成する必要があります。だから、各呼び出しごとにメソッドの代わりにクラスを考えてみましょう。

doInBackground()に渡されたパラメータを使用する必要はありません。 AsyncTaskに渡すパラメータの型が複数ある場合。それらをコンストラクタに渡します。 AsyncTaskインスタンスを再利用することはできません(つまり、AsyncTask.execute()をインスタンスごとに複数回呼び出すことはできません)。彼らのライフサイクルはインスタンス化、実行()、およびトスをしなければならない(MUST)。つまり、コンストラクタで入力を渡しても、AsyncTaskを使用する能力が損なわれることはありません。

私は、3つのコールバックメソッドを分離した独自のバージョンのAsyncTaskを作成しました:doInBackground()から返された結果を処理するためのsuccess(); doInBackground()から例外がスローされたときに呼び出されるhandleException()。 doInBackground()に関係なく呼び出されるdoFinally()は何かを返すか、例外をスローします。 AsyncTaskのデフォルトでは、onPostExecute()はエラーまたは成功に関係なく呼び出されます。多くの場合、私はUIへの参照を渡すことが必要とされていない匿名の内部クラスとしてこれをやるが、やはりあなたはアノンクラスをしない場合は、あなただけ渡すことができ

public class MyTask extends EnhancedAsyncTask<Param,Integer,MyResult> { 
    MyParam1 param1; 
    MyParam2 param2; 

    public MyTask(MyParam1 param1, MyParam2 param2) { 
     this.param1 = param; 
     this.param2 = param2; 
    } 

    protected MyResult doInBackground(Param... params) { 
     // do server work here 
     server.send(param1, param2); 
    } 

    protected void success(MyResult result) { 
     // do Update of the UI 
    } 

    protected void handleException(Exception ex) { 
     // show an error here 
    } 
} 

// Now to use this AsyncTask you would do something like this: 

MyTask task = new MyTask(param1, param2).execute(); 

:それはこのようになりますコンストラクタへのそれら。アクティビティが破棄された場合(ユーザーが画面を反転させた場合など)には、UIに触れないように注意するだけです。

+0

私はあなたの答えを感謝しますが、あなたは私のコード/質問を誤解していると思います。 2回の往復をすると2つのインスタンスが必要だと書いています。私はすべての私のパブリックメソッド呼び出しが新しいServerProxy()で新しいインスタンスをインスタンス化するので、それを持っています。あなたのコードがうまくいくように私が間違っていれば私を修正してください。しかし、私の問題を全く解決していないのですか?問題は1つのクラスで多くの異なる種類の要求を持つことでした。たとえば、単一のServerクラス、何らかの方法でAsyncTaskを拡張し、多くのメソッドpostFirstName、postLastName、getAllFriendsなどをすべて一意のパラメータで保持します。 – Farmor

+0

AyncTaskの目的を理解していないと思うので、AyncTaskが実際に行うことをよりよく説明するために私の答えを更新しました。 – chubbsondubs

0

デザインに先立って、間違っているように見えるものがあります。

  • あなたがここに

    を行っているとして、あなたはdoInBackground( "setSelectedCell"、postParameters))新しいServerProxyは(直接doInBackgroundを呼び出すべきではありません。

    代わりに、それは設計のために、任意のversion of execute

を呼ぶべきである、あなたはあなたがServerProxyクラスを作成し、AsyncTaskから、それを拡張していけないことができ、この

  • を試すことができます。あなたのロジックをカプセル化するために使用してください。
  • これで、を構成成分とするServerProxyAsyncを作成できます。
  • は今、あなたが行うことができます一つの選択肢は

    パブリッククラスServerProxyはあなたがServerProxyインスタンス上で呼び出したいメソッド名を指定することができAsyncTask

    ここ

    Stringを拡張し、そのためにリフレクションを使用することができます。

注:このPROBに他のSOLNがあるかもしれません、これは私はあなたがAsyncTaskが何をするか理解していないと思う問題

関連する問題