李晨晨:
本次主要实现聊天消息列表中图片信息的LruCache保存实现。
1.首先初始化图片缓存,获取应用最大可用内存,取1/8作为缓存内存。
- private Context mContext;
- private LruCache<String, Bitmap> mLruCache;
- public ChatUtils(Context context){
- mContext = context;
- //获取应用最大可用内存,取1/8作为缓存内存
- int maxMemory = (int) Runtime.getRuntime().maxMemory();
- int cacheMemory = maxMemory / 8;
- //初始化图片缓存
- mLruCache = new LruCache<String, Bitmap>(cacheMemory){
- @Override
- protected int sizeOf(String key, Bitmap value) {
- //返回图片所占内存
- return value.getRowBytes() * value.getHeight();
- }
- };
- }
2.获得图片消息附件,优先显示缩略图,缩略图不存在的情况下显示原图:
- public Bitmap getBitmap(ImageAttachment attachment) {
- // 优先显示缩略图,但是要限制宽高
- if (!TextUtils.isEmpty(attachment.getThumbPath())) {
- Bitmap bitmap = mLruCache.get(attachment.getThumbPath());
- if (bitmap == null){
- bitmap = ImageUtils.getBitmapFromFile(attachment.getThumbPath(), 400, 180);
- mLruCache.put(attachment.getThumbPath(),bitmap);
- }
- return bitmap;
- }
- // 缩略图不存在的情况下显示原图,但是要限制宽高
- if (!TextUtils.isEmpty(attachment.getPath())) {
- Bitmap bitmap = mLruCache.get(attachment.getPath());
- if (bitmap == null){
- bitmap = ImageUtils.getBitmapFromFile(attachment.getPath(), 400, 180);
- mLruCache.put(attachment.getPath(),bitmap);
- }
- return bitmap;
- }
- return null;
- }
3.返回IMMessage的传输状态:
- public boolean isTransferring(IMMessage message) {
- return message.getStatus() == MsgStatusEnum.sending || (message.getAttachment() != null
- && message.getAttachStatus() == AttachStatusEnum.transferring);
- }
4.返回音频文件的时长(单位:秒)
- public String getAudioTime(long duration) {
- return String.valueOf(duration / 1000.0) + "'";
- }
5.MsgHeadView下拉后的加载条,用于下周的聊天列表RecycleView。
- public class MsgHeadView extends LinearLayout {
- private static final String TAG = MsgHeadView.class.getSimpleName();
- private LinearLayout mContainer;
- private int mHeadHeight;
- public MsgHeadView(Context context) {
- this(context,null);
- }
- public MsgHeadView(Context context, @Nullable AttributeSet attrs) {
- this(context, attrs,0);
- }
- public MsgHeadView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init();
- }
- private void init(){
- mContainer = (LinearLayout) LayoutInflater.from(getContext()).inflate(R.layout.msg_head_view, null);
- LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
- lp.setMargins(0, 0, 0, 0);
- this.setLayoutParams(lp);
- this.setPadding(0, 0, 0, 0);
- addView(mContainer, new LayoutParams(LayoutParams.MATCH_PARENT, 0));
- setGravity(Gravity.BOTTOM);
- int height = View.MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);
- int width = View.MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);
- mContainer.measure(width,height);
- mHeadHeight = mContainer.getMeasuredHeight();
- }
- public int getHeadHeight(){
- return mHeadHeight;
- }
- public void setVisibleHeight(int height) {
- if (height < 0) height = 0;
- LayoutParams lp = (LayoutParams) mContainer .getLayoutParams();
- lp.height = height;
- mContainer.setLayoutParams(lp);
- }
- public int getVisibleHeight() {
- LayoutParams lp = (LayoutParams) mContainer.getLayoutParams();
- return lp.height;
- }
- }
msg_head_view.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/msg_header_content"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <ProgressBar
- android:id="@+id/progress"
- android:layout_width="match_parent"
- android:layout_height="20dp"
- android:indeterminate="true"
- android:indeterminateDrawable="@drawable/progress_bar_rotate"
- android:indeterminateBehavior="repeat"/>
即图中的加载环
仝心:
这次实现了两个工具类的编程,日后用于注册账号和申请权限。
NimClientHandle
- public static NimClientHandle getInstance() {
- if (instance == null) {
- synchronized (NimClientHandle.class) {
- if (instance == null) {
- instance = new NimClientHandle();
- }
- }
- }
- return instance;
- }
- private NimClientHandle() {
- initApi();
- }
- private void initApi() {
- mOkHttpClient = new OkHttpClient();
- }
- public void register(String account, String token, String name, final OnRegisterListener listener) {
- RequestBody body = new FormBody.Builder()
- .add("accid", account)
- .add("token", token)
- .add("name", name)
- .build();
- Request request = new Request.Builder()
- .url(APP_SERVER_BASE_URL + mAppServerUserCreate)
- .headers(createHeaders())
- .post(body)
- .build();
- mOkHttpClient.newCall(request).enqueue(new Callback() {
- @Override
- public void onFailure(@NonNull Call call, @NonNull IOException e) {
- listener.onFailed(e.getMessage());
- }
- @Override
- public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
- if (listener != null){
- if (response.code() == 200){
- listener.onSuccess();
- }else {
- listener.onFailed(response.message());
- }
- }
- }
- });
- }
- /**
- * 生成访问 NIM APP-SERVICE 所要求的 HEADER
- * @return headers ,in OK HTTP3
- */
- private Headers createHeaders(){
- String nonce = CheckSumUtils.getNonce();
- String time = String.valueOf(System.currentTimeMillis() / 1000L);
- return new Headers.Builder()
- .add("Content-Type","application/x-www-form-urlencoded;charset=utf-8")
- .add("AppKey", readAppKey())
- .add("Nonce", nonce)
- .add("CurTime", time)
- .add("CheckSum", CheckSumUtils.getCheckSum(Constant.APP_SECURY, nonce, time))
- .build();
- }
- /**
- * 读取存储于manifest文件下的 APP KEY
- *
- * @return APP key
- */
- private String readAppKey() {
- try {
- ApplicationInfo appInfo = MyApplication.getInstance().getPackageManager()
- .getApplicationInfo(MyApplication.getInstance().getPackageName(), PackageManager.GET_META_DATA);
- if (appInfo != null) {
- return appInfo.metaData.getString("com.netease.nim.appKey");
- }
- } catch (Exception e) {
- e.printStackTrace();
- return "";
- }
- return "";
- }
- @RequiresApi(api = Build.VERSION_CODES.M)
- public static boolean checkPermissions(Context context, String... permissions){
- for (String p : permissions){
- if (context.checkSelfPermission(p) != PackageManager.PERMISSION_GRANTED){
- return false;
- }
- }
- return true;
- }
- /**
- * 申请权限
- * @param activity Activity
- * @param requestCode 申请码
- * @param permissions 权限组
- */
- @RequiresApi(api = Build.VERSION_CODES.M)
- public static void requestPermissions(Activity activity, int requestCode, String... permissions){
- activity.requestPermissions(permissions,requestCode);
- }
- /**
- * 处理权限申请回调结果,分为 授权,拒绝未勾选不再提醒,拒绝并勾选不再提醒 三组结果返回
- * @param context 上下文
- * @param permission 申请的权限数组{@link ActivityCompat.OnRequestPermissionsResultCallback}
- * @param grantResult 申请结果数组{@link ActivityCompat.OnRequestPermissionsResultCallback}
- * @param callBack 处理回调接口 {@link RequestPermissionCallBack}
- */
- public static void dealPermissionResult(Context context,String[] permission,
- int[] grantResult,RequestPermissionCallBack callBack){
- List<String> grant = new ArrayList<>();
- List<String> denied = new ArrayList<>();
- List<String> neverAsk = new ArrayList<>();
- for (int i=0;i<grantResult.length;i++){
- if (grantResult[i] == PackageManager.PERMISSION_GRANTED){
- grant.add(permission[i]);
- }else {
- if (judgePermission(context,permission[i])){
- denied.add(permission[i]);
- }else {
- neverAsk.add(permission[i]);
- }
- }
- }
- if (!grant.isEmpty()){
- callBack.onGrant(list2Array(grant));
- }
- if (!denied.isEmpty()){
- callBack.onDenied(list2Array(denied));
- }
- if (!neverAsk.isEmpty()){
- callBack.onDeniedAndNeverAsk(list2Array(neverAsk));
- }
- }
- /**
- * 对于用户拒绝并勾选不再提醒的权限进行提示和辅助跳转到权限管理页面
- * @param context 上下文
- * @param message 权限需求说明
- */
- public static void requestPermissionDialog(final Context context, String message){
- new AlertDialog.Builder(context)
- .setTitle("权限申请")
- .setMessage(message)
- .setPositiveButton("授权", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- Intent intent = new Intent();
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
- intent.setData(Uri.fromParts("package", context.getPackageName(), null));
- context.startActivity(intent);
- // 跳转后请在 onRestart 在中再次检查权限是否已获取
- }
- })
- .setNegativeButton("拒绝", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- ToastUtils.showMessage(context,"未能获取权限,部分功能将受限");
- }
- })
- .show();
- }
- /**
- * 判断是否已拒绝过权限
- * 如果应用之前请求过此权限但用户拒绝,此方法将返回 true;
- * -----如果应用第一次请求权限或 用户在过去拒绝了权限请求,
- * -----并在权限请求系统对话框中选择了 Don't ask again 选项,此方法将返回 false。
- */
- private static boolean judgePermission(Context context, String permission) {
- return ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, permission);
- }
- private static String[] list2Array(List<String> list){
- String[] array = new String[list.size()];
- for (int i=0;i<list.size();i++){
- array[i] = list.get(i);
- }
- return array;
- }
- /**
- * 权限处理返回接口
- */
- public interface RequestPermissionCallBack {
- /**
- * 用户授予权限
- * @param permissions 已获得授权的权限
- */
- void onGrant(String... permissions);
- /**
- * 用户拒绝,(未勾选不再提醒)
- * @param permissions 被拒绝的权限
- */
- void onDenied(String... permissions);
- /**
- * 用户拒绝,并且已勾选不再询问选项
- * @param permissions 被拒绝的权限
- */
- void onDeniedAndNeverAsk(String... permissions);
- }
CheckSumUtils
- private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5',
- '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
- // 计算并获取CheckSum
- public static String getCheckSum(String appSecret, String nonce, String curTime) {
- return encode("sha1", appSecret + nonce + curTime);
- }
- // 计算并获取md5值
- public static String getMD5(String requestBody) {
- return encode("md5", requestBody);
- }
- // 生成随机字符串
- public static String getNonce(){
- String retStr;
- String strTable = "1234567890abcdefghijkmnpqrstuvwxyz";
- int len = strTable.length();
- boolean bDone = true;
- do {
- retStr = "";
- int count = 0;
- for (int i = 0; i < strTable.length(); i++) {
- double dblR = Math.random() * len;
- int intR = (int) Math.floor(dblR);
- char c = strTable.charAt(intR);
- if (('0' <= c) && (c <= '9')) {
- count++;
- }
- retStr += strTable.charAt(intR);
- }
- if (count >= 2) {
- bDone = false;
- }
- } while (bDone);
- return retStr;
- }
- private static String encode(String algorithm, String value) {
- if (value == null) {
- return null;
- }
- try {
- MessageDigest messageDigest
- = MessageDigest.getInstance(algorithm);
- messageDigest.update(value.getBytes());
- return getFormattedText(messageDigest.digest());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- private static String getFormattedText(byte[] bytes) {
- int len = bytes.length;
- StringBuilder buf = new StringBuilder(len * 2);
- for (byte aByte : bytes) {
- buf.append(HEX_DIGITS[(aByte >> 4) & 0x0f]);
- buf.append(HEX_DIGITS[aByte & 0x0f]);
- }
- return buf.toString();
- }
张静:
接下来完成MeFragment中可选择进入的AccountInfoActivity(账号信息详情页),可修改个人信息
1. activity_account_info.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:orientation="vertical"
- android:fitsSystemWindows="true">
- <include layout="@layout/title_layout"/>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:background="@color/interval_color">
- <View
- android:layout_width="match_parent"
- android:layout_height="10dp"/>
- <RelativeLayout
- android:id="@+id/layout_head"
- android:background="@color/white_color"
- android:layout_width="match_parent"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:layout_height="80dp">
- <TextView
- android:text="@string/account_head_picture"
- android:gravity="center_vertical"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:textSize="16sp"
- android:textColor="@color/app_black_color"/>
- <com.joooonho.SelectableRoundedImageView
- android:id="@+id/iv_head_picture"
- android:layout_alignParentRight="true"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:layout_width="70dp"
- android:scaleType="fitXY"
- app:sriv_oval="true"
- android:src="@mipmap/app_logo_main"
- android:layout_height="70dp"/>
- </RelativeLayout>
- <View
- android:layout_width="match_parent"
- android:layout_height="0.8dp"/>
- <RelativeLayout
- android:background="@color/white_color"
- android:layout_width="match_parent"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:layout_height="40dp">
- <TextView
- android:id="@+id/tv_1"
- android:text="账号"
- android:gravity="center_vertical"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:textSize="16sp"
- android:textColor="@color/app_black_color"/>
- <TextView
- android:layout_toRightOf="@+id/tv_1"
- android:layout_marginLeft="10dp"
- android:textSize="16sp"
- android:textColor="@color/default_text_color"
- android:id="@+id/tv_account"
- android:gravity="center_vertical|right"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
- </RelativeLayout>
- <View
- android:layout_width="match_parent"
- android:layout_height="0.8dp"/>
- <RelativeLayout
- android:background="@color/white_color"
- android:layout_width="match_parent"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:layout_height="40dp">
- <TextView
- android:id="@+id/tv_2"
- android:text="@string/account_nick"
- android:gravity="center_vertical"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:textSize="16sp"
- android:textColor="@color/app_black_color"/>
- <EditText
- android:layout_toRightOf="@+id/tv_2"
- android:layout_marginLeft="10dp"
- android:textSize="16sp"
- android:textColor="@color/default_text_color"
- android:id="@+id/et_account_nick"
- android:gravity="center_vertical|right"
- android:layout_width="match_parent"
- android:background="@null"
- android:layout_height="match_parent"/>
- </RelativeLayout>
- <View
- android:layout_width="match_parent"
- android:layout_height="0.8dp"/>
- <RelativeLayout
- android:background="@color/white_color"
- android:layout_width="match_parent"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:layout_height="40dp">
- <TextView
- android:id="@+id/tv_3"
- android:text="@string/account_sex"
- android:gravity="center_vertical"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:textSize="16sp"
- android:textColor="@color/app_black_color"/>
- <TextView
- android:layout_toRightOf="@+id/tv_3"
- android:layout_marginLeft="10dp"
- android:textSize="16sp"
- android:textColor="@color/default_text_color"
- android:id="@+id/tv_account_sex"
- android:gravity="center_vertical|right"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
- </RelativeLayout>
- <View
- android:layout_width="match_parent"
- android:layout_height="0.8dp"/>
- <RelativeLayout
- android:background="@color/white_color"
- android:layout_width="match_parent"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:layout_height="40dp">
- <TextView
- android:id="@+id/tv_4"
- android:text="@string/account_birth"
- android:gravity="center_vertical"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:textSize="16sp"
- android:textColor="@color/app_black_color"/>
- <TextView
- android:layout_toRightOf="@+id/tv_4"
- android:layout_marginLeft="10dp"
- android:textSize="16sp"
- android:textColor="@color/default_text_color"
- android:id="@+id/tv_account_birth"
- android:gravity="center_vertical|right"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
- </RelativeLayout>
- <View
- android:layout_width="match_parent"
- android:layout_height="0.8dp"/>
- <RelativeLayout
- android:background="@color/white_color"
- android:layout_width="match_parent"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:layout_height="40dp">
- <TextView
- android:id="@+id/tv_5"
- android:text="@string/account_location"
- android:gravity="center_vertical"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:textSize="16sp"
- android:textColor="@color/app_black_color"/>
- <TextView
- android:layout_toRightOf="@+id/tv_5"
- android:layout_marginLeft="10dp"
- android:gravity="center_vertical|right"
- android:textSize="16sp"
- android:textColor="@color/default_text_color"
- android:id="@+id/tv_account_location"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
- </RelativeLayout>
- <View
- android:layout_width="match_parent"
- android:layout_height="0.8dp"/>
- <RelativeLayout
- android:background="@color/white_color"
- android:layout_width="match_parent"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:layout_height="60dp">
- <TextView
- android:id="@+id/tv_6"
- android:text="@string/account_signature"
- android:gravity="center_vertical"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:textSize="16sp"
- android:textColor="@color/app_black_color"/>
- <EditText
- android:hint="@string/signature_hint"
- android:layout_toRightOf="@+id/tv_6"
- android:layout_marginLeft="10dp"
- android:textSize="16sp"
- android:textColor="@color/default_text_color"
- android:id="@+id/et_account_signature"
- android:gravity="center_vertical|right"
- android:maxLines="2"
- android:background="@null"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
- </RelativeLayout>
- </LinearLayout>
- </LinearLayout>
2. 显示数据
通过NimUserHandler获得本地账户,由在本地账户中设置的属性数据设置个人信息页并显示
- private void showData() {
- mAccountBean = NimUserHandler.getInstance().getLocalAccount();
- if (mAccountBean != null) {
- ImageUtils.setImageByFile(this, mIvHead,
- mAccountBean.getHeadImgUrl(), R.mipmap.bg_img_defalut);
- mTvAccount.setText(mAccountBean.getAccount());
- mEtNick.setText(mAccountBean.getNick());
- if (mAccountBean.getGenderEnum() == GenderEnum.FEMALE) {
- mTvSex.setText("女");
- } else if (mAccountBean.getGenderEnum() == GenderEnum.MALE) {
- mTvSex.setText("男");
- } else {
- mTvSex.setText("保密");
- }
- mEtSignature.setText(mAccountBean.getSignature());
- String birthday = mAccountBean.getBirthDay();
- if (TextUtils.isEmpty(birthday)) {
- mTvBirthDay.setText("未设置");
- } else {
- mTvBirthDay.setText(birthday);
- }
- String location = mAccountBean.getLocation();
- if (TextUtils.isEmpty(location)) {
- mTvLocation.setText("未设置");
- } else {
- mTvLocation.setText(location);
- }
- }
- }
3. 初始化
mInputMethodManager用于控制显示或隐藏输入法面板
然后在可以为设置头像,性别,生日,地区,编辑状态,回退这些控件上添加OnClickListener
为编辑昵称和签名的控件上添加OnTouchListener
- private void init() {
- mInputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
- // 文字
- mLayoutHead.setOnClickListener(this);
- mTvSex.setOnClickListener(this);
- mTvBirthDay.setOnClickListener(this);
- mTvLocation.setOnClickListener(this);
- // 标题栏
- mIvBack.setOnClickListener(this);
- mIvMenu.setOnClickListener(this);
- // 输入框
- mEtNick.setOnTouchListener(this);
- mEtSignature.setOnTouchListener(this);
- // 结束编辑,相当于初始化为非编辑状态
- finishEdit();
- }
4. onClick
设置点击到不同控件时,可以设置对应的不同属性
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.layout_head:
- setHeadImg();
- break;
- case R.id.tv_account_sex:
- setSex();
- break;
- case R.id.tv_account_location:
- setLocation();
- break;
- case R.id.tv_account_birth:
- setBirthday();
- break;
- case R.id.iv_back_btn:
- this.finish();
- break;
- case R.id.iv_menu_btn:
- if (isEditor) {
- finishEdit();
- } else {
- startEdit();
- }
- break;
- }
- }
5. onTouch——用于设置要自行输入的几项属性(昵称,签名)
如果是要设置昵称和签名时,获取焦点并将光标移动到末尾
显示软键盘
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- if (isEditor) {
- if (v.getId() == R.id.et_account_nick) {
- mEtNick.requestFocus();
- mEtNick.setSelection(mEtNick.getText().length());
- mInputMethodManager.showSoftInput(mEtNick, 0);
- } else if (v.getId() == R.id.et_account_signature) {
- mEtSignature.requestFocus();
- mEtSignature.setSelection(mEtSignature.getText().length());
- mInputMethodManager.showSoftInput(mEtSignature, 0);
- }
- return true;
- }
- return false;
- }
6. 启动编辑
当右上方菜单栏为此图标时,处在编辑状态(即点击该图标,可进入结束编辑状态)
所有控件处于可点击(头像,性别,地区,生日)或可编辑(昵称,签名)状态
- private void startEdit() {
- mIvMenu.setImageResource(R.mipmap.done);
- // 可点击
- mLayoutHead.setClickable(true);
- mTvSex.setClickable(true);
- mTvLocation.setClickable(true);
- mTvBirthDay.setClickable(true);
- // 可编辑
- mEtNick.setFocusable(true);
- mEtNick.setFocusableInTouchMode(true);
- mEtSignature.setFocusable(true);
- mEtSignature.setFocusableInTouchMode(true);
- isEditor = true;
- }
7. 结束编辑
判断是否有修改
若有修改,通过NimUserHandler的setLocalAccount方法将数据更新到缓存,syncChange2Servive方法将数据更新到服务器
结束编辑后,右上方菜单栏图标变换为(即点击该图标,可重新进入编辑状态)
并将控件设置为不可点击(头像,性别,地区,生日),不可编辑(昵称,签名)状态
- private void finishEdit() {
- if (!mEtNick.getText().toString()
- .equals(mAccountBean.getNick())) {
- mAccountBean.setNick(mEtNick.getText().toString());
- haveAccountChange = true;
- }
- if (!mEtSignature.getText().toString()
- .equals(mAccountBean.getSignature())) {
- mAccountBean.setSignature(mEtSignature.getText().toString());
- haveAccountChange = true;
- }
- if (haveAccountChange) {
- // 将数据更新到缓存
- NimUserHandler.getInstance().setLocalAccount(mAccountBean);
- // 通知handler将数据更新到服务器
- NimUserHandler.getInstance().syncChange2Service();
- haveAccountChange = false;
- }
- mIvMenu.setImageResource(R.mipmap.editor);
- // 不可点击
- mLayoutHead.setClickable(false);
- mTvSex.setClickable(false);
- mTvLocation.setClickable(false);
- mTvBirthDay.setClickable(false);
- // 不可编辑
- mEtNick.setFocusable(false);
- mEtNick.setFocusableInTouchMode(false);
- mEtSignature.setFocusable(false);
- mEtSignature.setFocusableInTouchMode(false);
- isEditor = false;
- }
8. 设置性别
利用AlertDialog
- private void setSex(){
- final int[] selected = new int[1];
- if (mAccountBean.getGenderEnum() == GenderEnum.MALE) {
- selected[0] = 0;
- } else if (mAccountBean.getGenderEnum() == GenderEnum.FEMALE) {
- selected[0] = 1;
- } else {
- selected[0] = 2;
- }
- final String[] items = new String[]{"男", "女", "保密"};
- new AlertDialog.Builder(this)
- .setTitle("性别")
- .setSingleChoiceItems(items, selected[0], new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (which != selected[0]) {
- if (which == 0) {
- mAccountBean.setGenderEnum(GenderEnum.MALE);
- mTvSex.setText("男");
- } else if (which == 1) {
- mAccountBean.setGenderEnum(GenderEnum.FEMALE);
- mTvSex.setText("女");
- } else {
- mAccountBean.setGenderEnum(GenderEnum.UNKNOWN);
- mTvSex.setText("保密");
- }
- haveAccountChange = true;
- }
- dialog.dismiss();
- }
- }).create().show();
- }
9. 设置头像,拍照或选择照片
用LayoutInflater找到dialog_set_head_img.xml布局文件,并实例化
dialog_set_head_img.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@color/white_color"
- android:id="@+id/layout_dialog">
- <TextView
- android:id="@+id/tv_take_photo"
- android:layout_width="match_parent"
- android:layout_height="45dp"
- android:text="@string/dialog_take_photo"
- android:textColor="@color/app_black_color"
- android:textSize="18sp"
- android:gravity="center"/>
- <View
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="@color/interval_color"/>
- <TextView
- android:id="@+id/tv_select_img"
- android:layout_width="match_parent"
- android:layout_height="45dp"
- android:text="@string/dialog_select_photo"
- android:textColor="@color/app_black_color"
- android:textSize="18sp"
- android:gravity="center"/>
- </LinearLayout>
(1)为“拍照”控件添加OnClickListener
使用MediaStore.ACTION_IMAGE_CAPTURE打开照相机
设置图片路径,创建图片文件并保存
若出错,显示“启动相机出错!请重试”
(2)为“从相册中选择”控件添加OnClickListener
查询外置内存卡(EXTERNAL_CONTENT_URI)
选择类型为图片
- private void setHeadImg() {
- View view = LayoutInflater.from(this).inflate(R.layout.dialog_set_head_img, null);
- final AlertDialog alertDialog = new AlertDialog.Builder(this).setView(view).create();
- TextView take = (TextView) view.findViewById(R.id.tv_take_photo);
- TextView select = (TextView) view.findViewById(R.id.tv_select_img);
- take.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- alertDialog.dismiss();
- try {
- Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
- mHeadImgPath = Constant.APP_CACHE_PATH + File.separator + "image"
- + File.separator + mAccountBean.getAccount() + ".jpg";
- Uri uri = Uri.fromFile(new File(mHeadImgPath));
- intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);//设置图像文件名
- startActivityForResult(intent, TAKE_PHOTO);
- } catch (Exception e) {
- ToastUtils.showMessage(AccountInfoActivity.this, "启动相机出错!请重试");
- e.printStackTrace();
- }
- }
- });
- select.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- alertDialog.dismiss();
- Intent intent = new Intent(Intent.ACTION_PICK,
- MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
- intent.setType("image/*");
- startActivityForResult(Intent.createChooser(intent, "选择头像图片"), SELECT_PHOTO);
- }
- });
- alertDialog.show();
- }
10. 处理拍照回传数据
获取图片旋转角度
从图像路径获取bitmap,并根据给定的显示宽高对bitmap进行压缩(600x400)
根据给定的角度(bitmapDegree),对bitmap进行旋转
将bitmap保存到本地
显示,记录更新,同步至网易云服务器
- private void dealTakePhotoResult() {
- Flowable.just(mHeadImgPath)
- .map(new Function<String, Bitmap>() {
- @Override
- public Bitmap apply(String path) throws Exception {
- // 调整旋转角度,压缩
- int bitmapDegree = ImageUtils.getBitmapDegree(mHeadImgPath);
- Bitmap bitmap = ImageUtils.getBitmapFromFile(mHeadImgPath, 600, 400);
- bitmap = ImageUtils.rotateBitmapByDegree(bitmap, bitmapDegree);
- ImageUtils.saveBitmap2Jpg(bitmap, path);
- return bitmap;
- }
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(new Consumer<Bitmap>() {
- @Override
- public void accept(Bitmap bitmap) throws Exception {
- // 显示,记录更新,同步至网易云服务器
- if (bitmap != null) {
- // 上传至服务器
- uploadHeadImg(bitmap);
- }
- }
- });
- }
11. 得到回传数据
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if (resultCode == RESULT_OK) {
- if (requestCode == TAKE_PHOTO) {
- dealTakePhotoResult();
- } else if (requestCode == SELECT_PHOTO) {
- mHeadImgPath = ImageUtils.getFilePathFromUri(AccountInfoActivity.this, data.getData());
- dealTakePhotoResult();
- }
- }
- }
12. 将头像数据上传至网易云服务器存储,获取服务器返回URL
通过NimClient的getService接口获取到NosService(网易云存储服务)服务实例,调用upload方法上传到网易云服务器存储图像
- private void uploadHeadImg(final Bitmap bitmap) {
- AbortableFuture<String> upload = NIMClient.getService(NosService.class)
- .upload(new File(mHeadImgPath), "image/ipeg");
- upload.setCallback(new RequestCallback() {
- @Override
- public void onSuccess(Object param) {
- Log.e(TAG,"uploadHeadImg onSuccess url = " + param.toString());
- mIvHead.setImageBitmap(bitmap);
- // 保存图片本地路径和服务器路径
- mAccountBean.setHeadImgUrl(param.toString());
- haveAccountChange = true;
- }
- @Override
- public void onFailed(int code) {
- Log.e(TAG,"uploadHeadImg onFailed code " + code);
- ToastUtils.showMessage(AccountInfoActivity.this,
- "修改失败,头像上传失败,code:" + code);
- }
- @Override
- public void onException(Throwable exception) {
- Log.e(TAG,"uploadHeadImg onException message " + exception.getMessage());
- ToastUtils.showMessage(AccountInfoActivity.this,
- "修改失败,图像上传出错:" + exception.getMessage());
- }
- });
- }
- }