调用系统相册上传头像到服务器

Posted xinruzhishui_11

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了调用系统相册上传头像到服务器相关的知识,希望对你有一定的参考价值。

调用系统相册上传头像到服务器

现在越来越多的app都需要上传图片到服务器中,包括我们公司刚开发的一款app,想实现的功能是调用系统相册,上传头像到服务器,为用户设置头像,在经过努力之下,终于完成了。写下博客,巩固一下这方面的知识点,同时也希望可以帮助大家;好了废话不多说,直接上代码

  • 先看一下MainActivity的布局文件把,很简单,就一个Button和一个ImageView,点击Button之后,会弹出一个对话框,可以选择相机、相册或者取消,ImageView用于显示你选择的照片
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.uploadimagetoserver.MainActivity" >

    <Button
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="调用相册" />

    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:src="@drawable/ic_launcher" />

</RelativeLayout>
  • 接下来看一下MainActivity的代码吧

    private Button btn;
    private PopupWindow pop;
    private LinearLayout llPopup;
    private ImageView ivImage;

    /**
     * 请求裁剪码
     */
    public static final int REQUEST_CODE_GETIMAGE_BYCROP = 1;
    /**
     * 请求相机码
     */
    public static final int REQUEST_CODE_GETIMAGE_BYCAMERA = 2;
    /**
     * 请求相册
     */
    public static final int REQUEST_CODE_GETIMAGE_BYSDCARD = 3;

    /**
     * 去上传文件
     */
    protected static final int TO_UPLOAD_FILE = 4;  

    /**
     * 上传文件响应
     */
    protected static final int UPLOAD_FILE_DONE = 5;  //

    private Uri origUri;
    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        creatPopupwindows();

        ivImage = (ImageView) findViewById(R.id.image);
        btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new OnClickListener() 

            @Override
            public void onClick(View v) 
                llPopup.startAnimation(AnimationUtils.loadAnimation(MainActivity.this,R.anim.activity_slide_enter_bottom));
                pop.showAtLocation(parent, Gravity.BOTTOM, 0, 0);
            
        );
    
    /**
     * 创建对话框
     */
    protected void creatPopupwindows() 

        pop = new PopupWindow(this);
        View popupView = getLayoutInflater().inflate(R.layout.item_popupwindows, null);
        llPopup = (LinearLayout) popupView.findViewById(R.id.ll_popup);
        pop.setWidth(LayoutParams.MATCH_PARENT);
        pop.setHeight(LayoutParams.WRAP_CONTENT);
        pop.setBackgroundDrawable(new BitmapDrawable());
        pop.setFocusable(true);
        pop.setOutsideTouchable(true);
        pop.setContentView(popupView);

        parent = (RelativeLayout) popupView.findViewById(R.id.parent);
        Button bt1 = (Button) popupView
                .findViewById(R.id.item_popupwindows_camera);//照相
        Button bt2 = (Button) popupView
                .findViewById(R.id.item_popupwindows_Photo);//相册
        Button bt3 = (Button) popupView
                .findViewById(R.id.item_popupwindows_cancel);//取消

        bt1.setOnClickListener(new OnClickListener() 
            public void onClick(View v) 
                //照相
                photo();
                pop.dismiss();
                llPopup.clearAnimation();
            
        );
        bt2.setOnClickListener(new OnClickListener() 
            public void onClick(View v) 
                Intent intent;
                // Android6.0以上,要动态申请读写权限
                if (ContextCompat.checkSelfPermission(getApplicationContext(),
                        Manifest.permission.WRITE_EXTERNAL_STORAGE)
                        != PackageManager.PERMISSION_GRANTED) 
                    //申请读写权限
                    ActivityCompat.requestPermissions(MainActivity.this,
                            new String[]Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE,
                            REQUEST_CODE_GETIMAGE_BYCROP);
                 else

                    if (Build.VERSION.SDK_INT < 19) 
                        intent = new Intent();
                        intent.setAction(Intent.ACTION_GET_CONTENT);
                        intent.setType("image/*");
                        startActivityForResult(Intent.createChooser(intent, "选择图片"),
                                REQUEST_CODE_GETIMAGE_BYCROP);
                     else 
                        intent = new Intent(Intent.ACTION_PICK,
                                Images.Media.EXTERNAL_CONTENT_URI);
                        intent.setType("image/*");
                        startActivityForResult(Intent.createChooser(intent, "选择图片"),
                                REQUEST_CODE_GETIMAGE_BYCROP);
                    
                
                pop.dismiss();
                //清除动画
                llPopup.clearAnimation();
            
        );

        bt3.setOnClickListener(new OnClickListener() 
            public void onClick(View v) 
                pop.dismiss();
                llPopup.clearAnimation();
            
        );

    
    /**
     * 照相
     */
    protected void photo() 
        String savePath ="";
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
            //SD卡处于挂载状态,创建图片保存的文件夹路径
            savePath = Environment.getExternalStorageDirectory().getAbsolutePath()
                    +"/image/";
            File saveDir = new File(savePath);
            if(!saveDir.exists())
                //文件夹不存在,创建文件夹
                saveDir.mkdirs();
            
        else
            Toast.makeText(this, "无法保存照片,请检查SD卡是否挂载", Toast.LENGTH_SHORT).show();
            return;
        

        //创建图片名称
        String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss")
        .format(new Date());
        String fileName = "zhicuo_" + timeStamp + ".jpg";// 照片命名

        //自定义图片保存路径
        File out = new File(savePath, fileName);
        Uri uri = Uri.fromFile(out);
        origUri = uri;

        // 动态申请照相权限和读写权限
        if (ContextCompat.checkSelfPermission(getApplicationContext(),
                Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) 
            ActivityCompat.requestPermissions(this,
                    new String[]Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE,
                    REQUEST_CODE_GETIMAGE_BYCAMERA);
         else
            Intent openCameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            Log.i("MainActivity", uri.toString());
            openCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
            startActivityForResult(openCameraIntent,
                    REQUEST_CODE_GETIMAGE_BYCAMERA);
        

    

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent imageReturnIntent) 
        //回调处理结果
        if (resultCode != Activity.RESULT_OK)
            return;

        switch (requestCode) 
        case REQUEST_CODE_GETIMAGE_BYCAMERA :
            startActionCrop(origUri);// 拍照后裁剪
            break;
        case REQUEST_CODE_GETIMAGE_BYCROP:
            startActionCrop(imageReturnIntent.getData());// 选图后裁剪
            break;
        case REQUEST_CODE_GETIMAGE_BYSDCARD :
            //发送上传头像的消息
            handler.sendEmptyMessage(TO_UPLOAD_FILE);
            Bitmap bitmap = BitmapFactory.decodeFile(portraitFile.getAbsolutePath());
            if(bitmap != null)
                ivImage.setImageBitmap(bitmap);
            
            break;
        

    

    private Handler handler = new Handler()
        @Override
        public void handleMessage(Message msg) 
            switch (msg.what) 
            case TO_UPLOAD_FILE:
                toUploadFile();
                break;

            case UPLOAD_FILE_DONE:
                //响应返回的结果
                if(msg.arg1 == UploadUtil.UPLOAD_SUCCESS_CODE )
                    String result = (String) msg.obj;
                    try 
                        //上传成功之后,服务端返回的数据
                        JSONObject obj = new JSONObject(result);
                        //获取服务端返回的头像地址
                        String portrait = obj.getString("portrait");
                        //根据自己业务做后续处理

                     catch (JSONException e) 
                        e.printStackTrace();
                    
                else if(msg.arg1 == UploadUtil.UPLOAD_SERVER_ERROR_CODE)
                    Toast.makeText(MainActivity.this, "上传失败", Toast.LENGTH_SHORT).show();
                
                break;
            default:
                break;
            
            super.handleMessage(msg);
        
    ;

    /**
     * 请求裁剪
     * @param origUri
     */
    private void startActionCrop(Uri data) 
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(data, "image/*");
        intent.putExtra("output", this.getUploadTempFile(data));
        intent.putExtra("crop", "true");
        intent.putExtra("aspectX", 1);// 裁剪框比例
        intent.putExtra("aspectY", 1);
        intent.putExtra("outputX", 200);// 输出图片大小
        intent.putExtra("outputY", 200);
        intent.putExtra("scale", true);// 去黑边
        intent.putExtra("scaleUpIfNeeded", true);// 去黑边
        startActivityForResult(intent,
                REQUEST_CODE_GETIMAGE_BYSDCARD);
    
    /**
     * 上传头像到服务器
     */
    protected void toUploadFile() 
        String fileKey = "img";
        UploadUtil uploadUtil = UploadUtil.getInstance();
        uploadUtil.setOnUploadProcessListener(this);  //设置监听器监听上传状态
        //定义一个Map集合,封装请求服务端时需要的参数
        Map<String, String> params = new HashMap<String, String>();
            //在这里根据服务端接口需要的参数来定,我们公司上传头像的接口,需要传入的参数是用户的
            //userId,用户tocken,图片类型
