将多个图像上传到队列中的服务器

Posted

技术标签:

【中文标题】将多个图像上传到队列中的服务器【英文标题】:Upload multiple images to server in a queue 【发布时间】:2016-12-13 21:09:51 【问题描述】:

用例: 将后台队列中的图片上传到服务器,图片可以是网址,也可以是手机内存中的图片文件。

我想要什么 将队列中的项目数限制为 3 个,并将模糊图像显示为实际图像的占位符,用于在活动的回收站视图中上传,每个占位符上都有一个进度条指示多少其中已上传。每个占位符的顶部是三个按钮,用于暂停、取消或恢复图像的上传。

现状:现在,我在Retrofit 1.9.0 中使用Multipart 来上传图片,这个服务调用是在活动内部完成的。

我无法弄清楚如何使用 Retrofit 或任何其他库来取消、暂停或恢复多部分 POST 请求,以及如何将 UI 事件与 api 服务线程联系起来。我可以从服务更新 UI,但是如何从 UI 中的事件(暂停/恢复/取消)更新服务中的某些内容?

我应该如何处理这个用例?我需要使用服务吗?我可以根据服务中正在执行的请求在另一个活动中显示进度指示器吗?这个过程的架构应该是什么? 我不需要它的代码,但是如果有一些与此相关的有用参考资料,我想阅读并测试它以最终得出我的方法。

【问题讨论】:

A user can upload an image to server either through existing urls(facebook or instagram) or through a local image file. ???可以将图像上传到服务器。服务器有一个网址。无法通过本地图像文件上传图像。请改写,因为现在没有意义了。 @greenapps 好的,我会解决的。其实,这个app是一个图片分享平台,你可以分享fb或instagram图片,也可以直接从手机相册上传。 【参考方案1】:

您可以这样做:这是通过传递图像的路径从设备上传图像的示例代码..类似地,您可以对图像 url 执行此操作, 步骤:1)创建一个将为每个图像运行的线程。 2)之后每张图片上传都会给你回复。 3) 现在你可以为每张图片更新你的 UI。

//TODO: Multiple file upload
public class FileUpload implements Runnable 
    Context context;
    String uploadApiUrl, uploadFilePath, fileType;
    int uploadId;
    LocalQueenDataBase localQueenDataBase;
    Activity activity;

    public FileUpload(Context context, ,String uploadApiUrl, String uploadFilePath, String fileType, int uploadId) 
        this.context = context;
        this.uploadApiUrl = uploadApiUrl;
        this.uploadFilePath = uploadFilePath;
        this.fileType = fileType;
        this.uploadId = uploadId;
        localQueenDataBase = new LocalQueenDataBase(context);
        Thread uploader = new Thread(this);
        uploader.start();
    

    @Override
    public void run() 
        try 
            executeMultipartPost();
         catch (Exception e) 
            e.printStackTrace();
        
    

    public void executeMultipartPost() throws Exception 
        try 
            String originalPath = uploadFilePath;
            if (uploadFilePath == null) 
                uploadFilePath = originalPath;
            
            HttpClient httpclient = new DefaultHttpClient();
            HttpPost httppost = new HttpPost("your api url");
            httppost.addHeader("put your header if required")
            FileBody bin = new FileBody(new File(uploadFilePath));
            StringBody fileTypeBody = new StringBody(fileType);
            StringBody uploadIdBody = new StringBody(uploadId + "");

            MultipartEntity reqEntity = new MultipartEntity();
            reqEntity.addPart("file", bin);
            reqEntity.addPart("fileType", fileTypeBody);
            reqEntity.addPart("uploadId", uploadIdBody);
            httppost.setEntity(reqEntity);

            HttpResponse response = httpclient.execute(httppost);
            HttpEntity resEntity = response.getEntity();
            String retSrc = EntityUtils.toString(resEntity);//Render your response
            //TODO: update your UI for each uploaded image by creating the Handler
             Message msg = handler.obtainMessage();
             handler.sendMessage(msg);
         catch (Exception e) 
            e.printStackTrace();
        
    


