android retrofit 上传文件表单
转载
Android上传文件到服务器,通常采用构造http协议的方法,模拟网页POST方法传输文件,服务器端可以采用JavaServlet或者PHP来 接收要传输的文件。使用JavaServlet来接收文件的方法比较常见,在这里给大家介绍一个简单的服务器端使用PHP语言来接收文件的例子。
服务器端代码比较简单,接收传输过来的文件:
<?php
$target_path = "./upload/" ; //接收文件目录
$target_path = $target_path . basename ( $_FILES [ 'uploadedfile' ][ 'name' ]);
if (move_uploaded_file( $_FILES [ 'uploadedfile' ][ 'tmp_name' ], $target_path )) {
echo "The file " . basename ( $_FILES [ 'uploadedfile' ][ 'name' ]). " has been uploaded" ;
} else {
echo "There was an error uploading the file, please try again!" . $_FILES [ 'uploadedfile' ][ 'error' ];
}
?>
手机客户端代码:
package com.figo.uploadfile;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class UploadfileActivity extends Activity
{
// 要上传的文件路径,理论上可以传输任何文件,实际使用时根据需要处理
private String uploadFile = "/sdcard/testimg.jpg" ;
private String srcPath = "/sdcard/testimg.jpg" ;
// 服务器上接收文件的处理页面,这里根据需要换成自己的
private String actionUrl = "http://10.100.1.208/receive_file.php" ;
private TextView mText1;
private TextView mText2;
private Button mButton;
@Override
public void onCreate(Bundle savedInstanceState)
{
super .onCreate(savedInstanceState);
setContentView(R.layout.main);
mText1 = (TextView) findViewById(R.id.myText2);
mText1.setText( "文件路径:\n" + uploadFile);
mText2 = (TextView) findViewById(R.id.myText3);
mText2.setText( "上传网址:\n" + actionUrl);
/* 设置mButton的onClick事件处理 */
mButton = (Button) findViewById(R.id.myButton);
mButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
uploadFile(actionUrl);
}
});
}
/* 上传文件至Server,uploadUrl:接收文件的处理页面 */
private void uploadFile(String uploadUrl)
{
String end = "\r\n" ;
String twoHyphens = "--" ;
String boundary = "******" ;
try
{
URL url = new URL(uploadUrl);
HttpURLConnection httpURLConnection = (HttpURLConnection) url
.openConnection();
// 设置每次传输的流大小,可以有效防止手机因为内存不足崩溃
// 此方法用于在预先不知道内容长度时启用没有进行内部缓冲的 HTTP 请求正文的流。
httpURLConnection.setChunkedStreamingMode( 128 * 1024 ); // 128K
// 允许输入输出流
httpURLConnection.setDoInput( true );
httpURLConnection.setDoOutput( true );
httpURLConnection.setUseCaches( false );
// 使用POST方法
httpURLConnection.setRequestMethod( "POST" );
httpURLConnection.setRequestProperty( "Connection" , "Keep-Alive" );
httpURLConnection.setRequestProperty( "Charset" , "UTF-8" );
httpURLConnection.setRequestProperty( "Content-Type" ,
"multipart/form-data;boundary=" + boundary);
DataOutputStream dos = new DataOutputStream(
httpURLConnection.getOutputStream());
dos.writeBytes(twoHyphens + boundary + end);
dos.writeBytes( "Content-Disposition: form-data; name=\"uploadedfile\"; filename=\""
+ srcPath.substring(srcPath.lastIndexOf( "/" ) + 1 )
+ "\""
+ end);
dos.writeBytes(end);
FileInputStream fis = new FileInputStream(srcPath);
byte [] buffer = new byte [ 8192 ]; // 8k
int count = 0 ;
// 读取文件
while ((count = fis.read(buffer)) != - 1 )
{
dos.write(buffer, 0 , count);
}
fis.close();
dos.writeBytes(end);
dos.writeBytes(twoHyphens + boundary + twoHyphens + end);
dos.flush();
InputStream is = httpURLConnection.getInputStream();
InputStreamReader isr = new InputStreamReader(is, "utf-8" );
BufferedReader br = new BufferedReader(isr);
String result = br.readLine();
Toast.makeText( this , result, Toast.LENGTH_LONG).show();
dos.close();
is.close();
} catch (Exception e)
{
e.printStackTrace();
setTitle(e.getMessage());
}
}
}
|
在AndroidManifest.xml文件里添加网络访问权限:
< uses-permission android:name = "android.permission.INTERNET" />
运行结果:
以上已经能够实现文件上传,但没有上传进度。这次在之前的基础上添加进度显示,Java代码如下所示:
package com.lenovo.uptest;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class UploadtestActivity extends Activity {
/** Called when the activity is first created. */
/**
* Upload file to web server with progress status, client: android;
* server:php
* **/
private TextView mtv1 = null ;
private TextView mtv2 = null ;
private Button bupload = null ;
private String uploadFile = "/sdcard/testimg.jpg" ;
private String actionUrl = "http://10.100.1.208/receive_file.php" ;
@Override
public void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.main);
mtv1 = (TextView) findViewById(R.id.mtv1);
mtv1.setText( "文件路径:\n" + uploadFile);
mtv2 = (TextView) findViewById(R.id.mtv2);
mtv2.setText( "上传地址:\n" + actionUrl);
bupload = (Button) findViewById(R.id.bupload);
bupload.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
FileUploadTask fileuploadtask = new FileUploadTask();
fileuploadtask.execute();
}
});
}
// show Dialog method
private void showDialog(String mess) {
new AlertDialog.Builder(UploadtestActivity. this ).setTitle( "Message" )
.setMessage(mess)
.setNegativeButton( "确定" , new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
}).show();
}
class FileUploadTask extends AsyncTask<Object, Integer, Void> {
private ProgressDialog dialog = null ;
HttpURLConnection connection = null ;
DataOutputStream outputStream = null ;
DataInputStream inputStream = null ;
//the file path to upload
String pathToOurFile = "/sdcard/testimg.jpg" ;
//the server address to process uploaded file
String urlServer = "http://10.100.1.208/receive_file.php" ;
String lineEnd = "\r\n" ;
String twoHyphens = "--" ;
String boundary = "*****" ;
File uploadFile = new File(pathToOurFile);
long totalSize = uploadFile.length(); // Get size of file, bytes
@Override
protected void onPreExecute() {
dialog = new ProgressDialog(UploadtestActivity. this );
dialog.setMessage( "正在上传..." );
dialog.setIndeterminate( false );
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setProgress( 0 );
dialog.show();
}
@Override
protected Void doInBackground(Object... arg0) {
long length = 0 ;
int progress;
int bytesRead, bytesAvailable, bufferSize;
byte [] buffer;
int maxBufferSize = 256 * 1024 ; // 256KB
try {
FileInputStream fileInputStream = new FileInputStream( new File(
pathToOurFile));
URL url = new URL(urlServer);
connection = (HttpURLConnection) url.openConnection();
// Set size of every block for post
connection.setChunkedStreamingMode( 256 * 1024 ); // 256KB
// Allow Inputs & Outputs
connection.setDoInput( true );
connection.setDoOutput( true );
connection.setUseCaches( false );
// Enable POST method
connection.setRequestMethod( "POST" );
connection.setRequestProperty( "Connection" , "Keep-Alive" );
connection.setRequestProperty( "Charset" , "UTF-8" );
connection.setRequestProperty( "Content-Type" ,
"multipart/form-data;boundary=" + boundary);
outputStream = new DataOutputStream(
connection.getOutputStream());
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
outputStream
.writeBytes( "Content-Disposition: form-data; name=\"uploadedfile\";filename=\""
+ pathToOurFile + "\"" + lineEnd);
outputStream.writeBytes(lineEnd);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte [bufferSize];
// Read file
bytesRead = fileInputStream.read(buffer, 0 , bufferSize);
while (bytesRead > 0 ) {
outputStream.write(buffer, 0 , bufferSize);
length += bufferSize;
progress = ( int ) ((length * 100 ) / totalSize);
publishProgress(progress);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0 , bufferSize);
}
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(twoHyphens + boundary + twoHyphens
+ lineEnd);
publishProgress( 100 );
// Responses from the server (code and message)
int serverResponseCode = connection.getResponseCode();
String serverResponseMessage = connection.getResponseMessage();
/* 将Response显示于Dialog */
// Toast toast = Toast.makeText(UploadtestActivity.this, ""
// + serverResponseMessage.toString().trim(),
// Toast.LENGTH_LONG);
// showDialog(serverResponseMessage.toString().trim());
/* 取得Response内容 */
// InputStream is = connection.getInputStream();
// int ch;
// StringBuffer sbf = new StringBuffer();
// while ((ch = is.read()) != -1) {
// sbf.append((char) ch);
// }
//
// showDialog(sbf.toString().trim());
fileInputStream.close();
outputStream.flush();
outputStream.close();
} catch (Exception ex) {
// Exception handling
// showDialog("" + ex);
// Toast toast = Toast.makeText(UploadtestActivity.this, "" +
// ex,
// Toast.LENGTH_LONG);
}
return null ;
}
@Override
protected void onProgressUpdate(Integer... progress) {
dialog.setProgress(progress[ 0 ]);
}
@Override
protected void onPostExecute(Void result) {
try {
dialog.dismiss();
// TODO Auto-generated method stub
} catch (Exception e) {
}
}
}
}
|
服务器端仍然和之前的一样。
这里使用了AsyncTask,它使创建需要与用户界面交互的长时间运行的任务变得更简单,适用于简单的异步处理,不需要借助线程和Handler即可实现。 AsyncTask是抽象类.AsyncTask定义了三种泛型类型 Params,Progress和Result。 Params 启动任务执行的输入参数,比如HTTP请求的URL。 Progress 后台任务执行的百分比。 Result 后台执行任务最终返回的结果,比如String。 AsyncTask的执行分为四个步骤,每一步都对应一个回调方法,这些方法不应该由应用程序调用,开发者需要做的就是实现这些方法。 1) 子类化AsyncTask 2) 实现AsyncTask中定义的下面一个或几个方法 onPreExecute(), 该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。 doInBackground(Params...), 将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台计算工作。可以调用 publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。 onProgressUpdate(Progress...),在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。 onPostExecute(Result), 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread. 为了正确的使用AsyncTask类,以下是几条必须遵守的准则: 1) Task的实例必须在UI thread中创建 2) execute方法必须在UI thread中调用 3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法 4) 该task只能被执行一次,否则多次调用时将会出现异常 doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为 doInBackground接受的参数,第二个为显示进度的参数,第三个为doInBackground返回和onPostExecute传入的参数。
运行结果如下:
本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。