Android仿QQ空间发说说实现上传图片到服务器(带缩略图的)
2016-11-25 13:36
633 查看
之前做别的项目的时候游泳到过,好久不用都生疏了。今天朋友问我这个问题我仔细看了一下,发现问题并改正了。下面是实现这个功能的全部代码(PS:界面很丑不用管,好看的我没传,大家自己写一下就好)
服务端:
需要两个jar包:(这两个是必须的)
commons-fileupload-1.2.jar
commons-io-2.0.1.jar
代码:
[java] view
plain copy
print?
<span style="font-family:KaiTi_GB2312;font-size:18px;">import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
/**
* 文件上传的Serlvet类
*
*/
public class FileImageUpload extends HttpServlet {
private static final long serialVersionUID = 1L;
private ServletFileUpload upload;
private final long MAXSize = 4194304*2L;//4*2MB
private String filedir;
/**
* @see HttpServlet#HttpServlet()
*/
public FileImageUpload() {
super();
// TODO Auto-generated constructor stub
}
/**
* 设置文件上传的初始化信息
* @see Servlet#init(ServletConfig)
*/
public void init(ServletConfig config) throws ServletException {
// Create a factory for disk-based file items
FileItemFactory factory = new DiskFileItemFactory();
// Create a new file upload handler
this.upload = new ServletFileUpload(factory);
// Set overall request size constraint 4194304
this.upload.setSizeMax(this.MAXSize);
// File file = new File(pathname);
filedir=config.getServletContext().getRealPath("images");
File file = new File(filedir);
if (!file.exists()) {
//创建临时目录
file.mkdir();
}
}
// @SuppressWarnings("unchecked")
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
PrintWriter out=response.getWriter();
try {
List<FileItem> items = this.upload.parseRequest(request);
if(items!=null && !items.isEmpty()){
for (FileItem fileItem : items) {
System.out.println(fileItem);
String filename=fileItem.getName();
String filepath=filedir+File.separator+filename;
System.out.println("文件保存路径为:"+filepath);
File file=new File(filepath);
InputStream inputSteam=fileItem.getInputStream();
BufferedInputStream fis=new BufferedInputStream(inputSteam);
FileOutputStream fos=new FileOutputStream(file);
int f;
while((f=fis.read())!=-1)
{
fos.write(f);
}
fos.flush();
fos.close();
fis.close();
inputSteam.close();
System.out.println("文件:"+filename+"上传成功!");
}
}
System.out.println("上传文件成功!");
out.write("上传文件成功!");
} catch (FileUploadException e) {
e.printStackTrace();
out.write("上传文件失败:"+e.getMessage());
}
}
}</span>
客户端:
布局代码:
activity_main.xml
[java] view
plain copy
print?
<span style="font-family:KaiTi_GB2312;font-size:18px;"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.girdviewtest.MainActivity" >
<!-- 显示图片 -->
<!-- 网格显示图片 行列间距5dp 每列宽度90dp -->
<GridView
android:id="@+id/gridView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="111"
android:background="#EFDFDF"
android:columnWidth="90dp"
android:gravity="center"
android:horizontalSpacing="5dp"
android:numColumns="4"
android:stretchMode="columnWidth"
android:verticalSpacing="5dp" >
</GridView>
<!-- 底部按钮 -->
<LinearLayout
android:id="@+id/Layout_bottom"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_weight="1"
android:orientation="horizontal" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="1"
android:onClick="button1"
android:text="上传"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout></span>
griditem_addpic.xml
[java] view
plain copy
print?
<span style="font-family:KaiTi_GB2312;font-size:18px;"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:descendantFocusability="blocksDescendants"
android:orientation="vertical" >
<RelativeLayout
android:layout_gravity="center"
android:layout_width="85dp"
android:layout_height="85dp"
android:orientation="vertical" >
<ImageView
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:id="@+id/imageView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitXY"
android:src="@drawable/gridview_addpic" />
</RelativeLayout>
</LinearLayout></span>
Java代码:
UploadUtils.Java
[java] view
plain copy
print?
<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.example.androiduploadfile;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.UUID;
import android.util.Log;
/**
*
* 实现文件上传的工具类
*/
public class UploadUtils {
private static final String TAG = "uploadFile";
private static final int TIME_OUT = 10*10000000; //超时时间
private static final String CHARSET = "utf-8"; //设置编码
public static final String SUCCESS="1";
public static final String FAILURE="0";
/**
* android上传文件到服务器
* @param file 需要上传的文件
* @param RequestURL 请求的rul
* @return 返回响应的内容
*/
public static String uploadFile(File file,String RequestURL)
{
String BOUNDARY = UUID.randomUUID().toString(); //边界标识 随机生成
String PREFIX = "--" , LINE_END = "\r\n";
String CONTENT_TYPE = "multipart/form-data"; //内容类型
try {
URL url = new URL(RequestURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(TIME_OUT);
conn.setConnectTimeout(TIME_OUT);
conn.setDoInput(true); //允许输入流
conn.setDoOutput(true); //允许输出流
conn.setUseCaches(false); //不允许使用缓存
conn.setRequestMethod("POST"); //请求方式
conn.setRequestProperty("Charset", CHARSET); //设置编码
conn.setRequestProperty("connection", "keep-alive");
conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);
if(file!=null)
{
/**
* 当文件不为空,把文件包装并且上传
*/
OutputStream outputSteam=conn.getOutputStream();
DataOutputStream dos = new DataOutputStream(outputSteam);
StringBuffer sb = new StringBuffer();
sb.append(PREFIX);
sb.append(BOUNDARY);
sb.append(LINE_END);
/**
* 这里重点注意:
* name里面的值为服务器端需要key 只有这个key 才可以得到对应的文件
* filename是文件的名字,包含后缀名的 比如:abc.png
*/
sb.append("Content-Disposition: form-data; name=\"img\"; filename=\""+file.getName()+"\""+LINE_END);
sb.append("Content-Type: application/octet-stream; charset="+CHARSET+LINE_END);
sb.append(LINE_END);
dos.write(sb.toString().getBytes());
InputStream is = new FileInputStream(file);
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();
Log.e(TAG, "response code:"+res);
if(res==200)
{
return SUCCESS;
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return FAILURE;
}
}</span>
UploadFileTask.java
使用到了异步加载
AsyncTask的用法 在开发Android应用时必须遵守单线程模型的原则:
Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。在单线程模型中始终要记住两条法则: 1. 不要阻塞UI线程 2.确保只在UI线程中访问Android UI工具包 当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。比如说从网上获取一个网页,在一个TextView中将其源代码显示出来,这种涉及到网络操作的程序一般都是需要开一个线程完成网络访问,但是在获得页面源码后, 是不能直接在网络操作线程中调用TextView.setText()的.因为其他线程中是不能直接访问主UI线程成员
。
android提供了几种在其他线程中访问UI线程的方法。 Activity.runOnUiThread( Runnable ) View.post(Runnable ) View.postDelayed( Runnable, long ) Hanlder这些类或方法同样会使你的代码很复杂很难理解。然而当你需要实现一些很复杂的操作并需要频繁地更新UI时这会变得更糟糕。
为了解决这个问题,Android 1.5提供了一个工具类:AsyncTask,它使创建需要与用户界面交互的长时间运行的任务变得更简单。相对来说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传入的参数。
[java] view
plain copy
print?
<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.example.androiduploadfile;
import java.io.File;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.widget.Toast;
public class UploadFileTask extends AsyncTask<String, Void, String> {
public static final String requestURL = "http://192.168.47.114:8080/UploadFileWeb/servlet/FileImageUpload";
/**
* 可变长的输入参数,与AsyncTask.exucute()对应
*/
private ProgressDialog pdialog;
private Activity context = null;
public UploadFileTask(Activity ctx) {
this.context = ctx;
pdialog = ProgressDialog.show(context, "正在加载...", "系统正在处理您的请求");
}
@Override
protected void onPostExecute(String result) {
// 返回HTML页面的内容
pdialog.dismiss();
if (UploadUtils.SUCCESS.equalsIgnoreCase(result)) {
Toast.makeText(context, "上传成功!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "上传失败!", Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onPreExecute() {
}
@Override
protected void onCancelled() {
super.onCancelled();
}
@Override
protected String doInBackground(String... params) {
File file = new File(params[0]);
return UploadUtils.uploadFile(file, requestURL);
}
@Override
protected void onProgressUpdate(Void... values) {
}
}</span>
MainActivity.java
[java] view
plain copy
print?
<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.example.androiduploadfile;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.SimpleAdapter;
import android.widget.SimpleAdapter.ViewBinder;
import android.widget.Toast;
/**
*
* @author yu_longji
*
*/
public class MainActivity extends Activity {
private GridView gridView1; // 网格显示缩略图
private final int IMAGE_OPEN = 1; // 打开图片标记
private String pathImage; // 选择图片路径
private Bitmap bmp; // 导入临时图片
private ArrayList<HashMap<String, Object>> imageItem;
private SimpleAdapter simpleAdapter; // 适配器
private List<String> list;
String uploadFile = "";
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
switch (msg.what) {
case 1:
String b = (String) msg.obj;
Toast.makeText(MainActivity.this, b, Toast.LENGTH_SHORT).show();
break;
case 0:
String string = (String) msg.obj;
Toast.makeText(MainActivity.this, string, Toast.LENGTH_SHORT)
.show();
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*
* 防止键盘挡住输入框 不希望遮挡设置activity属性 android:windowSoftInputMode="adjustPan"
* 希望动态调整高度 android:windowSoftInputMode="adjustResize"
*/
getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
// 锁定屏幕
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(R.layout.activity_main);
list = new ArrayList<>();
// 获取控件对象
gridView1 = (GridView) findViewById(R.id.gridView1);
/*
* 载入默认图片添加图片加号 通过适配器实现 SimpleAdapter参数imageItem为数据源
* R.layout.griditem_addpic为布局
*/
bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.gridview_addpic); // 加号
imageItem = new ArrayList<HashMap<String, Object>>();
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("itemImage", bmp);
imageItem.add(map);
simpleAdapter = new SimpleAdapter(this, imageItem,
R.layout.griditem_addpic, new String[] { "itemImage" },
new int[] { R.id.imageView1 });
/*
* HashMap载入bmp图片在GridView中不显示,但是如果载入资源ID能显示 如 map.put("itemImage",
* R.drawable.img); 解决方法: 1.自定义继承BaseAdapter实现 2.ViewBinder()接口实现
*/
simpleAdapter.setViewBinder(new ViewBinder() {
@Override
public boolean setViewValue(View view, Object data,
String textRepresentation) {
// TODO Auto-generated method stub
if (view instanceof ImageView && data instanceof Bitmap) {
ImageView i = (ImageView) view;
i.setImageBitmap((Bitmap) data);
return true;
}
return false;
}
});
gridView1.setAdapter(simpleAdapter);
/*
* 监听GridView点击事件 报错:该函数必须抽象方法 故需要手动导入import android.view.View;
*/
gridView1.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
if (position == 0) { // 点击图片位置为+ 0对应0张图片
Toast.makeText(MainActivity.this, "添加图片",
Toast.LENGTH_SHORT).show();
// 选择图片
Intent intent = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, IMAGE_OPEN);
// 通过onResume()刷新数据
} else {
dialog(position);
Toast.makeText(MainActivity.this,
"点击第" + position + 1 + " 号图片", Toast.LENGTH_SHORT)
.show();
}
}
});
}
// 获取图片路径 响应startActivityForResult
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// 打开图片
if (resultCode == RESULT_OK && requestCode == IMAGE_OPEN) {
Uri uri = data.getData();
if (!TextUtils.isEmpty(uri.getAuthority())) {
// 查询选择图片
Cursor cursor = getContentResolver().query(uri,
new String[] { MediaStore.Images.Media.DATA }, null,
null, null);
// 返回 没找到选择图片
if (null == cursor) {
return;
}
// 光标移动至开头 获取图片路径
cursor.moveToFirst();
pathImage = cursor.getString(cursor
.getColumnIndex(MediaStore.Images.Media.DATA));
list.add(pathImage);
}
} // end if 打开图片
}
// 提交发布
public void button1(View view) {
for (int i = 0; i < list.size(); i++) {
uploadFile = list.get(i);
System.out.println(uploadFile);
if (uploadFile != null && uploadFile.length() > 0) {
UploadFileTask uploadFileTask = new UploadFileTask(this);
uploadFileTask.execute(uploadFile);
}
}
}
// 刷新图片
@Override
protected void onResume() {
super.onResume();
if (!TextUtils.isEmpty(pathImage)) {
Bitmap addbmp = BitmapFactory.decodeFile(pathImage);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("itemImage", addbmp);
imageItem.add(map);
simpleAdapter = new SimpleAdapter(this, imageItem,
R.layout.griditem_addpic, new String[] { "itemImage" },
new int[] { R.id.imageView1 });
simpleAdapter.setViewBinder(new ViewBinder() {
@Override
public boolean setViewValue(View view, Object data,
String textRepresentation) {
// TODO Auto-generated method stub
if (view instanceof ImageView && data instanceof Bitmap) {
ImageView i = (ImageView) view;
i.setImageBitmap((Bitmap) data);
return true;
}
return false;
}
});
gridView1.setAdapter(simpleAdapter);
simpleAdapter.notifyDataSetChanged();
// 刷新后释放防止手机休眠后自动添加
pathImage = null;
}
}
/*
* Dialog对话框提示用户删除操作 position为删除图片位置
*/
protected void dialog(final int position) {
String string = "是否删除该图片";
AlertDialog.Builder builder = new Builder(MainActivity.this);
builder.setMessage(string);
builder.setTitle("提示");
builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
imageItem.remove(position);
list.remove(position - 1);
simpleAdapter.notifyDataSetChanged();
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.create().show();
}
}
</span>
服务端:
需要两个jar包:(这两个是必须的)
commons-fileupload-1.2.jar
commons-io-2.0.1.jar
代码:
[java] view
plain copy
print?
<span style="font-family:KaiTi_GB2312;font-size:18px;">import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
/**
* 文件上传的Serlvet类
*
*/
public class FileImageUpload extends HttpServlet {
private static final long serialVersionUID = 1L;
private ServletFileUpload upload;
private final long MAXSize = 4194304*2L;//4*2MB
private String filedir;
/**
* @see HttpServlet#HttpServlet()
*/
public FileImageUpload() {
super();
// TODO Auto-generated constructor stub
}
/**
* 设置文件上传的初始化信息
* @see Servlet#init(ServletConfig)
*/
public void init(ServletConfig config) throws ServletException {
// Create a factory for disk-based file items
FileItemFactory factory = new DiskFileItemFactory();
// Create a new file upload handler
this.upload = new ServletFileUpload(factory);
// Set overall request size constraint 4194304
this.upload.setSizeMax(this.MAXSize);
// File file = new File(pathname);
filedir=config.getServletContext().getRealPath("images");
File file = new File(filedir);
if (!file.exists()) {
//创建临时目录
file.mkdir();
}
}
// @SuppressWarnings("unchecked")
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
PrintWriter out=response.getWriter();
try {
List<FileItem> items = this.upload.parseRequest(request);
if(items!=null && !items.isEmpty()){
for (FileItem fileItem : items) {
System.out.println(fileItem);
String filename=fileItem.getName();
String filepath=filedir+File.separator+filename;
System.out.println("文件保存路径为:"+filepath);
File file=new File(filepath);
InputStream inputSteam=fileItem.getInputStream();
BufferedInputStream fis=new BufferedInputStream(inputSteam);
FileOutputStream fos=new FileOutputStream(file);
int f;
while((f=fis.read())!=-1)
{
fos.write(f);
}
fos.flush();
fos.close();
fis.close();
inputSteam.close();
System.out.println("文件:"+filename+"上传成功!");
}
}
System.out.println("上传文件成功!");
out.write("上传文件成功!");
} catch (FileUploadException e) {
e.printStackTrace();
out.write("上传文件失败:"+e.getMessage());
}
}
}</span>
客户端:
布局代码:
activity_main.xml
[java] view
plain copy
print?
<span style="font-family:KaiTi_GB2312;font-size:18px;"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.girdviewtest.MainActivity" >
<!-- 显示图片 -->
<!-- 网格显示图片 行列间距5dp 每列宽度90dp -->
<GridView
android:id="@+id/gridView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="111"
android:background="#EFDFDF"
android:columnWidth="90dp"
android:gravity="center"
android:horizontalSpacing="5dp"
android:numColumns="4"
android:stretchMode="columnWidth"
android:verticalSpacing="5dp" >
</GridView>
<!-- 底部按钮 -->
<LinearLayout
android:id="@+id/Layout_bottom"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_weight="1"
android:orientation="horizontal" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="1"
android:onClick="button1"
android:text="上传"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout></span>
griditem_addpic.xml
[java] view
plain copy
print?
<span style="font-family:KaiTi_GB2312;font-size:18px;"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:descendantFocusability="blocksDescendants"
android:orientation="vertical" >
<RelativeLayout
android:layout_gravity="center"
android:layout_width="85dp"
android:layout_height="85dp"
android:orientation="vertical" >
<ImageView
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:id="@+id/imageView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitXY"
android:src="@drawable/gridview_addpic" />
</RelativeLayout>
</LinearLayout></span>
Java代码:
UploadUtils.Java
[java] view
plain copy
print?
<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.example.androiduploadfile;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.UUID;
import android.util.Log;
/**
*
* 实现文件上传的工具类
*/
public class UploadUtils {
private static final String TAG = "uploadFile";
private static final int TIME_OUT = 10*10000000; //超时时间
private static final String CHARSET = "utf-8"; //设置编码
public static final String SUCCESS="1";
public static final String FAILURE="0";
/**
* android上传文件到服务器
* @param file 需要上传的文件
* @param RequestURL 请求的rul
* @return 返回响应的内容
*/
public static String uploadFile(File file,String RequestURL)
{
String BOUNDARY = UUID.randomUUID().toString(); //边界标识 随机生成
String PREFIX = "--" , LINE_END = "\r\n";
String CONTENT_TYPE = "multipart/form-data"; //内容类型
try {
URL url = new URL(RequestURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(TIME_OUT);
conn.setConnectTimeout(TIME_OUT);
conn.setDoInput(true); //允许输入流
conn.setDoOutput(true); //允许输出流
conn.setUseCaches(false); //不允许使用缓存
conn.setRequestMethod("POST"); //请求方式
conn.setRequestProperty("Charset", CHARSET); //设置编码
conn.setRequestProperty("connection", "keep-alive");
conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);
if(file!=null)
{
/**
* 当文件不为空,把文件包装并且上传
*/
OutputStream outputSteam=conn.getOutputStream();
DataOutputStream dos = new DataOutputStream(outputSteam);
StringBuffer sb = new StringBuffer();
sb.append(PREFIX);
sb.append(BOUNDARY);
sb.append(LINE_END);
/**
* 这里重点注意:
* name里面的值为服务器端需要key 只有这个key 才可以得到对应的文件
* filename是文件的名字,包含后缀名的 比如:abc.png
*/
sb.append("Content-Disposition: form-data; name=\"img\"; filename=\""+file.getName()+"\""+LINE_END);
sb.append("Content-Type: application/octet-stream; charset="+CHARSET+LINE_END);
sb.append(LINE_END);
dos.write(sb.toString().getBytes());
InputStream is = new FileInputStream(file);
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();
Log.e(TAG, "response code:"+res);
if(res==200)
{
return SUCCESS;
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return FAILURE;
}
}</span>
UploadFileTask.java
使用到了异步加载
AsyncTask的用法 在开发Android应用时必须遵守单线程模型的原则:
Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。在单线程模型中始终要记住两条法则: 1. 不要阻塞UI线程 2.确保只在UI线程中访问Android UI工具包 当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。比如说从网上获取一个网页,在一个TextView中将其源代码显示出来,这种涉及到网络操作的程序一般都是需要开一个线程完成网络访问,但是在获得页面源码后, 是不能直接在网络操作线程中调用TextView.setText()的.因为其他线程中是不能直接访问主UI线程成员
。
android提供了几种在其他线程中访问UI线程的方法。 Activity.runOnUiThread( Runnable ) View.post(Runnable ) View.postDelayed( Runnable, long ) Hanlder这些类或方法同样会使你的代码很复杂很难理解。然而当你需要实现一些很复杂的操作并需要频繁地更新UI时这会变得更糟糕。
为了解决这个问题,Android 1.5提供了一个工具类:AsyncTask,它使创建需要与用户界面交互的长时间运行的任务变得更简单。相对来说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传入的参数。
[java] view
plain copy
print?
<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.example.androiduploadfile;
import java.io.File;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.widget.Toast;
public class UploadFileTask extends AsyncTask<String, Void, String> {
public static final String requestURL = "http://192.168.47.114:8080/UploadFileWeb/servlet/FileImageUpload";
/**
* 可变长的输入参数,与AsyncTask.exucute()对应
*/
private ProgressDialog pdialog;
private Activity context = null;
public UploadFileTask(Activity ctx) {
this.context = ctx;
pdialog = ProgressDialog.show(context, "正在加载...", "系统正在处理您的请求");
}
@Override
protected void onPostExecute(String result) {
// 返回HTML页面的内容
pdialog.dismiss();
if (UploadUtils.SUCCESS.equalsIgnoreCase(result)) {
Toast.makeText(context, "上传成功!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "上传失败!", Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onPreExecute() {
}
@Override
protected void onCancelled() {
super.onCancelled();
}
@Override
protected String doInBackground(String... params) {
File file = new File(params[0]);
return UploadUtils.uploadFile(file, requestURL);
}
@Override
protected void onProgressUpdate(Void... values) {
}
}</span>
MainActivity.java
[java] view
plain copy
print?
<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.example.androiduploadfile;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.SimpleAdapter;
import android.widget.SimpleAdapter.ViewBinder;
import android.widget.Toast;
/**
*
* @author yu_longji
*
*/
public class MainActivity extends Activity {
private GridView gridView1; // 网格显示缩略图
private final int IMAGE_OPEN = 1; // 打开图片标记
private String pathImage; // 选择图片路径
private Bitmap bmp; // 导入临时图片
private ArrayList<HashMap<String, Object>> imageItem;
private SimpleAdapter simpleAdapter; // 适配器
private List<String> list;
String uploadFile = "";
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
switch (msg.what) {
case 1:
String b = (String) msg.obj;
Toast.makeText(MainActivity.this, b, Toast.LENGTH_SHORT).show();
break;
case 0:
String string = (String) msg.obj;
Toast.makeText(MainActivity.this, string, Toast.LENGTH_SHORT)
.show();
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*
* 防止键盘挡住输入框 不希望遮挡设置activity属性 android:windowSoftInputMode="adjustPan"
* 希望动态调整高度 android:windowSoftInputMode="adjustResize"
*/
getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
// 锁定屏幕
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(R.layout.activity_main);
list = new ArrayList<>();
// 获取控件对象
gridView1 = (GridView) findViewById(R.id.gridView1);
/*
* 载入默认图片添加图片加号 通过适配器实现 SimpleAdapter参数imageItem为数据源
* R.layout.griditem_addpic为布局
*/
bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.gridview_addpic); // 加号
imageItem = new ArrayList<HashMap<String, Object>>();
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("itemImage", bmp);
imageItem.add(map);
simpleAdapter = new SimpleAdapter(this, imageItem,
R.layout.griditem_addpic, new String[] { "itemImage" },
new int[] { R.id.imageView1 });
/*
* HashMap载入bmp图片在GridView中不显示,但是如果载入资源ID能显示 如 map.put("itemImage",
* R.drawable.img); 解决方法: 1.自定义继承BaseAdapter实现 2.ViewBinder()接口实现
*/
simpleAdapter.setViewBinder(new ViewBinder() {
@Override
public boolean setViewValue(View view, Object data,
String textRepresentation) {
// TODO Auto-generated method stub
if (view instanceof ImageView && data instanceof Bitmap) {
ImageView i = (ImageView) view;
i.setImageBitmap((Bitmap) data);
return true;
}
return false;
}
});
gridView1.setAdapter(simpleAdapter);
/*
* 监听GridView点击事件 报错:该函数必须抽象方法 故需要手动导入import android.view.View;
*/
gridView1.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
if (position == 0) { // 点击图片位置为+ 0对应0张图片
Toast.makeText(MainActivity.this, "添加图片",
Toast.LENGTH_SHORT).show();
// 选择图片
Intent intent = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, IMAGE_OPEN);
// 通过onResume()刷新数据
} else {
dialog(position);
Toast.makeText(MainActivity.this,
"点击第" + position + 1 + " 号图片", Toast.LENGTH_SHORT)
.show();
}
}
});
}
// 获取图片路径 响应startActivityForResult
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// 打开图片
if (resultCode == RESULT_OK && requestCode == IMAGE_OPEN) {
Uri uri = data.getData();
if (!TextUtils.isEmpty(uri.getAuthority())) {
// 查询选择图片
Cursor cursor = getContentResolver().query(uri,
new String[] { MediaStore.Images.Media.DATA }, null,
null, null);
// 返回 没找到选择图片
if (null == cursor) {
return;
}
// 光标移动至开头 获取图片路径
cursor.moveToFirst();
pathImage = cursor.getString(cursor
.getColumnIndex(MediaStore.Images.Media.DATA));
list.add(pathImage);
}
} // end if 打开图片
}
// 提交发布
public void button1(View view) {
for (int i = 0; i < list.size(); i++) {
uploadFile = list.get(i);
System.out.println(uploadFile);
if (uploadFile != null && uploadFile.length() > 0) {
UploadFileTask uploadFileTask = new UploadFileTask(this);
uploadFileTask.execute(uploadFile);
}
}
}
// 刷新图片
@Override
protected void onResume() {
super.onResume();
if (!TextUtils.isEmpty(pathImage)) {
Bitmap addbmp = BitmapFactory.decodeFile(pathImage);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("itemImage", addbmp);
imageItem.add(map);
simpleAdapter = new SimpleAdapter(this, imageItem,
R.layout.griditem_addpic, new String[] { "itemImage" },
new int[] { R.id.imageView1 });
simpleAdapter.setViewBinder(new ViewBinder() {
@Override
public boolean setViewValue(View view, Object data,
String textRepresentation) {
// TODO Auto-generated method stub
if (view instanceof ImageView && data instanceof Bitmap) {
ImageView i = (ImageView) view;
i.setImageBitmap((Bitmap) data);
return true;
}
return false;
}
});
gridView1.setAdapter(simpleAdapter);
simpleAdapter.notifyDataSetChanged();
// 刷新后释放防止手机休眠后自动添加
pathImage = null;
}
}
/*
* Dialog对话框提示用户删除操作 position为删除图片位置
*/
protected void dialog(final int position) {
String string = "是否删除该图片";
AlertDialog.Builder builder = new Builder(MainActivity.this);
builder.setMessage(string);
builder.setTitle("提示");
builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
imageItem.remove(position);
list.remove(position - 1);
simpleAdapter.notifyDataSetChanged();
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.create().show();
}
}
</span>
相关文章推荐
- Android开发:仿微信和QQ空间发说说相册读取、拍照、图片裁剪和图片上传服务器等功能的实现
- android批量上传图片(模仿QQ空间和微信发表说说)
- Android-客户端上传多张图片到服务器功能实现
- android 实现图片上传功能 Tomcat作为服务器
- android实现拖动上传图片和文字至服务器
- Base64Coder方式实现android向jsp服务器后台上传图片
- Android 通过Base64上传图片到服务器实现实例
- 服务器基于PHP CodeIgniter,Android基于Volley实现多文件/图片上传(含服务器,web版和android客户端完整代码)
- jQuery上传文件到服务器,实现量上传及压缩包导入,支持Office文档、PDF、图像、音视频和图纸等各类型文件。上传完成后系统自动为图片、音、视频类文件增加摘要及缩略图
- Android实现多图上传 QQ发说说图片上传 朋友圈图片上传
- Android开发:相册读取、拍照、图片裁剪和图片上传服务器等功能的实现
- Android实现上传图片至java服务器
- android实现简单的图片上传服务器
- Android简单实现将手机图片上传到服务器中
- Android 上传图片,服务器接收图片实现
- Android如何实现压缩图片后再上传至服务器
- 自定义控件实现无刷新上传图片,立即显示缩略图,保存图片缩略图<原创>
- Android上传图片至服务器
- 如何实现ASP上传图片自动生成缩略图
- swfupload实现图片及缩略图上传