您的位置:首页 > 移动开发 > Android开发

上传android手机图片到服务器的方法

2012-08-29 10:27 381 查看
最近做微博开发,想实现上传图片的功能。于是写个样式,放上一些按钮和ImageView,在代码中做监听处理,这个具体就不说了。

那么如何实现上传图片的功能呢?这里有两种上传的方式,本地相册上传和拍照上传。

这两种方式都要使用startActivForResult,因为需要使用这种方式获取激活的那个Activity传回的图片地址,这里说地址不确切,实际上是URI。

至于如何激活,使用的是Intent中的action方法,我在项目中用到了两种处理方式:“本地上传”和“拍照上传”,代码如下:

picBtn = (ImageButton) findViewById(R.id.insert_pic_btn);
picBtn.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

final CharSequence[] items = { "本地上传", "拍照上传" };
AlertDialog dialog = new AlertDialog.Builder(Tweet.this)
.setTitle("选择上传方式")
.setItems(items, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
if (item == 0) {
Log.v(TAG, "本地上传 ");
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(intent,
GET_PHOTO_BY_GALLERY);
dialog.cancel();
} else if (item == 1) {

Log.v(TAG, "拍照上传 ");

Intent intent = new Intent(
"android.media.action.IMAGE_CAPTURE");

startActivityForResult(intent,
GET_PHOTO_BY_CAMERA);

dialog.cancel();
}
}
}).create();
dialog.show();
}
});
需要强调一下,这里有个陷阱,就是
private final int GET_PHOTO_BY_CAMERA = 100;
private final int GET_PHOTO_BY_GALLERY = 200;

这两个常量的值,必须大于或者等于0,否则,onActivityResult无法执行。我当时因为这个错误,摸索了一下午,更多资料,请移步:

startActivityForResult的用法

下面是onActivityResult:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == GET_PHOTO_BY_GALLERY) {
uri = data.getData();
Log.v(TAG, "uri: " + uri.toString());
ContentResolver cr = getContentResolver();
try {
mBitmap = BitmapFactory.decodeStream(cr.openInputStream(uri));
} catch (FileNotFoundException e) {

e.printStackTrace();
}

} else if (requestCode == GET_PHOTO_BY_CAMERA) {
Bundle bundle = data.getExtras();
mBitmap = (Bitmap) bundle.get("data");
Log.v(TAG, "bundle.size(): " + bundle.size());

}

super.onActivityResult(requestCode, resultCode, data);

}
}

得到Bitmap之后就可以在你的ImageView控件中显示待上传图片的缩略图了。这样设计比较人性化,因为用户选择了一张图片后,也许改变主意不想上传了,因此这里可以提供上传前的预览。贴一张效果图吧:


关键部分来了,如何把得到的图片上传到服务器呢?

光知道如何获取要上传图片的Bitmap远远不够,因为像新浪微博和腾讯微博这样的开发平台,支持的是url上传方式,那么如何获取到android手机上的或者android虚拟机上的待上传图片的url地址呢?

这里要考虑三个要素,一个是调用startActivityForResult的代码,一个是被激活的其他第三方用于选择图片的activity(如看图大师),还有一个是主调activity和她的onActivityResult方法。

在上面的代码中,对如何在startActivityForResult方法中启动第三方图片查看器和相机已经做了介绍,但是那种方法经过实际测试,只有调用本地相册时可以,调用相机拍照的那些代码无效,无法获取图片的URL地址。这里我也无法提供有效的解决办法,仍在探索中。

那我就说说如何上传从本地上册挑选出的图片吧,这里以发布一条带文字和图片的腾讯微博为例。主要的代码都在onActivityResult方法体中,不多说,直接贴代码了:

if (requestCode == GET_PHOTO_BY_GALLERY) {
uri = data.getData();
Log.v(TAG, "uri: " + uri.toString());

String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, proj, null, null, null);
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
path = cursor.getString(column_index);
Log.v(TAG, "path: " + path);

ContentResolver cr = getContentResolver();
try {
mBitmap = BitmapFactory.decodeStream(cr.openInputStream(uri));
} catch (FileNotFoundException e) {

e.printStackTrace();
}

} else if (requestCode == GET_PHOTO_BY_CAMERA) {
Bundle bundle = data.getExtras();
mBitmap = (Bitmap) bundle.get("data");
//对于使用相机上传,我这里目前只能获取到Bitmap,无法获取到URL,欢迎交流

}
从控制台打印出来的log可知,uri中的数据示例:
08-29 22:47:17.050: V/Tweet(2740): uri: content://media/external/images/media/23


经过游标跳转查找后得到的URL地址示例:
08-29 22:47:17.060: V/Tweet(2740): path: /mnt/sdcard/DCIM/Camera/C360_2012-05-19-18-22-50.jpg


