即时通讯App|发送图片消息的实现
程序员文章站
2022-07-12 14:17:09
...
即时通讯App——发送图片消息的实现
前置知识:
1、onActivityResult()的用法
假如有两个Activity A,B。如今需要从A的界面跳转到B的界面执行相应的操作。操作执行完毕之后,从B的界面跳转回A的界面,或许还会返回一些数据交给A处理,这样的数据交流可以利用回调函数onActivityResult()实现。
业务流程
1、读取相机/相册图片
2、发送图片消息
3、photoview预览
1、读取相机实现代码
/**
* 相机
* 如果头像上传,可以支持裁剪,自行增加
*
* @param mActivity
*/
public void toCamera(Activity mActivity) {
try {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
String fileName = simpleDateFormat.format(new Date());
tempFile = new File(Environment.getExternalStorageDirectory(), fileName + ".jpg");
//兼容Android N
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
imageUri = Uri.fromFile(tempFile);
} else {
//利用FileProvider
imageUri = FileProvider.getUriForFile(mActivity,
mActivity.getPackageName() + ".fileprovider", tempFile);
//添加权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
mActivity.startActivityForResult(intent, CAMEAR_REQUEST_CODE);
} catch (Exception e) {
Toast.makeText(mActivity, "无法打开相机", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
2、跳转到相册实现代码
/**
* 跳转到相册
*
* @param mActivity
*/
public void toAlbum(Activity mActivity) {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
mActivity.startActivityForResult(intent, ALBUM_REQUEST_CODE);
}
以上两个方法封装在FileHelper文件的帮助类中。
然后在聊天Activity中处理FileHelper回调的图片数据
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
if (requestCode == FileHelper.CAMEAR_REQUEST_CODE) {
uploadFile = FileHelper.getInstance().getTempFile();
} else if (requestCode == FileHelper.ALBUM_REQUEST_CODE) {
Uri uri = data.getData();
if (uri != null) {
//String path = uri.getPath();
//获取真实的地址
String path = FileHelper.getInstance().getRealPathFromURI(this, uri);
//LogUtils.e("path:" + path);
if (!TextUtils.isEmpty(path)) {
uploadFile = new File(path);
}
}
}
if (uploadFile != null) {
//发送图片消息
CloudManager.getInstance().sendImageMessage(yourUserId, uploadFile);
//更新列表
addImage(1, uploadFile);
uploadFile = null;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
发送图片调用融云SDK,下面有一个callback,由于我们省略了发送图片的进度,是否成功等回调,直接写在service中就可以了。如果需要具体回调处理,则把回调放置到传参列表即可。
private RongIMClient.SendImageMessageCallback sendImageMessageCallback = new RongIMClient.SendImageMessageCallback() {
@Override
public void onAttached(Message message) {
LogUtils.i("onAttached");
}
@Override
public void onError(Message message, RongIMClient.ErrorCode errorCode) {
LogUtils.i("onError:" + errorCode);
}
@Override
public void onSuccess(Message message) {
LogUtils.i("onSuccess");
}
@Override
public void onProgress(Message message, int i) {
LogUtils.i("onProgress:" + i);
}
};
/**
* 发送图片消息
*
* @param targetId 对方ID
* @param file 文件
*/
public void sendImageMessage(String targetId, File file) {
ImageMessage imageMessage = ImageMessage.obtain(Uri.fromFile(file), Uri.fromFile(file), true);
RongIMClient.getInstance().sendImageMessage(
Conversation.ConversationType.PRIVATE,
targetId,
imageMessage,
null,
null,
sendImageMessageCallback);
}
adapter多数据绑定
mChatAdapter = new CommonAdapter<>(mList, new CommonAdapter.OnMoreBindDataListener<ChatModel>() {
@Override
public int getItemType(int position) {
return mList.get(position).getType();
}
@Override
public void onBindViewHolder(final ChatModel model, CommonViewHolder viewHolder, int type, int position) {
//布局文件中的控件,设置相应的数据,通过chatModel中的type来区分是左边还是右边的布局的控件
switch (model.getType()) {
case TYPE_LEFT_IMAGE:
viewHolder.setImageUrl(ChatActivity.this, R.id.iv_left_img, model.getImgUrl());
viewHolder.setImageUrl(ChatActivity.this, R.id.iv_left_photo, yourUserPhoto);
viewHolder.getView(R.id.iv_left_img).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ImagePreviewActivity.startActivity(
ChatActivity.this, true, model.getImgUrl());
}
});
break;
case TYPE_RIGHT_IMAGE://右边的是本地文件
if (TextUtils.isEmpty(model.getImgUrl())) {
if (model.getLocalFile() != null) {
//加载本地文件
viewHolder.setImageFile(ChatActivity.this, R.id.iv_right_img, model.getLocalFile());
viewHolder.getView(R.id.iv_right_img).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ImagePreviewActivity.startActivity(
ChatActivity.this, false, model.getLocalFile().getPath());
}
});
}
} else {
viewHolder.setImageUrl(ChatActivity.this, R.id.iv_right_img, model.getImgUrl());
viewHolder.setImageUrl(ChatActivity.this, R.id.iv_right_photo, meUserPhoto);
viewHolder.getView(R.id.iv_right_img).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ImagePreviewActivity.startActivity(
ChatActivity.this, true, model.getImgUrl());
}
});
}
break;
}
}
//布局文件,通过chatModel中的type来区分是左边还是右边的布局
@Override
public int getLayoutId(int type) {
} else if (type == TYPE_LEFT_IMAGE) {
return R.layout.layout_chat_left_img;
} else if (type == TYPE_RIGHT_IMAGE) {
return R.layout.layout_chat_right_img;
}
return 0;
}
});
mChatView.setAdapter(mChatAdapter);
/**
* 添加数据的基类
*
* @param model
*/
private void baseAddItem(ChatModel model) {
long currentTime = System.currentTimeMillis();
LogUtils.e("currentTime:" + currentTime);
if (CommonUtils.isEmpty(mList)) {
//本地逻辑:每次添加消息前,可以判断是否需要添加时间 这里比较的是本地时间,实际上应该比较服务器消息时间,我没做而已
ChatModel lastModel = mList.get(mList.size() - 1);
long lastTime = lastModel.getMessageTime();
LogUtils.e("lastTime:" + lastTime);
//间隔五分钟
if (Math.abs(lastTime - currentTime) > 5 * 60 * 1000) {
addTimeItem(currentTime);
}
}
model.setMessageTime(currentTime);
mList.add(model);
mChatAdapter.notifyDataSetChanged();
//滑动到底部
mChatView.scrollToPosition(mList.size() - 1);
}
/**
* 添加图片
*
* @param index
* @param url
*/
private void addImage(int index, String url) {
ChatModel model = new ChatModel();
if (index == 0) {
model.setType(TYPE_LEFT_IMAGE);
} else {
model.setType(TYPE_RIGHT_IMAGE);
}
model.setImgUrl(url);
baseAddItem(model);
}
/**
* 添加图片
*
* @param index
* @param file
*/
private void addImage(int index, File file) {
ChatModel model = new ChatModel();
if (index == 0) {
model.setType(TYPE_LEFT_IMAGE);
} else {
model.setType(TYPE_RIGHT_IMAGE);
}
model.setLocalFile(file);
baseAddItem(model);
}
只有每次进来才会调用查询服务器的消息queryMessage(),然后再解析历史记录进行渲染
/**
* 解析历史记录
*
* @param messages
*/
private void parsingListMessage(List<Message> messages) {
//倒序
Collections.reverse(messages);
//遍历
for (int i = 0; i < messages.size(); i++) {
Message m = messages.get(i);
String objectName = m.getObjectName();
if (objectName.equals(CloudManager.MSG_IMAGE_NAME)) {
ImageMessage imageMessage = (ImageMessage) m.getContent();
String url = imageMessage.getRemoteUri().toString();
if (!TextUtils.isEmpty(url)) {
LogUtils.i("url:" + url);
if (m.getSenderUserId().equals(yourUserId)) {
addImage(0, url);//另外一个人的
} else {
addImage(1, url);//自己的
}
}
}
}
}
}
Service 的逻辑:
//接收消息
CloudManager.getInstance().setOnReceiveMessageListener((message, i) -> {
parsingImMessage(message);
return false;
});
/**
* 解析消息体
*
* @param message
*/
private void parsingImMessage(Message message) {
LogUtils.i("message:" + message);
String objectName = message.getObjectName();
if (objectName.equals(CloudManager.MSG_IMAGE_NAME)) {
try {
ImageMessage imageMessage = (ImageMessage) message.getContent();
String url = imageMessage.getRemoteUri().toString();
if (!TextUtils.isEmpty(url)) {
LogUtils.i("url:" + url);
MessageEvent event = new MessageEvent(EventManager.FLAG_SEND_IMAGE);
event.setImgUrl(url);
event.setUserId(message.getSenderUserId());
EventManager.post(event);
pushSystem(message.getSenderUserId(), 1, 0, 0, getString(R.string.text_chat_record_img));
}
} catch (Exception e) {
LogUtils.e("e." + e.toString());
e.printStackTrace();
}
}
通过在Activity中onMessageEvent处理事件:
case EventManager.FLAG_SEND_IMAGE:
addImage(0, event.getImgUrl());//别人发过来的
break;
下面实现图片预览:
使用开源控件photoview
**
* FileName: ImagePreviewActivity
* Profile: 图片预览
*/
public class ImagePreviewActivity extends BaseUIActivity implements View.OnClickListener {
/**
* 跳转
* @param mContext
* @param isUrl
* @param url
*/
public static void startActivity(Context mContext, boolean isUrl, String url) {
Intent intent = new Intent(mContext, ImagePreviewActivity.class);
intent.putExtra(Constants.INTENT_IMAGE_TYPE, isUrl);
intent.putExtra(Constants.INTENT_IMAGE_URL, url);
mContext.startActivity(intent);
}
private PhotoView photo_view;
private ImageView iv_back;
private TextView tv_download;
//图片地址
private String url;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_preview);
initView();
}
private void initView() {
photo_view = (PhotoView) findViewById(R.id.photo_view);
iv_back = (ImageView) findViewById(R.id.iv_back);
tv_download = (TextView)findViewById(R.id.tv_download);
iv_back.setOnClickListener(this);
tv_download.setOnClickListener(this);
Intent intent = getIntent();
boolean isUrl = intent.getBooleanExtra(Constants.INTENT_IMAGE_TYPE,false);
url = intent.getStringExtra(Constants.INTENT_IMAGE_URL);
//图片地址才下载,File代表本次已经存在
tv_download.setVisibility(isUrl?View.VISIBLE:View.GONE);
if(isUrl){
GlideHelper.loadUrl(this,url,photo_view);
}else{
GlideHelper.loadFile(this,new File(url),photo_view);
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.iv_back:
finish();
break;
case R.id.tv_download:
Toast.makeText(this, getString(R.string.text_iv_pre_downloading), Toast.LENGTH_SHORT).show();
GlideHelper.loadUrlToBitmap(this, url, new GlideHelper.OnGlideBitmapResultListener() {
@Override
public void onResourceReady(Bitmap resource) {
if(resource != null){
FileHelper.getInstance().saveBitmapToAlbum(ImagePreviewActivity.this,resource);
}else{
Toast.makeText(ImagePreviewActivity.this, getString(R.string.text_iv_pre_save_fail), Toast.LENGTH_SHORT).show();
}
}
});
break;
}
}
}
上一篇: PayPal支付功能实现