android-----基於XUtils照片上傳用戶端以及伺服器端實現

來源:互聯網
上載者:User

標籤:

        想必大家都在android中或多或少的使用過XUtils架構了吧,今天我們通過他來實現一個照片上傳的Demo,希望能夠對大家有協助,下一篇再從源碼角度來分析下XUtils的HttpUtils是怎麼一個執行流程的;

        先上執行:

 

        用戶端實現:

        首先來看布局檔案:

<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"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context=".MainActivity" >    <LinearLayout        android:id="@+id/top"        android:layout_width="wrap_content"        android:layout_height="wrap_content">    <Button        android:id="@+id/upload_image"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="上傳圖片" />             </LinearLayout>    <ImageView        android:id="@+id/imageView"        android:layout_below="@id/top"        android:layout_centerInParent="true"        android:layout_width="wrap_content"        android:layout_height="wrap_content"/>    </RelativeLayout>
        很簡單吧,就是一個按鈕和一個用於顯示圖片的ImageView;

        接下來是MainActivity,直接看onCreate方法:

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();httpUtils = new HttpUtils(100000);httpUtils.configCurrentHttpCacheExpiry(5000);}
        這個方法首先會調用initView來初始化介面,接著建立了一個HttpUtils對象,並且設定他的連線逾時時間是100s,設定他的緩衝有效時間是5s,來看看initView方法:

/** * 初始化view控制項 */public void initView(){uploadImageBt = (Button) findViewById(R.id.upload_image);imageView = (ImageView)findViewById(R.id.imageView);uploadImageBt.setOnClickListener(this);progressDialog = getProgressDialog();//獲得進度條dialogListener = new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {switch (which) {case 0:tempFile = new File(Environment.getExternalStorageDirectory(),getPhotoFileName());//調用系統拍照startCamera(dialog);break;case 1://開啟系統圖庫startWall(dialog);break;default:break;}}};mHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {if(msg.arg1 > 0)progressDialog.setProgress(msg.arg1);//更新進度條}};}

        首先第9行獲得一個ProgressDialog對象,第10行為選擇對話方塊綁定點擊監聽事件,用來提示使用者是通過拍照獲得照片還是從圖庫獲得,這個對象的定義如下:

/** * 顯示選擇圖片來源的dialog(來自拍照還是本地圖庫) * @param title * @param items */public void showDialog(String title,String[] items){AlertDialog.Builder dialog = new AlertDialog.Builder(this).setTitle(title).setItems(items, dialogListener);//顯示dialogdialog.show();}
        如果選擇拍照,則通過startCamera方法來調用系統照相機:

/** * 調用相機來照相 * @param dialog */public void startCamera(DialogInterface dialog){dialog.dismiss();//首先隱藏選擇照片來源的dialog//調用系統的拍照功能Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);intent.putExtra("camerasensortype", 2);//調用自拍intent.putExtra("autofocus", true);//進行自動對焦操作intent.putExtra("fullScreen", false);//設定全屏intent.putExtra("showActionIcons", false);intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile));//指定調用相機之後所拍照儲存到的位置startActivityForResult(intent, PHOTO_CAMERA);}
        該方法首先會將選擇對話方塊隱藏,接著開啟系統網路攝影機並且進行相應的設定,並且指定儲存照片的位置,最後在返回上一個Activity之前將照片結果封裝在intent中返回,並且設定返回標誌是PHOTO_CAMERA;

        如果選擇的是相簿的話,則通過調用startWall方法來獲得SD上面照片:

/** * 開啟系統圖庫 * @param dialog */public void startWall(DialogInterface dialog){dialog.dismiss();//設定隱藏dialogIntent intent = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");startActivityForResult(intent, PHOTO_WALL);}
        該方法同樣首先將選擇對話方塊隱藏,接著調用系統服務顯示出SD卡中所有存在的圖片,並且通過intent返回圖片資訊,同時設定返回標誌為PHOTO_WALL;

        接下來我們看看不同的返回標誌各自所執行的到底是什麼內容呢?

@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);switch (requestCode) {case PHOTO_CAMERA://表示從相機獲得的照片,需要進行裁剪startPhotoCut(Uri.fromFile(tempFile), 300,true);break;case PHOTO_WALL:if(null != data)startPhotoCut(data.getData(),300,false);break;case PHOTO_STORE:if(null != data){setPictureToImageView(data,true);}break;case PHOTO_NOT_STORE:if(null != data){setPictureToImageView(data,false);}break;default:break;}}
        該方法是在調用startActivityForResult之後由系統調用的,看到了我們剛剛見到的PHOTO_CAMREA以及PHOTO_WALL標誌,首選來看看PHOTO_CAMREA,他會調用startPhotoCut對照片進行裁剪,來看看startPhotoCut方法:

/** * 將圖片裁剪到指定大小 * @param uri * @param size * @param flag */public void startPhotoCut(Uri uri,int size,boolean flag){Intent intent = new Intent("com.android.camera.action.CROP");intent.setDataAndType(uri, "image/*");intent.putExtra("crop", true);//設定Intent中的view是可以裁剪的//設定寬高比intent.putExtra("aspectX", 1);intent.putExtra("aspectY", 1);//設定裁剪圖片的寬高intent.putExtra("outputX", size);intent.putExtra("outputY", size);//設定是否返回資料intent.putExtra("return-data", true);if(flag == true)startActivityForResult(intent, PHOTO_STORE);else{tempIntent = intent;try {startActivityForResult(tempIntent, PHOTO_NOT_STORE);System.out.println("haha");} catch (Exception e) {System.out.println(e.toString());}}}
        這個方法前面的幾行都是對照片進行裁剪的一些設定,接著通過flag標誌來判斷是否將照片儲存到SD卡上面,因為如果flag為false的話,表示這張照片是我們通過圖庫擷取的,他來自於SD卡,因此沒什麼必要再存一次了,因而返回標誌PHOTO_NOT_STORE,如果flag為true的話,才需要儲存一遍,返回標誌PHOTO_STORE,同樣的調用的是startActivityForResult方法,那麼他也會執行onActivityResult方法;

        那麼對於PHOTO_WALL標誌,如果選擇的圖片不為空白的話,則執行startPhotoCut方法,同樣也進行裁剪;

        對於PHOTO_NOT_STORE和PHOTO_STORE標誌,他們都會執行setPictureToImageView方法,所以我們直接看他的代碼就可以了:

/** * 將圖片顯示到ImageView上面 * @param data * @param flag 表示如果是拍照獲得的照片的話則是true,如果是從系統選擇的照片的話就是false */public void setPictureToImageView(Intent data,boolean flag){Bundle bundle = data.getExtras();if(null != bundle){Bitmap bitmap = bundle.getParcelable("data");imageView.setImageBitmap(bitmap);//將圖片顯示到ImageView上面//上傳圖片到伺服器if(flag == false){//需要首先修改tempFile的值String path = getSelectPhotoPath(tempIntent);System.out.println("path:  "+path);tempFile = new File(path);//uploadPicture();//上傳圖片UploadThread thread = new UploadThread();thread.start();}else{//uploadPicture();//上傳圖片UploadThread thread = new UploadThread();thread.start();}if(flag == true)savePictureToSD(bitmap);//儲存圖片到sd卡上面}}
        這個方法做的事比較多,首先呢,他會從intent中擷取到擷取到圖片並且顯示到ImageView上面,接著會調用UploadThread線程將圖片上傳到伺服器上面,最如果flag為true的話表示需要將圖片儲存到本地,那麼我們需要調用savePictureToSD來儲存圖片,先來看看UploadThread線程:

class UploadThread extends Thread{@Overridepublic void run() {uploadPicture();}}
        很簡單,就只有一個uploadPicture方法了,自然我們需要查看uploadPicture的代碼:

/** * 上傳圖片到資料庫 */public void uploadPicture(){RequestParams params = new RequestParams();params.addBodyParameter("msg",tempFile.getAbsolutePath());params.addBodyParameter(tempFile.getPath().replace("/", ""), tempFile);httpUtils.send(HttpMethod.POST, url,params,new RequestCallBack<String>() {@Overridepublic void onStart() {progressDialog.show();//顯示進度條}@Overridepublic void onFailure(HttpException arg0, String arg1) {System.out.println("上傳失敗");System.out.println(arg0.toString());//上傳失敗之後隱藏進度條progressDialog.dismiss();}@Overridepublic void onLoading(long total, long current, boolean isUploading) {System.out.println("current/total:  "+current+"/"+total);int process = 0;if(total != 0){process = (int)(current/(total/100));}Message message = new Message();message.arg1 = process;mHandler.sendMessage(message);super.onLoading(total, current, isUploading); }@Overridepublic void onSuccess(ResponseInfo<String> arg0) {System.out.println("上傳成功");//上傳成功之後隱藏進度條progressDialog.dismiss();}});}
        這部分就是用到XUtils的HttpUtils的部分啦,首先設定一些請求參數,接著調用HttpUtils的send方法進行請求,為了能夠對上傳結果更加直觀,我們添加了進度條,onStart方法是上傳執行開始調用的方法,我們在此顯示出進度條,onLoading是上傳過程中執行的方法,大約每一秒鐘會執行一次,我們在此通過Handler的訊息機制將進度封裝成Message對象將其發送給Handler處理,具體的更新進度條的代碼是在我們上面的initView方法出現的,因為他只能在主線程中更新,最後在電泳失敗或者成功之後都要調用ProgressDialog的dismiss方法來隱藏進度條;

        最後就只剩下儲存圖片到SD卡的操作了,這個比較簡單,就只是簡單的檔案儲存體操作了,只不過路徑是SD卡而已:

/** * 將圖片儲存到SD卡上面 * @param bitmap */public void savePictureToSD(Bitmap bitmap){ByteArrayOutputStream baos = new ByteArrayOutputStream();FileOutputStream fos = null;bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);//第2個參數表示壓縮率,100表示不壓縮try {fos = new FileOutputStream(tempFile);fos.write(baos.toByteArray());fos.flush();} catch (Exception e) {e.printStackTrace();}finally{try {if(null != baos){    baos.close();    baos = null;}if(null != fos){fos.close();fos = null;}} catch (Exception e2) {}}}
        至此,用戶端代碼講解完畢,接下來是伺服器端代碼:

        伺服器端:

        代碼比較少,直接copy出來了:

public class UploadServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doPost(request, response);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {request.setCharacterEncoding("utf-8");response.setCharacterEncoding("utf-8");response.setContentType("text/html,charset=utf-8");SmartUpload smartUpload = new SmartUpload();String msg= null;        try {              smartUpload.initialize(this.getServletConfig(), request, response);             smartUpload.upload();              msg = smartUpload.getRequest().getParameter("msg");            System.out.println(smartUpload.getFiles().getCount());            com.jspsmart.upload.File smartFile = smartUpload.getFiles().getFile(0);              if (!smartFile.isMissing()) {                  String saveFileName = getServletContext().getRealPath("/")+"images\\" + smartFile.getFileName();                  System.out.println(saveFileName);                smartFile.saveAs(saveFileName, SmartUpload.SAVE_PHYSICAL);              }        } catch (Exception e) {          e.printStackTrace();        } }}

        最主要是doPost方法了,本執行個體採用的是SmartUpload的方式來實現檔案上傳操作的,當然你也可以採用別的方法,至於jar包等會源碼下載連結的工程裡面就有啦,第18行首先對SmartUpload進行初始化,接著調用upload方法準備上傳,第22行獲得用戶端上傳檔案的第一個檔案,從這裡我們也可以看出來SmartUpload是支援多檔案上傳的,接著第23行判斷這個檔案是否存在,24行產生存放檔案的路徑,26行進行檔案的儲存操作,注意SmartUpload.SAVE_PHYSICAL的意思指的是絕對路徑,因此你的檔案儲存體路徑必須是全路徑,這樣伺服器端代碼講解結束,是不是很簡單呀,提醒一下web.xml的配置,我的配置如下:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"><servlet><servlet-name>UploadServlet</servlet-name>        <servlet-class>com.hzw.servlet.UploadServlet</servlet-class></servlet><servlet-mapping>    <servlet-name>UploadServlet</servlet-name>        <url-pattern>/upload</url-pattern>    </servlet-mapping></web-app>
        基本上講解結束啦,記得在用戶端裡面別忘記添加網路訪問和SD卡存取權限哈:

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>    <uses-permission android:name="android.permission.INTERNET"></uses-permission>    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
點擊這裡下載源碼!!!!!
















android-----基於XUtils照片上傳用戶端以及伺服器端實現

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.