很显然,根据path地址,我们就可以在手机或者虚拟机的SD卡中找到这张图片,这个地址就是发布微博时需要上传的参数之一,至于发布微博的代码我就不多啰嗦了,有兴趣的可以加我QQ:676395711,欢迎交流。

现在,我还是不甘心,明明计划实现本地上传和拍照上传的功能。但是,到了拍照上传就卡壳了,我原先使用的代码是这样的,不过这段代码是错的:

if (item == 1) {

// this.TEMP_IMG_DIR.mkdirs();
File dir = Environment.getExternalStorageDirectory();
String fileName = String.valueOf(System.currentTimeMillis()) + ".jpg";
File file = new File(dir, fileName);
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
Uri uri = Uri.fromFile(file);
intent.putExtra("output", uri);
startActivityForResult(intent,GET_PHOTO_BY_CAMERA);
Log.v(TAG, "拍照上传 ");
dialog.cancel();
}


虽然是错的,可以看出这段代码表达的意思是,先在SD卡中建立一个文件,文件名是以系统当前时间命名的,以防止重名。然后调用第三方拍照软件,拍完照片后,把照片保存到先前指定的路径。然后在onActivityResult方法中使用如下代码获取path值,当然这段代码也是错误的:

if (requestCode == GET_PHOTO_BY_CAMERA) {
Bundle bundle = data.getExtras();
mBitmap = (Bitmap) bundle.get("data");
uri = data.getData();
Log.v(TAG, "uri: " + uri.toString());

String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, proj, null, null, null);
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
path = cursor.getString(column_index);
Log.v(TAG, "path: " + path);

}
然后就需要说说我控制台里打印出的错误信息了:
08-29 22:51:02.040: E/AndroidRuntime(3251): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=100, result=-1, data=Intent { act=inline-data (has extras) }} to activity {com.example.testphoto/com.example.testphoto.Tweet}: java.lang.NullPointerException
08-29 22:51:02.040: E/AndroidRuntime(3251): 	at android.app.ActivityThread.deliverResults(ActivityThread.java:2653)
08-29 22:51:02.040: E/AndroidRuntime(3251): 	at android.app.ActivityThread.handleSendResult(ActivityThread.java:2695)
08-29 22:51:02.040: E/AndroidRuntime(3251): 	at android.app.ActivityThread.access$2000(ActivityThread.java:123)
08-29 22:51:02.040: E/AndroidRuntime(3251): 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:969)
08-29 22:51:02.040: E/AndroidRuntime(3251): 	at android.os.Handler.dispatchMessage(Handler.java:99)
08-29 22:51:02.040: E/AndroidRuntime(3251): 	at android.os.Looper.loop(Looper.java:130)
08-29 22:51:02.040: E/AndroidRuntime(3251): 	at android.app.ActivityThread.main(ActivityThread.java:3835)
08-29 22:51:02.040: E/AndroidRuntime(3251): 	at java.lang.reflect.Method.invokeNative(Native Method)
08-29 22:51:02.040: E/AndroidRuntime(3251): 	at java.lang.reflect.Method.invoke(Method.java:507)
08-29 22:51:02.040: E/AndroidRuntime(3251): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
08-29 22:51:02.040: E/AndroidRuntime(3251): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
08-29 22:51:02.040: E/AndroidRuntime(3251): 	at dalvik.system.NativeStart.main(Native Method)
08-29 22:51:02.040: E/AndroidRuntime(3251): Caused by: java.lang.NullPointerException
08-29 22:51:02.040: E/AndroidRuntime(3251): 	at com.example.testphoto.Tweet.onActivityResult(Tweet.java:100)
08-29 22:51:02.040: E/AndroidRuntime(3251): 	at android.app.Activity.dispatchActivityResult(Activity.java:3908)
08-29 22:51:02.040: E/AndroidRuntime(3251): 	at android.app.ActivityThread.deliverResults(ActivityThread.java:2649)

弄了大半天,也没整明白,希望知道如何处理的朋友告诉我一声。

那么,既然我这里得到了拍照上传时的Bitmap数据,那么能不能把bitmap保存成图片到指定的本地路径,然后在把这个路径作为上传的参数呢?

因为图片的路径是自己指定的,图片的名字也是自己指定的,貌似这样是可以的。处理的代码在下面,不过我没有测试,不保证一定能用:
public void saveBitmap(String bitName) throws IOException {
File f = new File("/sdcard/Note/" + bitName + ".png");
f.createNewFile();
FileOutputStream out = null;
try {
out = new FileOutputStream(f);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
mBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
try {
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
未完待续~

参考资料:


android中实现将图片上传到服务器的问题

android 拍照上传及本地上传

【Android】本地图片选择(打开媒体库,选择图片)

希望能帮到你

(完)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: