我正在开发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();
}
}
}
}
答案 0 :(得分:0)
如何优化我的代码或防止我必须同时上传许多内容
我放弃了AsyncTask,转而使用IntentService,它同时执行一个作业并将所有其他作业排队。当然整个过程并不像看起来那么简单,所以使用像Android Priority Job Queue这样的专用库会更好。
答案 1 :(得分:0)
好吧,开始不要为每次上传创建一个新的请求队列。队列的想法是你向它添加一堆请求,然后运行队列,让Volley一次慢慢地通过一小组请求。你创建了几十个队列,我甚至都没有看到一个运行队列的呼叫。
我也使用Thread而不是AsyncTask。 AsyncTasks应该是一次性的。事实上,通过使用这么多任务,你可以匮乏可能需要任务的所有其他事情,因为它们共享一个共同的线程。