即时通讯App|发送图片消息的实现

即时通讯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;
        }
    }
}

你可能感兴趣的:(android)