如何在Android中实现长时间运行的网络上传,而不是使用AsyncTask而不使用库

时间:2014-08-31 09:14:55

标签: android android-asynctask

实现长时间运行的网络操作(如上传大量照片)的本机Android方式是什么,而不必使用像RoboSpice这样的库?

我已经阅读了很多关于stackoverflow的主题,建议asynctask不适合长时间运行的操作,因为它与活动的生命周期密切相关,可能导致内存泄漏,因为android 3.2只有一个线程可供所有人使用应用程序的asynctasks。 (不确定最后一个)

如何用别的东西替换我的asynctask?

现在,我听说过处理程序,执行程序,服务以及什么不是,但我究竟如何在我的代码中实现它们以及选择哪一个?

这是我使用的asynctask的一个例子

我删除了很多代码,只是为了让您看到基本结构

public class UploadPhotosToServer extends AsyncTask<String, Void, Boolean> {

@Override
protected Boolean doInBackground(String... args) {

    HashMap<String, String> params = new HashMap<String, String>();


        try {
            if(uploadImageToServer(id, path, params)) {
       success = true;
} else {
        success = false;
}
        } catch (Exception e) {
            e.printStackTrace();
            success = false;
        }


    return success;
} 

public boolean uploadImageToServer(int imageId, String imagePath, HashMap<String, String> params) throws Exception {

    try {
        JSONObject json = jsonParser.uploadImageToServer(imagePath, params);
        JSONObject message = json.getJSONObject("message");
        String serverResponse = message.getString("success");
        if (serverResponse.contentEquals("true") {
            return true;
        } else {
            return false;
        }
    } catch (JSONException e) {
        e.printStackTrace();
        return false;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}

}

这里是jsonParser.uploadImageToServer

public JSONObject uploadImageToServer(String imagePath, HashMap<String, String> params) throws Exception {

        HttpResponse response;
        MultipartEntityBuilder multipartEntity;
        HttpPost postRequest;
        HttpContext localContext;
        Bitmap bitmap;

        try {
            // Set the http handlers
            httpClient = new DefaultHttpClient();
            localContext = new BasicHttpContext();
            postRequest = new HttpPost(SERVER + "images");

            // Send the package
            multipartEntity = MultipartEntityBuilder.create();
            multipartEntity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
            multipartEntity.addPart("file", new FileBody(new File(imagePath)));
            for (Map.Entry<String, String> entry : params.entrySet()) {
                multipartEntity.addTextBody(entry.getKey(), entry.getValue());
            }
            postRequest.setEntity(multipartEntity.build());
            // Get the response. we will deal with it in onPostExecute.
            response = httpClient.execute(postRequest, localContext);
            HttpEntity httpEntity = response.getEntity();
            inputStream = httpEntity.getContent();
            try {
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "iso-8859-1"), 8);
                StringBuilder sb = new StringBuilder();
                String line = null;
                while ((line = reader.readLine()) != null) {
                    sb.append(line + "\n");
                }
                json = sb.toString();
                inputStream.close();
                reader.close();
            } catch (ClientProtocolException e1) {
                e1.printStackTrace();
            } catch (IOException e1) {
                e1.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }

            // Try parsing the string to a JSON object
            try {
                jsonObject = new JSONObject(json);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            // Return JSON String
            return jsonObject;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    } 

1 个答案:

答案 0 :(得分:3)

我认为对于一组上传,我会考虑实施IntentService。正如在链接中所解释的那样,它将处理工作线程中的意图列表,直到该列表用完为止,此时服务将再次关闭。

IntentService的实施非常简单。基于您在上面给出的示例的示例;

public class ImageUploadIntentService extends IntentService {

    public ImageUploadIntentService() {
        super("ImageUploadIntentService");
    }

    @Override
    public void onCreate() {
        // Not a required implementation but you might want to setup any dependencies
        // here that can be reused with each intent that the service is about to
        // receive.

        super.onCreate();
    }

    @Override
    public void onHandleIntent(Intent intent) {
        // Process your intent, this presumably will include data such as the local
        // path of the image that you want to upload.
        try {
            uploadImageToServer(intent.getExtra("image_to_upload"), params);
        } catch (Exception e) {
            // Oh :( Consider updating any internal state here so we know the state
            // of play for later
        }
    }

    public JSONObject uploadImageToServer(String imagePath, HashMap<String, String> params) throws Exception {
        // All of your upload code
    }

}

然后调用服务就像它一样简单;

Intent intent = new Intent(this, ImageUploadIntentService.class)
    .putExtra("image_to_upload", mImagePath);
startService(intent);

这确实给我们留下了指示上传队列进度的问题。我们可以使用ResultReceiver来解决这个问题。结果接收器为Parcelable,因此我们可以将其与意图一起发送,以便倾听我们可能感兴趣的结果。您可以使用ResultReceiver和合适的片段来处理Activity进度对话框,或者如果您想要一个带进度条的持久通知,那么您可以使用Service来托管接收器。

与使用AsyncTask相比,它更复杂一些,但它确实为您提供了更多的灵活性,而不是附加到Activity生命周期。另一个问题是IntentService,它仍然只会让你有一个工作线程,所以图像上传不会同时发生。但我可能会考虑将你的Bitmap JPEG压缩分解为它自己的IntentService,然后你可以在第一个上传的时候在队列中的下一个图像上进行压缩。