Android聊天软件开发(基于网易云IM即时通讯)——发送图片消息(五)
程序员文章站
2022-07-12 14:16:21
...
最近工作太忙,都没有时间写博客了。废话不多说,直接上代码。
在activity_send_message.xml添加发送图片的按钮
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="44dp"
android:background="@color/deepskyblue"
android:gravity="center_vertical"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/ll_return"
android:layout_width="44sp"
android:layout_height="44sp"
android:gravity="center_vertical">
<ImageView
android:layout_width="24sp"
android:layout_height="24sp"
android:layout_marginStart="20dp"
android:contentDescription="@string/tv_icon_des"
android:src="@drawable/return1" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:text="@string/btn_send_message"
android:textColor="@color/white"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:id="@+id/ed_send_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/btn_send_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/btn_send_message" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="消息接收显示" />
<TextView
android:id="@+id/tv_receive_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="@+id/btn_album"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tv_album" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="图片接收显示" />
<ImageView
android:id="@+id/iv_receive_message"
android:layout_width="200dp"
android:layout_height="200dp" />
</LinearLayout>
</LinearLayout>
<!--<RelativeLayout-->
<!--android:id="@+id/rl_loading"-->
<!--android:layout_width="150dp"-->
<!--android:layout_height="150dp"-->
<!--android:layout_gravity="center"-->
<!--android:background="@drawable/shape_label_clarity_black">-->
<!--<com.github.ybq.android.spinkit.SpinKitView-->
<!--xmlns:app="http://schemas.android.com/apk/res-auto"-->
<!--android:id="@+id/pb_loading"-->
<!--style="@style/SpinKitView.Large.Circle"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_centerInParent="true"-->
<!--app:SpinKit_Color="@color/white" />-->
<!--<TextView-->
<!--android:id="@+id/tv_loading_text"-->
<!--android:layout_below="@id/pb_loading"-->
<!--android:layout_centerHorizontal="true"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:textColor="@color/white"-->
<!--/>-->
<!--</RelativeLayout>-->
</FrameLayout>
在SendMessageActivity添加按钮的注册以及点击事件
package heath.com.chat.message;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.netease.nimlib.sdk.NIMClient;
import com.netease.nimlib.sdk.RequestCallback;
import com.netease.nimlib.sdk.msg.MessageBuilder;
import com.netease.nimlib.sdk.msg.MsgService;
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
import com.netease.nimlib.sdk.msg.model.IMMessage;
import java.io.File;
import java.net.URI;
import java.util.HashMap;
import heath.com.chat.R;
import heath.com.chat.service.IMService;
import heath.com.chat.utils.Common;
import heath.com.chat.utils.RealPathFromUriUtils;
import heath.com.chat.utils.ToastUtil;
public class SendMessageActivity extends AppCompatActivity implements View.OnClickListener {
private static IMService mImService;
private LinearLayout mLlReturn;
private EditText mEdSendText;
//调用系统相册-选择图片
private static final int IMAGE = 1;
/**
* 发消息
*/
private Button mBtnSendText;
private static TextView mTvReceiveMessage;
private Button mBtnAlbum;
private static ImageView mIvReceiveMessage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_send_message);
initView();
init();
}
private void init() {
// 绑定服务
Intent service = new Intent(SendMessageActivity.this, IMService.class);
bindService(service, mMyServiceConnection, BIND_AUTO_CREATE);
}
@Override
public void onDestroy() {
super.onDestroy();
// 解绑服务
if (mMyServiceConnection != null) {
unbindService(mMyServiceConnection);
}
}
MyServiceConnection mMyServiceConnection = new MyServiceConnection();
private void initView() {
mLlReturn = (LinearLayout) findViewById(R.id.ll_return);
mEdSendText = (EditText) findViewById(R.id.ed_send_text);
mBtnSendText = (Button) findViewById(R.id.btn_send_text);
mBtnSendText.setOnClickListener(this);
mTvReceiveMessage = (TextView) findViewById(R.id.tv_receive_message);
mBtnAlbum = (Button) findViewById(R.id.btn_album);
mIvReceiveMessage = (ImageView) findViewById(R.id.iv_receive_message);
mBtnAlbum.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
default:
break;
case R.id.ll_return:
finish();
break;
case R.id.btn_album:
Intent intent = new Intent(Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*");
startActivityForResult(intent, IMAGE);
break;
case R.id.btn_send_text:
final String content = mEdSendText.getText().toString();//消息文本
String account = "1";//目前这里是写死的账号
SessionTypeEnum type = SessionTypeEnum.P2P;//会话类型
final IMMessage textMessage = MessageBuilder.createTextMessage(account, type, content);
NIMClient.getService(MsgService.class).sendMessage(textMessage, false).setCallback(new RequestCallback<Void>() {
@Override
public void onSuccess(Void param) {
ToastUtil.toastOnUiThread(SendMessageActivity.this, "发送成功");
}
@Override
public void onFailed(int code) {
Log.e("文本发送失败", "onEvent: " + code);
}
@Override
public void onException(Throwable exception) {
Log.e("文本发送异常", "onEvent: " + exception);
}
});
mEdSendText.setText("");
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//获取图片路径
if (requestCode == IMAGE && resultCode == Activity.RESULT_OK && data != null) {
Uri selectedImage = data.getData();
//将uri转换为路径
String path = RealPathFromUriUtils.getRealPathFromUri(this, selectedImage);
File file = new File(path);
String account = "1";//目前这里是写死的账号
IMMessage message = MessageBuilder.createImageMessage(account, SessionTypeEnum.P2P, file, file.getName());
NIMClient.getService(MsgService.class).sendMessage(message, false).setCallback(new RequestCallback<Void>() {
@Override
public void onSuccess(Void param) {
try {
ToastUtil.toastOnUiThread(SendMessageActivity.this, "发送成功");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onFailed(int code) {
Log.e("图片发送失败", "onEvent: " + code);
}
@Override
public void onException(Throwable exception) {
exception.printStackTrace();
Log.e("图片发送异常", "onEvent: " + exception);
}
});
}
}
//收到文本消息更新界面
public static void updateData(String message) {
mTvReceiveMessage.setText(message);
}
//收到图片消息更新界面
public static void updateData1(String message) {
mIvReceiveMessage.setImageURI(Uri.parse(message));
}
class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out
.println("--------------onServiceConnected--------------");
IMService.MyBinder binder = (IMService.MyBinder) service;
mImService = binder.getService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
System.out
.println("--------------onServiceDisconnected--------------");
}
}
}
RealPathFromUriUtils这个是将URI转换为路径的文件
package heath.com.chat.utils;
import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
public class RealPathFromUriUtils {
/**
* 根据Uri获取图片的绝对路径
*
* @param context 上下文对象
* @param uri 图片的Uri
* @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
*/
public static String getRealPathFromUri(Context context, Uri uri) {
int sdkVersion = Build.VERSION.SDK_INT;
if (sdkVersion >= 19) { // api >= 19
return getRealPathFromUriAboveApi19(context, uri);
} else { // api < 19
return getRealPathFromUriBelowAPI19(context, uri);
}
}
/**
* 适配api19以下(不包括api19),根据uri获取图片的绝对路径
*
* @param context 上下文对象
* @param uri 图片的Uri
* @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
*/
private static String getRealPathFromUriBelowAPI19(Context context, Uri uri) {
return getDataColumn(context, uri, null, null);
}
/**
* 适配api19及以上,根据uri获取图片的绝对路径
*
* @param context 上下文对象
* @param uri 图片的Uri
* @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
*/
@SuppressLint("NewApi")
private static String getRealPathFromUriAboveApi19(Context context, Uri uri) {
String filePath = null;
if (DocumentsContract.isDocumentUri(context, uri)) {
// 如果是document类型的 uri, 则通过document id来进行处理
String documentId = DocumentsContract.getDocumentId(uri);
if (isMediaDocument(uri)) { // MediaProvider
// 使用':'分割
String id = documentId.split(":")[1];
String selection = MediaStore.Images.Media._ID + "=?";
String[] selectionArgs = {id};
filePath = getDataColumn(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection, selectionArgs);
} else if (isDownloadsDocument(uri)) { // DownloadsProvider
Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(documentId));
filePath = getDataColumn(context, contentUri, null, null);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
// 如果是 content 类型的 Uri
filePath = getDataColumn(context, uri, null, null);
} else if ("file".equals(uri.getScheme())) {
// 如果是 file 类型的 Uri,直接获取图片对应的路径
filePath = uri.getPath();
}
return filePath;
}
/**
* 获取数据库表中的 _data 列,即返回Uri对应的文件路径
*
* @return
*/
private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
String path = null;
String[] projection = new String[]{MediaStore.Images.Media.DATA};
Cursor cursor = null;
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
int columnIndex = cursor.getColumnIndexOrThrow(projection[0]);
path = cursor.getString(columnIndex);
}
} catch (Exception e) {
if (cursor != null) {
cursor.close();
}
}
return path;
}
/**
* @param uri the Uri to check
* @return Whether the Uri authority is MediaProvider
*/
private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
/**
* @param uri the Uri to check
* @return Whether the Uri authority is DownloadsProvider
*/
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
}
在IMService添加接收图片的消息处理
private Observer<IMMessage> statusObserver = new Observer<IMMessage>() {
@Override
public void onEvent(IMMessage message) {
if (message.getDirect() == MsgDirectionEnum.In) {
if (message.getAttachStatus() == AttachStatusEnum.transferred) {
if (message.getMsgType() == MsgTypeEnum.image) {
//这里是图片下载成功
SendMessageActivity.updateData1(((ImageAttachment) message.getAttachment()).getThumbPath());
}
}
}
}
};
在IMService注册statusObserver和注销
在TabHostActivity增加加载动态权限
private void open() {
if (Build.VERSION.SDK_INT >= 23) {
int REQUEST_CODE_CONTACT = 101;
String[] permissions = {android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.CAMERA};
//验证是否许可权限
for (String str : permissions) {
if (this.checkSelfPermission(str) != PackageManager.PERMISSION_GRANTED) {
//申请权限
this.requestPermissions(permissions, REQUEST_CODE_CONTACT);
}
}
}
}
项目下载地址:https://download.csdn.net/download/qq_32090185/11122479