0

問題は、Android フォンとサーバーと通信する方法です。これにより、Activity が残され、Activity での呼び出しが成功しなかった場合に、トランザクションがもう一度自動的に繰り返されます。ちょうど今、Android の AsyncTask を使用してサーバーと通信します。

new AsyncTask<String, Void, List<String>>() {

    @Override
    protected void onPreExecute(
       showWaitDialog();        
    }

    @Override
    protected void onPostExecute(List<String> msgList) {
       //here I put the handling after the POST ie. error and success handling
       hideWaitDialog();

       if (msgList.isEmpty() {
          //success handling --> starting an new Activity
       } else {
          errorView.setText (...);
          errorLayout.setVisibility (View.VISIBLE); 
       }
    } 

    @Override
    protected List<String> doInBackground(String... params) {
       List<String> msgs = new ArrayList<String>();
       try{
          //for example submitting an JSONObject
          JSONObject result = HttpUtils.sendHttpPost(
              AppConstants.WEB_URL, jsonObject);
          //error handling on the result
          boolean hasErrors = JsonResult.isOk(result);
          if (hasErrors) {
              // adding errors to msgs list
              String[] errorMessages = JsonResult.getErrorMessages (result,...);           
              fillList (msgs, errorMessages);
              return msgs;
          }
       } catch (CommunicationError er) {
           msgs.add (er...);
       }
       return msgs;
    }
 } 

このアプローチの問題は、データの送信が成功しない場合、同じアクティビティにとどまらなければならないことです。今まで私はユーザーにエラーメッセージを表示し、ボタンで結果をサーバーに再度送信することを担当していました。私が探しているのは、送信が行われなかった場合に後で実行されるメモリに永続的に残るアクティビティです。

アプリケーションのケースとして、これを使用して、ウェイポイントを押した場合にマップ内のウェイポイントの写真を動的にアップロードします。場合によっては、モバイル サービス プロバイダーへの接続が利用できないことがあります (山、森、アンテナから遠く離れた場所)。次に、マップ アクティビティを終了して、このウェイポイントの詳細ビューに切り替えます。成功した場合は、画像をモデル クラスに入れ、シリアル化します。ユーザーが同じウェイポイントを再度クリックしても、画像は再度読み込まれません。成功しない場合、ユーザーがウェイポイントをクリックして画像を取得するのを待ちたくありません。実際、バックグラウンド タスクが必要です。既に訪れたウェイポイントの写真を表示するための何らかのキューが必要です。通信部分が肯定的な結果を返し、画像をモデルに書き込めるようになるまで、取得されないデータが読み込まれます。次にユーザーがウェイポイントを押すと、画像が表示されます。

このようなコードの実装を行うためのベスト プラクティスはありますか? 周りに例はありますか?これを行うより良い方法はありますか?

4

2 に答える 2

0

デビッドの答えに感謝します。

提案の後にチュートリアルを読んだところです

[1] http://code.tutsplus.com/tutorials/android-fundamentals-intentservice-basics--mobile-6183

私のテストの後、私はサービスを好みました(IntentServiceではありません)

サービスを作成しました: SubmissionService

public class SubmissionIntentService extends Service {

    private List<PendingMessage> pMsgList = new CopyOnWriteArrayList<PendingMessage>();
    private Handler handler = new Handler();
    private boolean hasAppStopped = false;
    private Runnable runner;


    public SubmissionIntentService() {
      super();
      Log.d (TAG, "Service created...");
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
      PendingMessage pMessage = (PendingMessage) intent.getParcelableExtra(AppConstants.MESSAGE_OBJECT);
      synchronized (pMsgList) {
         pMsgList.add(pMessage);
      }
      if (runner == null) {
         handler.postDelayed(runner = initializeRunnable(), 500);
      }
      return Service.START_NOT_STICKY;
   }

    private void runAsLongAppIsActive (Runnable runner) {
        if (!hasAppStopped) {
           handler.postDelayed (runner, SOME_INTERVAL_CONSTANT); 
        }
    }

    private Runnable initializeRunnable() {
        Runnable result;
        result = new Runnable() {

             @Override
             public void run() {
                if (pMsgList.isEmpty()) {
                   runAsLongAppIsActive (this);
                   return; 
                }

                PendingMessage[] pMArray = null;

                synchronized(pMsgList) {
                    pMArray = pMsgList.toArray (new PendingMessage[pMsgList.size()]);
                } 
                if (pMArray==null || pMArray.length==0) {
                   runAsLongAppIsActive (this);
                   return;
                }
                Log.d (TAG, "Message List size is actually :"+pMArray.length);

                for (PendingMessage pM: pMArray) {
                     try {
                        JSONObject jsonMess = JSONSendMessage.buildOutput (pM);
                        JSONObject result = HttupUtils.sendHttpPost (WEB_URL, jsonMess);

                        boolean hasErrors = JSONResult.isOk (result);
                        if (hasErrors) {
                           //TODO: error handling in case of transmission
                           //don't remove the message from the queue
                           runAsLongAppIsActive(this); 
                           return; 
                        }
                        //remove pending transmission of the queue if success
                        synchronized (pMsgList) {
                           pMsgList.remove (pM);
                        } 
                        //inform over receiver if activity is shown
                        Intent broadcastIntent = new Intent();
                        //put data in intent
                        sendBroadcast (intent);

                        //more important
                        WayPointModel model = ModelInstance.getWayPointModel();
                        model.addToModel (pM, result);
                        model.store();

                     } catch (Exception e) {
                        continue; //try to send other messages
                     }
                }
                runAsLongAppIsActive (this);
             }

           };
        return result;
    }
}

   @Override
   public void onDestroy() {
      hasAppStopped = true;
      handler.removeCallbacks (runner);
      super.onDestroy();
   }

}

さらに、ResponseReceiver を追加しました。

public class ResponseReceiver extends BroadcastReceiver {
   public static final String ACTION_RESP = "MESSAGE_PROCESSED";

   @Override
   public void onReceive(Context context, Intent intent) {
      //work in progress...
   }
}

そして、イベントについて通知を受けたいアクティビティで:

public class SomeActivity extends Activity {    
  private ResponseReceiver receiver;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    IntentFilter filter = new IntentFilter(ResponseReceiver.ACTION_RESP);
    filter.addCategory(Intent.CATEGORY_DEFAULT);
    receiver = new ResponseReceiver();
    registerReceiver(receiver, filter);
    ...
 }

}

最後に、HTTP 経由でメッセージを送信します。

Intent msgIntent = new Intent(this, SubmissionIntentService.class);
msgIntent.putExtra(...);
startService(msgIntent);

マニフェストでサービスを宣言することを忘れないでください。

<service android:name="ch.xxx.app.service.SubmissionIntentService" />

観察: - メソッド startService(...) をさまざまなアクティビティから呼び出しました。コンストラクターは 1 回だけ呼び出されます。==> すべてのアクティビティのサービスのインスタンスが 1 つだけあります (まさに必要なもの)。

今まで得られなかったもの: - データをアクティビティに戻します。アクティビティが現在表示されていない場合はどうなりますか?

于 2014-05-30T12:15:29.947 に答える