Android图片上传(头像裁切+原图原样)

先看一下效果图:

(一)头像裁切、上传服务器(效果图)

一般都是有圆形显示头像的,这里我自定义了一个ImageView,页面很干净但是看着很上档次吧!

点击头像从底部弹出一个对话框,提示用户头像来自相机或者相册,这都是常规流程。

上传完成后默认的“程序员头像”换成了萌妹子

(二)普通图片上传服务器(效果图)

模仿QQ空间发动态的布局随意捏造一个界面出来

点击添加图片从底部弹出一个对话框,提示用户图片来自相机或者相册,这也都是常规流程。

上传过程中,有可能图片很大,显示一个进度圈(其实头像上传也有,只是文件小,还没显示就上传完成了)

上传完成后把刚才的照片亮出来显示到按钮的地方,当然大家根据需要还可以自己扩展(比如长按抖动出现删除、继续添加N张等等)。

下面简单铺一下代码:

(一)头像裁切、上传服务器(代码)

这里上边的按钮是头像的点击事件,弹出底部的头像选择框,下边的按钮跳到下个页面,进行原图上传。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16@Override

publicvoidonClick(View v) {

switch(v.getId()) {

caseR.id.avatarImg:// 更换头像点击事件

menuWindow =newSelectPicPopupWindow(mContext, itemsOnClick);

menuWindow.showAtLocation(findViewById(R.id.mainLayout),

Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL,0,0);

break;

caseR.id.loginBtn://登录按钮跳转事件

startActivity(newIntent(mContext, UploadActivity.class));

break;

default:

break;

}

}

弹出窗绑定一个按钮事件

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26//为弹出窗口实现监听类

