【问题标题】:Where to put in Android code to communicate with server over http在哪里放置 Android 代码以通过 http 与服务器通信
【发布时间】:2014-05-30 08:41:45
【问题描述】:

问题是如何将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;
    }
 } 

这种方法的问题是,如果我没有成功传输数据,我必须留在同一个 Activity 中。到目前为止,我向用户显示了一条错误消息,他负责通过按钮再次将结果提交给服务器。 我正在寻找的是一些在内存中保持持久性的活动,在没有进行传输的情况下稍后运行。

作为一个应用案例,如果我按下该航点,我会使用它来动态上传地图中航点的图片。在某些情况下,与移动服务提供商的连接可能不可用(山脉、森林、远离天线)。然后我想离开地图Activity,切换到这个航点的详细视图。在成功案例中,我将图片放入我的模型类并进行序列化。如果用户再次单击同一航点,则不会再次加载图片。在不成功的情况下,我不想等待用户点击航路点来检索图像。事实上,我需要一个后台任务,某种队列,在通信部分返回肯定结果并且图像可以写入模型之前,无法检索已经访问过的航点的图片。下次用户按下 Waypoint 时,图片就会出现。

是否有任何最佳实践来实现这样的代码? 周围有例子吗? 有没有更好的方法来做到这一点?

【问题讨论】:

    标签: java android android-asynctask background-process server-communication


    【解决方案1】:

    是的,你需要为这个要求实现Intent Service

    根据开发者网站

    IntentService 类为在单个后台线程上运行操作提供了一个简单的结构。

    有关完整的详细信息和工作源代码,请访问Android Docs

    【讨论】:

      【解决方案2】:

      感谢大卫的回答。

      我刚刚在建议后阅读了

      的教程

      [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(...)。构造函数只被调用一次。 ==> 我刚刚为所有活动提供了服务实例(正是我需要的)。

      直到现在我还没有得到: - 将数据放回活动。如果 Activity 目前没有显示怎么办?

      【讨论】:

      • 保留数据是一些变量,并且当您的活动恢复时,即在您的 Activity 的 onResume 方法中。将该数据设置为视图。
      猜你喜欢
      • 2012-08-20
      • 1970-01-01
      • 2018-06-19
      • 2012-08-08
      • 2011-09-23
      • 2021-12-29
      • 1970-01-01
      • 2016-10-07
      • 2015-04-16
      相关资源
      最近更新 更多