//      params.put("userId", user.getUserId());
//      params.put("tocken", user.getTocken());
//      params.put("picType", "1");
        if(portraitFile.exists())
            //参数三:请求的url,这里我用到了公司的url
            uploadUtil.uploadFile(portraitFile.getAbsolutePath() ,fileKey, "http://www.megabes.com/zhicuo/v1/UploadPics.do",params);
        
    
    //获取保存头像地址的Uri
    private Uri getUploadTempFile(Uri uri) 
        String portraitPath = "";
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
            //保存图像的文件夹路径
            portraitPath = Environment.getExternalStorageDirectory().getAbsolutePath()
                    +"/image/Portrait";
            File saveDir = new File(portraitPath);
            if(!saveDir.exists())
                saveDir.mkdirs();
            
        else 
            Toast.makeText(this, "无法保存照片,请检查SD卡是否挂载", Toast.LENGTH_SHORT).show();;
            return null;
        

        String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss")
        .format(new Date());

        String thePath = getAbsolutePathFromNoStandardUri(uri);
        if (thePath.isEmpty()) 
            thePath = getAbsoluteImagePath(uri);
        

        //获取图片路径的扩展名
        String ext = thePath.substring(thePath.lastIndexOf('.') + 1);
        ext = ext.isEmpty() ? "jpg" : ext;

        // 照片命名
        String cropFileName = "crop_" + timeStamp + "." + ext;
        portraitFile = new File(portraitPath, cropFileName);
        cropUri = Uri.fromFile(portraitFile);
        return cropUri;
    

    private String SDCARD_MNT = "/mnt/sdcard";
    private String SDCARD = "/sdcard";
    private Uri cropUri;
    private File portraitFile;
    private RelativeLayout parent;

    /**
     * 判断当前Url是否标准的content://样式,如果不是,则返回绝对路径
     * @param uri
     * @return
     */
    private String getAbsolutePathFromNoStandardUri(Uri mUri) 
        String filePath = "";

        String mUriString = mUri.toString();
        mUriString = Uri.decode(mUriString);

        String pre1 = "file://" + SDCARD + File.separator;
        String pre2 = "file://" + SDCARD_MNT + File.separator;

        if (mUriString.startsWith(pre1)) 
            filePath = Environment.getExternalStorageDirectory().getPath()
                    + File.separator + mUriString.substring(pre1.length());
         else if (mUriString.startsWith(pre2)) 
            filePath = Environment.getExternalStorageDirectory().getPath()
                    + File.separator + mUriString.substring(pre2.length());
        
        return filePath;
    

    /**
     * 通过uri获取文件的绝对路径
     * @param uri
     * @return
     */
    @SuppressWarnings("deprecation")
    private String getAbsoluteImagePath(Uri uri) 
        String imagePath = "";
        String[] proj =  MediaStore.Images.Media.DATA ;
        Cursor cursor = managedQuery(uri, proj, // Which columns to
                // return
                null, // WHERE clause; which rows to return (all rows)
                null, // WHERE clause selection arguments (none)
                null); // Order-by clause (ascending by name)

        if (cursor != null) 
            int column_index = cursor
                    .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            if (cursor.getCount() > 0 && cursor.moveToFirst()) 
                imagePath = cursor.getString(column_index);
            
        
        return imagePath;
    
    @Override
    public void onUploadDone(int responseCode, String message) 
        Message msg = Message.obtain();
        msg.what = UPLOAD_FILE_DONE;
        msg.arg1 = responseCode;
        msg.obj = message;  
        handler.sendMessage(msg);
    
  • 再来看一下UploadUtil工具类的代码吧

    private static UploadUtil uploadUtil;
    private static final String BOUNDARY =  UUID.randomUUID().toString(); // 边界标识 随机生成
    private static final String PREFIX = "--";
    private static final String LINE_END = "\\r\\n";
    private static final String CONTENT_TYPE = "multipart/form-data"; // 内容类型

    String result = null;

    private UploadUtil() 

    

    /**
     * 单例模式获取上传工具类
     * @return
     */
    public static UploadUtil getInstance() 
        if (null == uploadUtil) 
            uploadUtil = new UploadUtil();
        
        return uploadUtil;
    

    private static final String TAG = "UploadUtil";
    private int readTimeOut = 10 * 1000; // 读取超时
    private int connectTimeout = 10 * 1000; // 超时时间

    /***
     * 请求使用多长时间
     */
    private static int requestTime = 0;

    private static final String CHARSET = "utf-8"; // 设置编码

    /***
     * 上传成功
     */
    public static final int UPLOAD_SUCCESS_CODE = 1;

    /**
     * 文件不存在
     */
    public static final int UPLOAD_FILE_NOT_EXISTS_CODE = 2;

    /**
     * 服务器出错
     */
    public static final int UPLOAD_SERVER_ERROR_CODE = 3;

    protected static final int WHAT_TO_UPLOAD = 1;
    protected static final int WHAT_UPLOAD_DONE = 2;

    /**
     * android上传文件到服务器
     * 
     * @param filePath
     *            需要上传的文件的路径
     * @param fileKey
     *            在网页上<input type=file name=xxx/> xxx就是这里的fileKey
     * @param RequestURL
     *            请求的URL
     */
    public void uploadFile(String filePath, String fileKey, String RequestURL, Map<String, String> param) 
        if (filePath == null) 
            sendMessage(UPLOAD_FILE_NOT_EXISTS_CODE,"文件不存在");
            return;
        
        try 
            File file = new File(filePath);
            uploadFile(file, fileKey, RequestURL, param);
         catch (Exception e) 
            sendMessage(UPLOAD_FILE_NOT_EXISTS_CODE,"文件不存在");
            e.printStackTrace();
            return;
        
    

    /**
     * android上传文件到服务器
     * 
     * @param file
     *            需要上传的文件
     * @param fileKey
     *            在网页上<input type=file name=xxx/> xxx就是这里的fileKey
     * @param RequestURL
     *            请求的URL
     */
    public void uploadFile(final File file, final String fileKey, final String RequestURL, final Map<String, String> param) 
        //开启线程上传文件
        new Thread()
            @Override
            public void run() 
                toUploadFile(file, fileKey, RequestURL, param);
            
        ;

    

    private void toUploadFile(File file, String fileKey, String RequestURL, Map<String, String> param) 
        requestTime= 0;

        long requestTime = System.currentTimeMillis();
        long responseTime = 0;

        try 
            URL url = new URL(RequestURL);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setReadTimeout(readTimeOut);
            conn.setConnectTimeout(connectTimeout);
            conn.setDoInput(true); // 允许输入流
            conn.setDoOutput(true); // 允许输出流
            conn.setUseCaches(false); // 不允许使用缓存
            conn.setRequestMethod("POST"); // 请求方式
            conn.setRequestProperty("Charset", CHARSET); // 设置编码
            conn.setRequestProperty("connection", "keep-alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
            conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);

            /**
             * 当文件不为空,把文件包装并且上传
             */
            DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
            StringBuffer sb = null;
            String params = "";

            /***
             * 以下是用于上传参数
             */
            if (param != null && param.size() > 0) 
                Iterator<String> it = param.keySet().iterator();
                while (it.hasNext()) 
                    sb = null;
                    sb = new StringBuffer();
                    String key = it.next();
                    String value = param.get(key);
                    sb.append(PREFIX).append(BOUNDARY).append(LINE_END);
                    sb.append("Content-Disposition: form-data; name=\\"").append(key).append("\\"").append(LINE_END).append(LINE_END);
                    sb.append(value).append(LINE_END);
                    params = sb.toString();
                    Log.i(TAG, key+"="+params+"##");
                    dos.write(params.getBytes());
                
            

            sb = null;
            params = null;
            sb = new StringBuffer();
            /**
             * 这里重点注意: name里面的值为服务器端需要key 只有这个key 才可以得到对应的文件
             * filename是文件的名字,包含后缀名的 比如:abc.png
             */
            sb.append(PREFIX).append(BOUNDARY).append(LINE_END);
            sb.append("Content-Disposition:form-data; name=\\"" + fileKey
                    + "\\"; filename=\\"" + file.getName() + "\\"" + LINE_END);
            sb.append("Content-Type:image/pjpeg" + LINE_END); // 这里配置的Content-type很重要的 ,用于服务器端辨别文件的类型的
            sb.append(LINE_END);
            params = sb.toString();
            sb = null;

            Log.i(TAG, file.getName()+"=" + params+"##");
            dos.write(params.getBytes());
            /**上传文件*/
            InputStream is = new FileInputStream(file);
            //          //文件大小
            //          onUploadProcessListener.initUpload((int)file.length());
            //          
            byte[] bytes = new byte[1024];
            int len = 0;
            while ((len = is.read(bytes)) != -1) 
                dos.write(bytes, 0, len);
            
            is.close();

            dos.write(LINE_END.getBytes());
            byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINE_END).getBytes();
            dos.write(end_data);
            dos.flush();
            /**
             * 获取响应码 200=成功 当响应成功,获取响应的流
             */
            int res = conn.getResponseCode();
            responseTime = System.currentTimeMillis();
            this.requestTime = (int) ((responseTime-requestTime)/1000);
            Log.e(TAG, "response code:" + res);
            if (res == 200) 
                Log.e(TAG, "request success");
                InputStream input = conn.getInputStream();
                StringBuffer sb1 = new StringBuffer();
                int ss;
                while ((ss = input.read()) != -1) 
                    sb1.append((char) ss);
                
                result = sb1.toString();
                Log.i(TAG, "result : " + result);
                sendMessage(UPLOAD_SUCCESS_CODE, result);
                return;
             else 
                Log.e(TAG, "request error");
                sendMessage(UPLOAD_SERVER_ERROR_CODE,"上传失败:code=" + res);
                return;
            
         catch (MalformedURLException e) 
            sendMessage(UPLOAD_SERVER_ERROR_CODE,"上传失败:error=" + e.getMessage());
            e.printStackTrace();
            return;
         catch (IOException e) 
            sendMessage(UPLOAD_SERVER_ERROR_CODE,"上传失败:error=" + e.getMessage());
            e.printStackTrace();
            return;
        
    

    /**
     * 发送上传结果
     * @param responseCode
     * @param responseMessage
     */
    private void sendMessage(int responseCode,String responseMessage)
    
        onUploadProcessListener.onUploadDone(responseCode, responseMessage);
    

    /**
     * 下面是一个自定义的回调函数,用到回调上传文件是否完成
     * 
     */
    public interface OnUploadProcessListener 
        /**
         * 上传响应
         * @param responseCode
         * @param message
         */
        void onUploadDone(int responseCode, String message);
    
    private OnUploadProcessListener onUploadProcessListener;

    public void setOnUploadProcessListener(
            OnUploadProcessListener onUploadProcessListener) 
        this.onUploadProcessListener = onUploadProcessListener;
    

    public int getReadTimeOut() 
        return readTimeOut;
    

    public void setReadTimeOut(int readTimeOut) 
        this.readTimeOut = readTimeOut;
    

    public int getConnectTimeout() 
        return connectTimeout;
    

    public void setConnectTimeout(int connectTimeout) 
        this.connectTimeout = connectTimeout;
    
    /**
     * 获取上传使用的时间
     * @return
     */
    public static int getRequestTime() 
        return requestTime;
    

最后别忘了在AndroidManifest.xml文件中添加如下权限哦

     <!-- 访问internet权限 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

注意:Android6.0之后,需要在代码中动态的申请权限

完整代码下载

以上是关于调用系统相册上传头像到服务器的主要内容,如果未能解决你的问题,请参考以下文章

iOS之设置头像(访问系统相册本地上传)

HTML5 开发APP(打开相册以及图片上传)

android实现头像更改并保存(调用系统相册,系统相机)

相册选择头像或者拍照 上传头像以NSData 图片二进制格式 表单上传

dz论坛通信成功,上传头像的flash滚动条一直加载,个人空间也不能上传图片到相册,帖子里可以上传图片。

Android端上传图片到后台,存储到数据库中 详细代码