final Handler handler = new Handler() 
    @Override
    public void handleMessage(Message msg) 
        try 
            uploadGalleryRecyclerAdapter = new UploadGalleryRecyclerAdapter(getApplicationContext(), PostUpdateActivity.this, localQueenDataBase.getGallery());
            postUpdateRV.setAdapter(uploadGalleryRecyclerAdapter);
            if (localQueenDataBase.getGallery().size() > 3)
                gallerylayoutManager.scrollToPosition(localQueenDataBase.getGallery().size() - 2);
         catch (Exception e) 
            e.printStackTrace();
        
        super.handleMessage(msg);
    
;

希望这会对你有所帮助。

【讨论】:

【参考方案2】:

我强烈建议您在一次上传多个文件/图像时使用 Square 的 Tape,以考虑易用性、效率、错误处理、排队系统。如果您一次只使用一个文件,请尝试在任何 android Http 客户端中使用任何多部分文件上传

这就是Square's Tape:

Tape 是 Square, Inc. 的 Android 和 Java 队列相关类的集合。

QueueFile 是一个闪电般快速、事务性、基于文件的 FIFO。从实例中添加和删除是一个 O(1) 操作并且是原子的。写入是同步的;数据将在操作返回之前写入磁盘。底层文件的结构可以在进程甚至系统崩溃时继续存在,如果在变异更改期间引发 I/O 异常,则更改将被中止。

ObjectQueue 表示任意对象的排序,可以由文件系统(通过 QueueFile)或仅在内存中支持。

TaskQueue 是一个特殊的对象队列,它保存着任务,这些对象具有被执行的概念。实例由准备和执行入队任务的外部执行器管理。

【讨论】:

【参考方案3】:
enter codepackage com.mohit.mom.multipleimage;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.StrictMode;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;

@SuppressLint("NewApi")
public class MainActivity extends Activity 
    private Button upload, pick;
    private ProgressDialog dialog;
    MultipartEntity entity;
    GridView gv;
    int count = 0;
    public ArrayList<String> map = new ArrayList<String>();
    Bundle b;
    TextView noImage;
    HttpEntity resEntity;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
                .permitAll().build();
        StrictMode.setThreadPolicy(policy);
        b = getIntent().getExtras();

        noImage = (TextView) findViewById(R.id.noImage);
        upload = (Button) findViewById(R.id.btnUpload);
        pick = (Button) findViewById(R.id.btnPicture);
        gv = (GridView) findViewById(R.id.gridview);
        gv.setAdapter(new ImageAdapter(this));

        if (b != null)
        
            ArrayList<String> ImgData = b.getStringArrayList("IMAGE");
            for (int i = 0; i < ImgData.size(); i++)
            
                map.add(ImgData.get(i).toString());
            
         else
        
            noImage.setVisibility(View.VISIBLE);
        

        upload.setOnClickListener(new View.OnClickListener() 

            public void onClick(View v)
            
                new ImageUploadTask().execute(count + "", "pk" + count + ".jpg");
            
        );

        pick.setOnClickListener(new View.OnClickListener() 

            public void onClick(View v) 
                Intent i3 = new Intent(MainActivity.this, UploadActivity.class);
                startActivity(i3);
            
        );

    

    class ImageUploadTask extends AsyncTask<String, Void, String> 

        String sResponse = null;

        @Override
        protected void onPreExecute() 
            // TODO Auto-generated method stub
            super.onPreExecute();
            dialog = ProgressDialog.show(MainActivity.this, "Uploading",
                    "Please wait...", true);
            dialog.show();
        

        @Override
        protected String doInBackground(String... params) 
            try 

                String url = "yours url";
                int i = Integer.parseInt(params[0]);
                Bitmap bitmap = decodeFile(map.get(i));
                HttpClient httpClient = new DefaultHttpClient();
                HttpContext localContext = new BasicHttpContext();
                HttpPost httpPost = new HttpPost(url);
                entity = new MultipartEntity();

                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                bitmap.compress(CompressFormat.JPEG, 50, bos);
                byte[] data = bos.toByteArray();

                entity.addPart("user_id", new StringBody("199"));
                entity.addPart("club_id", new StringBody("10"));
                entity.addPart("club_image", new ByteArrayBody(data,
                        "image/jpeg", params[1]));

                httpPost.setEntity(entity);
                HttpResponse response = httpClient.execute(httpPost);
                resEntity = response.getEntity();
                sResponse = EntityUtils.toString(resEntity);
                //HttpResponse response = httpClient.execute(httpPost,localContext);
                //sResponse = EntityUtils.getContentCharSet(response.getEntity());

                System.out.println("sResponse : " + sResponse);
             catch (Exception e) 
                if (dialog.isShowing())
                    dialog.dismiss();
                Log.e(e.getClass().getName(), e.getMessage(), e);

            
            return sResponse;
        

        @Override
        protected void onPostExecute(String sResponse) 
            try 
                if (dialog.isShowing())
                    dialog.dismiss();

                if (sResponse != null) 
                    Toast.makeText(getApplicationContext(),
                            sResponse + " Photo uploaded successfully",
                            Toast.LENGTH_SHORT).show();
                    count++;
                    if (count < map.size()) 
                        new ImageUploadTask().execute(count + "", "hm" + count
                                + ".jpg");
                    
                

             catch (Exception e) 
                Toast.makeText(getApplicationContext(), e.getMessage(),
                        Toast.LENGTH_LONG).show();
                Log.e(e.getClass().getName(), e.getMessage(), e);
            

        
    

    public Bitmap decodeFile(String filePath) 
// Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filePath, o);
// The new size we want to scale to
        final int REQUIRED_SIZE = 1024;
// Find the correct scale value. It should be the power of 2.
        int width_tmp = o.outWidth, height_tmp = o.outHeight;
        int scale = 1;
        while (true) 
            if (width_tmp < REQUIRED_SIZE && height_tmp < REQUIRED_SIZE)
                break;
            width_tmp /= 2;
            height_tmp /= 2;
            scale *= 2;
        
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        Bitmap bitmap = BitmapFactory.decodeFile(filePath, o2);
        return bitmap;
    

    private class ImageAdapter extends BaseAdapter
    
        private Context mContext;

        public ImageAdapter(Context c)
        
            mContext = c;
        

        public int getCount()
        
            return map.size();
        

        public Object getItem(int position)
        
            return null;
        

        // create a new ImageView for each item referenced by the Adapter
        public View getView(int position, View convertView, ViewGroup parent) 
            ImageView imageView;
            if (convertView == null)
             // if it's not recycled, initialize some
                // attributes
                imageView = new ImageView(mContext);
                imageView.setLayoutParams(new GridView.LayoutParams(85, 85,
                        Gravity.CENTER));
                imageView.setScaleType(ImageView.ScaleType.FIT_XY);
                imageView.setPadding(1, 1, 1, 1);

            
            else
            
                imageView = (ImageView) convertView;
            
            //Bitmap bm=BitmapFactory.decodeFile(map.get(position));
            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize = 8;
            Bitmap bmp = BitmapFactory.decodeFile(map.get(position),options);
            imageView.setImageBitmap(bmp);
            return imageView;
        

        @Override
        public long getItemId(int position) 
            // TODO Auto-generated method stub
            return 0;
        
    

    @Override
    public void onBackPressed() 
// TODO Auto-generated method stub
        super.onBackPressed();
        MainActivity.this.finish();
    

【讨论】:

这段代码非常好......实现这个......之后我也发布了服务器端代码......

以上是关于将多个图像上传到队列中的服务器的主要内容,如果未能解决你的问题,请参考以下文章

将多张图片作为 Facebook 快速上传到服务器 iOS

从android应用程序上传多个图像文件到php服务器

将多张图片从图库上传到android中的服务器

将多个图像上传到服务器时出现内存问题

在android中将多个图像上传到服务器的最快方法

使用 PHP 和单个 HTML 输入将多个图像上传到服务器和数据库[重复]