privateOnClickListener itemsOnClick =newOnClickListener() {

@Override

publicvoidonClick(View v) {

menuWindow.dismiss();

switch(v.getId()) {

// 拍照

caseR.id.takePhotoBtn:

Intent takeIntent =newIntent(MediaStore.ACTION_IMAGE_CAPTURE);

//下面这句指定调用相机拍照后的照片存储的路径

takeIntent.putExtra(MediaStore.EXTRA_OUTPUT,

Uri.fromFile(newFile(Environment.getExternalStorageDirectory(), IMAGE_FILE_NAME)));

startActivityForResult(takeIntent, REQUESTCODE_TAKE);

break;

// 相册选择图片

caseR.id.pickPhotoBtn:

Intent pickIntent =newIntent(Intent.ACTION_PICK,null);

// 如果朋友们要限制上传到服务器的图片类型时可以直接写如:image/jpeg 、 image/png等的类型

pickIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, image/*);

startActivityForResult(pickIntent, REQUESTCODE_PICK);

break;

default:

break;

}

}

};

为图像选取返回的接收处理

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23@Override

publicvoidonActivityResult(intrequestCode,intresultCode, Intent data) {

switch(requestCode) {

caseREQUESTCODE_PICK:// 直接从相册获取

try{

startPhotoZoom(data.getData());

}catch(NullPointerException e) {

e.printStackTrace();// 用户点击取消操作

}

break;

caseREQUESTCODE_TAKE:// 调用相机拍照

File temp =newFile(Environment.getExternalStorageDirectory() + / + IMAGE_FILE_NAME);

startPhotoZoom(Uri.fromFile(temp));

break;

caseREQUESTCODE_CUTTING:// 取得裁剪后的图片

if(data !=null) {

setPicToView(data);

}

break;

}

super.onActivityResult(requestCode, resultCode, data);

}

把图片显示出来,然后上传

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140/**

* 裁剪图片方法实现

* @param uri

*/

publicvoidstartPhotoZoom(Uri uri) {

Intent intent =newIntent(com.android.camera.action.CROP);

intent.setDataAndType(uri, image/*);

// crop=true是设置在开启的Intent中设置显示的VIEW可裁剪

intent.putExtra(crop, true);

// aspectX aspectY 是宽高的比例

intent.putExtra(aspectX, 1);

intent.putExtra(aspectY, 1);

// outputX outputY 是裁剪图片宽高

intent.putExtra(outputX, 300);

intent.putExtra(outputY, 300);

intent.putExtra(return-data, true);

startActivityForResult(intent, REQUESTCODE_CUTTING);

}

/**

* 保存裁剪之后的图片数据

* @param picdata

*/

privatevoidsetPicToView(Intent picdata) {

Bundle extras = picdata.getExtras();

if(extras !=null) {

// 取得SDCard图片路径做显示

Bitmap photo = extras.getParcelable(data);

Drawable drawable =newBitmapDrawable(null, photo);

urlpath = FileUtil.saveFile(mContext, temphead.jpg, photo);

avatarImg.setImageDrawable(drawable);

// 新线程后台上传服务端

pd = ProgressDialog.show(mContext,null, 正在上传图片,请稍候...);

newThread(uploadImageRunnable).start();

}

}

/**

* 使用HttpUrlConnection模拟post表单进行文件

* 上传平时很少使用,比较麻烦

* 原理是: 分析文件上传的数据格式,然后根据格式构造相应的发送给服务器的字符串。

*/

Runnable uploadImageRunnable =newRunnable() {

@Override

publicvoidrun() {

if(TextUtils.isEmpty(imgUrl)){

Toast.makeText(mContext, 还没有设置上传服务器的路径!, Toast.LENGTH_SHORT).show();

return;

}

Map textParams =newHashMap();

Map fileparams =newHashMap();

try{

// 创建一个URL对象

URL url =newURL(imgUrl);

textParams =newHashMap();

fileparams =newHashMap();

// 要上传的图片文件

File file =newFile(urlpath);

fileparams.put(image, file);

// 利用HttpURLConnection对象从网络中获取网页数据

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

// 设置连接超时(记得设置连接超时,如果网络不好,Android系统在超过默认时间会收回资源中断操作)

conn.setConnectTimeout(5000);

// 设置允许输出(发送POST请求必须设置允许输出)

conn.setDoOutput(true);

// 设置使用POST的方式发送

conn.setRequestMethod(POST);

// 设置不使用缓存(容易出现问题)

conn.setUseCaches(false);

conn.setRequestProperty(Charset, UTF-8);//设置编码

// 在开始用HttpURLConnection对象的setRequestProperty()设置,就是生成HTML文件头

conn.setRequestProperty(ser-Agent, Fiddler);

// 设置contentType

conn.setRequestProperty(Content-Type, multipart/form-data; boundary= + NetUtil.BOUNDARY);

OutputStream os = conn.getOutputStream();

DataOutputStream ds =newDataOutputStream(os);

NetUtil.writeStringParams(textParams, ds);

NetUtil.writeFileParams(fileparams, ds);

NetUtil.paramsEnd(ds);

// 对文件流操作完,要记得及时关闭

os.close();

// 服务器返回的响应吗

intcode = conn.getResponseCode();// 从Internet获取网页,发送请求,将网页以流的形式读回来

// 对响应码进行判断

if(code ==200) {// 返回的响应码200,是成功

// 得到网络返回的输入流

InputStream is = conn.getInputStream();

resultStr = NetUtil.readString(is);

}else{

Toast.makeText(mContext, 请求URL失败!, Toast.LENGTH_SHORT).show();

}

}catch(Exception e) {

e.printStackTrace();

}

handler.sendEmptyMessage(0);// 执行耗时的方法之后发送消给handler

}

};

Handler handler =newHandler(newHandler.Callback() {

@Override

publicbooleanhandleMessage(Message msg) {

switch(msg.what) {

case0:

pd.dismiss();

try{

// 返回数据示例,根据需求和后台数据灵活处理

// {status:1,statusMessage:上传成功,imageUrl:http://120.24.219.49/726287_temphead.jpg}

JSONObject jsonObject =newJSONObject(resultStr);

// 服务端以字符串“1”作为操作成功标记

if(jsonObject.optString(status).equals(1)) {

BitmapFactory.Options option =newBitmapFactory.Options();

// 压缩图片:表示缩略图大小为原始图片大小的几分之一,1为原图,3为三分之一

option.inSampleSize =1;

// 服务端返回的JsonObject对象中提取到图片的网络URL路径

String imageUrl = jsonObject.optString(imageUrl);

Toast.makeText(mContext, imageUrl, Toast.LENGTH_SHORT).show();

}else{

Toast.makeText(mContext, jsonObject.optString(statusMessage), Toast.LENGTH_SHORT).show();

}

}catch(JSONException e) {

e.printStackTrace();

}

break;

default:

break;

}

returnfalse;

}

});

(二)普通图片上传服务器(代码)

直接从这里开始,和头像那里基本没什么区别,我把拍照什么的单独抽出了方法,思路更清晰

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22//为弹出窗口实现监听类

privateOnClickListener itemsOnClick =newOnClickListener() {

@Override

publicvoidonClick(View v) {

// 隐藏弹出窗口

menuWindow.dismiss();

switch(v.getId()) {

caseR.id.takePhotoBtn:// 拍照

takePhoto();

break;

caseR.id.pickPhotoBtn:// 相册选择图片

pickPhoto();

break;

caseR.id.cancelBtn:// 取消

break;

default:

break;

}

}

};

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33/**

* 拍照获取图片

*/

privatevoidtakePhoto() {

// 执行拍照前,应该先判断SD卡是否存在

String SDState = Environment.getExternalStorageState();

if(SDState.equals(Environment.MEDIA_MOUNTED)) {

Intent intent =newIntent(MediaStore.ACTION_IMAGE_CAPTURE);

/***

* 需要说明一下,以下操作使用照相机拍照,拍照后的图片会存放在相册中的

* 这里使用的这种方式有一个好处就是获取的图片是拍照后的原图

* 如果不使用ContentValues存放照片路径的话,拍照后获取的图片为缩略图不清晰

*/

ContentValues values =newContentValues();

photoUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, photoUri);

startActivityForResult(intent, SELECT_PIC_BY_TACK_PHOTO);

}else{

Toast.makeText(this, 内存卡不存在, Toast.LENGTH_LONG).show();

}

}

/***

* 从相册中取图片

*/

privatevoidpickPhoto() {

Intent intent =newIntent();

// 如果要限制上传到服务器的图片类型时可以直接写如:image/jpeg 、 image/png等的类型

intent.setType(image/*);

intent.setAction(Intent.ACTION_GET_CONTENT);

startActivityForResult(intent, SELECT_PIC_BY_PICK_PHOTO);

}

处理一下图片选取的页面回调

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18@Override

protectedvoidonActivityResult(intrequestCode,intresultCode, Intent data) {

// 点击取消按钮

if(resultCode == RESULT_CANCELED){

return;

}

// 可以使用同一个方法,这里分开写为了防止以后扩展不同的需求

switch(requestCode) {

caseSELECT_PIC_BY_PICK_PHOTO:// 如果是直接从相册获取

doPhoto(requestCode, data);

break;

caseSELECT_PIC_BY_TACK_PHOTO:// 如果是调用相机拍照时

doPhoto(requestCode, data);

break;

}

super.onActivityResult(requestCode, resultCode, data);

}

接下来就是显示图片和上传服务器了,上传和头像是同一个流程,只是不进行裁切

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154/**

* 选择图片后,获取图片的路径

*

* @param requestCode

* @param data

*/

privatevoiddoPhoto(intrequestCode, Intent data) {

// 从相册取图片,有些手机有异常情况,请注意

if(requestCode == SELECT_PIC_BY_PICK_PHOTO) {

if(data ==null) {

Toast.makeText(this, 选择图片文件出错, Toast.LENGTH_LONG).show();

return;

}

photoUri = data.getData();

if(photoUri ==null) {

Toast.makeText(this, 选择图片文件出错, Toast.LENGTH_LONG).show();

return;

}

}

String[] pojo = { MediaColumns.DATA };

// The method managedQuery() from the type Activity is deprecated

//Cursor cursor = managedQuery(photoUri, pojo, null, null, null);

Cursor cursor = mContext.getContentResolver().query(photoUri, pojo,null,null,null);

if(cursor !=null) {

intcolumnIndex = cursor.getColumnIndexOrThrow(pojo[0]);

cursor.moveToFirst();

picPath = cursor.getString(columnIndex);

// 4.0以上的版本会自动关闭 (4.0--14;; 4.0.3--15)

if(Integer.parseInt(Build.VERSION.SDK) <14) {

cursor.close();

}

}

// 如果图片符合要求将其上传到服务器

if(picPath !=null&& (    picPath.endsWith(.png) ||

picPath.endsWith(.PNG) ||

picPath.endsWith(.jpg) ||

picPath.endsWith(.JPG))) {

BitmapFactory.Options option =newBitmapFactory.Options();

// 压缩图片:表示缩略图大小为原始图片大小的几分之一,1为原图

option.inSampleSize =1;

// 根据图片的SDCard路径读出Bitmap

Bitmap bm = BitmapFactory.decodeFile(picPath, option);

// 显示在图片控件上

picImg.setImageBitmap(bm);

pd = ProgressDialog.show(mContext,null, 正在上传图片,请稍候...);

newThread(uploadImageRunnable).start();

}else{

Toast.makeText(this, 选择图片文件不正确, Toast.LENGTH_LONG).show();

}

}

/**

* 使用HttpUrlConnection模拟post表单进行文件

* 上传平时很少使用,比较麻烦

* 原理是: 分析文件上传的数据格式,然后根据格式构造相应的发送给服务器的字符串。

*/

Runnable uploadImageRunnable =newRunnable() {

@Override

publicvoidrun() {

if(TextUtils.isEmpty(imgUrl)){

Toast.makeText(mContext, 还没有设置上传服务器的路径!, Toast.LENGTH_SHORT).show();

return;

}

Map textParams =newHashMap();

Map fileparams =newHashMap();

try{

// 创建一个URL对象

URL url =newURL(imgUrl);

textParams =newHashMap();

fileparams =newHashMap();

// 要上传的图片文件

File file =newFile(picPath);

fileparams.put(image, file);

// 利用HttpURLConnection对象从网络中获取网页数据

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

// 设置连接超时(记得设置连接超时,如果网络不好,Android系统在超过默认时间会收回资源中断操作)

conn.setConnectTimeout(5000);

// 设置允许输出(发送POST请求必须设置允许输出)

conn.setDoOutput(true);

// 设置使用POST的方式发送

conn.setRequestMethod(POST);

// 设置不使用缓存(容易出现问题)

conn.setUseCaches(false);

// 在开始用HttpURLConnection对象的setRequestProperty()设置,就是生成HTML文件头

conn.setRequestProperty(ser-Agent, Fiddler);

// 设置contentType

conn.setRequestProperty(Content-Type, multipart/form-data; boundary= + NetUtil.BOUNDARY);

OutputStream os = conn.getOutputStream();

DataOutputStream ds =newDataOutputStream(os);

NetUtil.writeStringParams(textParams, ds);

NetUtil.writeFileParams(fileparams, ds);

NetUtil.paramsEnd(ds);

// 对文件流操作完,要记得及时关闭

os.close();

// 服务器返回的响应吗

intcode = conn.getResponseCode();// 从Internet获取网页,发送请求,将网页以流的形式读回来

// 对响应码进行判断

if(code ==200) {// 返回的响应码200,是成功

// 得到网络返回的输入流

InputStream is = conn.getInputStream();

resultStr = NetUtil.readString(is);

}else{

Toast.makeText(mContext, 请求URL失败!, Toast.LENGTH_SHORT).show();

}

}catch(Exception e) {

e.printStackTrace();

}

handler.sendEmptyMessage(0);// 执行耗时的方法之后发送消给handler

}

};

Handler handler =newHandler(newHandler.Callback() {

@Override

publicbooleanhandleMessage(Message msg) {

switch(msg.what) {

case0:

pd.dismiss();

try{

JSONObject jsonObject =newJSONObject(resultStr);

// 服务端以字符串“1”作为操作成功标记

if(jsonObject.optString(status).equals(1)) {

// 用于拼接发布说说时用到的图片路径

// 服务端返回的JsonObject对象中提取到图片的网络URL路径

String imageUrl = jsonObject.optString(imageUrl);

// 获取缓存中的图片路径

Toast.makeText(mContext, imageUrl, Toast.LENGTH_SHORT).show();

}else{

Toast.makeText(mContext, jsonObject.optString(statusMessage), Toast.LENGTH_SHORT).show();

}

}catch(JSONException e) {

e.printStackTrace();

}

break;

default:

break;

}

returnfalse;

}

});

364595326

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,311评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,339评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,671评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,252评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,253评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,031评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,340评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,973评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,466评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,937评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,039评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,701评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,254评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,259评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,497评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,786评论 2 345

推荐阅读更多精彩内容