对于许多同时上传的AsyncTask

时间:2016-09-07 17:00:35

标签: java android android-asynctask android-volley image-uploading

请原谅我的英语不好,我希望我的解释是可以理解的。

我正在开发app,它与我的服务器进行通信。它有不同的任务。其中之一是将我的智能手机上的图片上传到我的服务器。我想,我的应用程序在后台执行此操作,最大限度地减少了内存和带宽的使用。

基本上它可以工作,但是当我需要很多新图片的时候,同时会有很多AsyncTask,并且可以减少内存和带宽的感知。

首先我使用BroadcastReceiver,它每30分钟启动一次我的图片扫描仪。 Scanner frist检查,如果外部存储器是可读的,WIFI是否打开以及是否有Internet连接。

当这是真的时,它从数据库中查询已经上传的图片中的列表。

然后它请求MediaStore库中的所有图片,检查一些最小值(大小,高度,宽度)以及图片是否未上传。当一切正常时,它会启动一个AsyncTask来调整图像大小并上传它:

public class Scanner {

    private Context context;
    private PicDAO picDAO;
    private Helper helper;

    public Scanner(Context context) {
        this.context = context;
        picDAO = new PicDAO(context);
        helper = new Helper(context);
    }

    public void startScan(){
        if(helper.isExternalStorageReadable()
                && helper.isWifiOn()
                && helper.checkInternet()){
            HashMap<Integer, String> pics = picDAO.picsHashMap();
            Cursor mCursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,null,null,null,MediaStore.Images.Media.DEFAULT_SORT_ORDER);
            if(mCursor != null){
                mCursor.moveToFirst();
                while(!mCursor.isAfterLast()) {
                    PicClass pic = new PicClass(
                            mCursor.getInt(mCursor.getColumnIndex(MediaStore.Images.Media._ID)),
                            mCursor.getString(mCursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)),
                            mCursor.getString(mCursor.getColumnIndex(MediaStore.Images.Media.DATA)),
                            mCursor.getInt(mCursor.getColumnIndex(MediaStore.Images.Media.WIDTH)),
                            mCursor.getInt(mCursor.getColumnIndex(MediaStore.Images.Media.HEIGHT)),
                            mCursor.getInt(mCursor.getColumnIndex(MediaStore.Images.Media.SIZE)),
                            context
                    );
                    if(pic.getSize() > 25000
                            && pic.getHeight() > 200
                            && pic.getWidth() > 200
                            && ( pics.get(pic.getIdent()) == null || !pics.get(pic.getIdent()).equals(pic.getDisplay_name()))
                            ){
                        CreateThumb createThumb = new CreateThumb(context);
                        createThumb.execute(new PicClass[]{pic});
                    }
                    mCursor.moveToNext();
                }
                mCursor.close();
            }
        }
    }
}

creatThumb看起来调整了Image的大小并开始上传(使用凌空库):

公共类CreateThumb扩展了AsyncTask {

private Context context;

public CreateThumb(Context context) {
    this.context = context;
}

@Override
protected PicClass doInBackground(PicClass... pics) {
    Helper helper = new Helper(context);
    String encodedString = "";
    if(helper.isWifiOn() && helper.checkInternet()){
        double dWidth = 1000;
        double dHeight = 1000;
        if(pics[0].getWidth() < (int) dWidth && pics[0].getHeight() < (int) dHeight){
            dWidth = pics[0].getWidth();
            dHeight = pics[0].getHeight();
        }else{
            if (pics[0].getWidth() > pics[0].getHeight()){
                double div = pics[0].getWidth() / dWidth;
                dHeight = pics[0].getHeight() / div;
            }else{
                double div = pics[0].getHeight() / dHeight;
                dWidth = pics[0].getWidth() / div;
            }
        }
        int width = (int) dWidth;
        int height = (int) dHeight;
        BitmapFactory.Options bmOptions = new BitmapFactory.Options();
        Bitmap bitmap = BitmapFactory.decodeFile(pics[0].getPath(),bmOptions);
        Bitmap thumbnail = ThumbnailUtils.extractThumbnail(bitmap,width,height,0);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        thumbnail.compress(Bitmap.CompressFormat.JPEG, 90, stream);
        byte[] byte_arr = stream.toByteArray();
        encodedString = Base64.encodeToString(byte_arr, 0);
    }
    pics[0].setThumb_file(encodedString);
    return pics[0];
}
@Override
protected void onPostExecute(final PicClass pic) {
    if(!pic.getThumb_file().equals("")){
        RequestQueue queue = Volley.newRequestQueue(context);
        String url ="http://example.de/upload.php";
        StringRequest postRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>(){
            @Override
            public void onResponse(String response) {
                if(response.equals("OK")){
                    PicDAO picDAO = new PicDAO(context);
                    picDAO.savePic(pic);
                }
            }
        },
            new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {}
            }
        ){
            @Override
            protected Map<String, String> getParams() {
                Map<String, String>  params = new HashMap<>();
                params.put("img",pic.getThumb_file());
                params.put("filename",pic.getDisplay_name() + ".jpg");
                return params;
            }
        };
        queue.add(postRequest);
    }
}

}

我服务器上的脚本:

<?php
    $base = $_POST['img'];
    $filename = $_POST['filename'];
    $binary = base64_decode($base);
    $file = fopen('uploadedimages/'.$filename, 'wb');
    fwrite($file, $binary);
    fclose($file);
    echo "OK";

问题是,当我需要很多新图片时,它会降低设备和互联网连接的速度,我会收到这样的错误:

  

W / art:暂停所有线程:278.260ms   D / Volley:[2790] BasicNetwork.logSlowRequests:对于请求的HTTP响应=&lt; [] http://example.de/upload.php 0x8a9f5792正常1&gt; [lifetime = 3447],[size = 2],[rc = 200],[retryCount = 1]

如何优化我的代码或防止我必须同时上传许多内容。

修改

我尝试重建扫描仪部件,并且只使用一个添加请求的队列。但似乎它不起作用。当只有一张图片可以工作时,但是当脚本添加的次数超过请求时,它就不会得到响应,而服务器只是第一张图片。

public class Scanner {

    private Context context;
    private PicDAO picDAO;
    private Helper helper;

    public Scanner(Context context) {
        this.context = context;
        picDAO = new PicDAO(context);
        helper = new Helper(context);
    }

    public void startScan(){
        if(helper.isDeviceReady()){
            Cursor mCursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,null,null,null,MediaStore.Images.Media.DEFAULT_SORT_ORDER);
            if(mCursor != null){
                final RequestQueue mRequestQueue = Volley.newRequestQueue(context);
                mCursor.moveToFirst();
                while(!mCursor.isAfterLast()) {
                    final PicClass pic = new PicClass(mCursor, context);
                    if(pic.checkSize() && !picDAO.picExist(pic)){
                        BitmapFactory.Options bmOptions = new BitmapFactory.Options();
                        Bitmap bitmap = BitmapFactory.decodeFile(pic.getPath(),bmOptions);
                        Bitmap thumbnail = ThumbnailUtils.extractThumbnail(bitmap,pic.getNewSize()[0],pic.getNewSize()[1],0);
                        ByteArrayOutputStream stream = new ByteArrayOutputStream();
                        thumbnail.compress(Bitmap.CompressFormat.JPEG, 90, stream);
                        byte[] byte_arr = stream.toByteArray();
                        pic.setThumb_file(Base64.encodeToString(byte_arr, 0));
                        StringRequest postRequest = new StringRequest(Request.Method.POST, "http://example.de/upload.php", new Response.Listener<String>(){
                            @Override
                            public void onResponse(String response) {
                                Log.d("DEBUG",response);
                                if(response.equals("OK")){
                                    PicDAO picDAO = new PicDAO(context);
                                    picDAO.savePic(pic);
                                }
                            }
                        },
                                new Response.ErrorListener() {
                                    @Override
                                    public void onErrorResponse(VolleyError error) {
                                        VolleyLog.e("Error: ", error.getMessage());
                                    }
                                }
                        ){
                            @Override
                            protected Map<String, String> getParams() {
                                Map<String, String>  params = new HashMap<>();
                                params.put("img",pic.getThumb_file());
                                params.put("filename",pic.getDisplay_name() + ".jpg");
                                return params;
                            }
                        };
                        mRequestQueue.add(postRequest);
                    }
                    mCursor.moveToNext();
                }
                mCursor.close();
            }
        }
    }
}

2 个答案:

答案 0 :(得分:0)

  

如何优化我的代码或防止我必须同时上传许多内容

我放弃了AsyncTask,转而使用IntentService,它同时执行一个作业并将所有其他作业排队。当然整个过程并不像看起来那么简单,所以使用像Android Priority Job Queue这样的专用库会更好。

答案 1 :(得分:0)

好吧,开始不要为每次上传创建一个新的请求队列。队列的想法是你向它添加一堆请求,然后运行队列,让Volley一次慢慢地通过一小组请求。你创建了几十个队列,我甚至都没有看到一个运行队列的呼叫。

我也使用Thread而不是AsyncTask。 AsyncTasks应该是一次性的。事实上,通过使用这么多任务,你可以匮乏可能需要任务的所有其他事情,因为它们共享一个共同的线程。