实训第六周(2)

李晨晨:

本次主要实现聊天消息列表中图片信息的LruCache保存实现。

1.首先初始化图片缓存,获取应用最大可用内存,取1/8作为缓存内存。

[java]  view plain  copy
  1. private Context mContext;  
  2.     private LruCache<String, Bitmap> mLruCache;  
  3.   
  4.     public ChatUtils(Context context){  
  5.         mContext = context;  
  6.   
  7.         //获取应用最大可用内存,取1/8作为缓存内存  
  8.         int maxMemory = (int) Runtime.getRuntime().maxMemory();  
  9.         int cacheMemory = maxMemory / 8;  
  10.         //初始化图片缓存  
  11.         mLruCache = new LruCache<String, Bitmap>(cacheMemory){  
  12.             @Override  
  13.             protected int sizeOf(String key, Bitmap value) {  
  14.                 //返回图片所占内存  
  15.                 return value.getRowBytes() * value.getHeight();  
  16.             }  
  17.         };  
  18.   
  19.     }  

2.获得图片消息附件,优先显示缩略图,缩略图不存在的情况下显示原图:

[java]  view plain  copy
  1. public Bitmap getBitmap(ImageAttachment attachment) {  
  2.   
  3.         // 优先显示缩略图,但是要限制宽高  
  4.         if (!TextUtils.isEmpty(attachment.getThumbPath())) {  
  5.             Bitmap bitmap = mLruCache.get(attachment.getThumbPath());  
  6.             if (bitmap == null){  
  7.                 bitmap = ImageUtils.getBitmapFromFile(attachment.getThumbPath(), 400180);  
  8.                 mLruCache.put(attachment.getThumbPath(),bitmap);  
  9.             }  
  10.   
  11.             return bitmap;  
  12.         }  
  13.   
  14.         // 缩略图不存在的情况下显示原图,但是要限制宽高  
  15.         if (!TextUtils.isEmpty(attachment.getPath())) {  
  16.             Bitmap bitmap = mLruCache.get(attachment.getPath());  
  17.             if (bitmap == null){  
  18.                 bitmap = ImageUtils.getBitmapFromFile(attachment.getPath(), 400180);  
  19.                 mLruCache.put(attachment.getPath(),bitmap);  
  20.             }  
  21.   
  22.             return bitmap;  
  23.         }  
  24.   
  25.         return null;  
  26.     }  

3.返回IMMessage的传输状态:

[java]  view plain  copy
  1. public  boolean isTransferring(IMMessage message) {  
  2.         return message.getStatus() == MsgStatusEnum.sending || (message.getAttachment() != null  
  3.                 && message.getAttachStatus() == AttachStatusEnum.transferring);  
  4.     }  

4.返回音频文件的时长(单位:秒)

[java]  view plain  copy
  1. public String getAudioTime(long duration) {  
  2.         return String.valueOf(duration / 1000.0) + "'";  
  3.     }  

5.MsgHeadView下拉后的加载条,用于下周的聊天列表RecycleView。

[java]  view plain  copy
  1. public class MsgHeadView extends LinearLayout {  
  2.   
  3.     private static final String TAG = MsgHeadView.class.getSimpleName();  
  4.     private LinearLayout mContainer;  
  5.     private int mHeadHeight;  
  6.   
  7.     public MsgHeadView(Context context) {  
  8.         this(context,null);  
  9.     }  
  10.   
  11.     public MsgHeadView(Context context, @Nullable AttributeSet attrs) {  
  12.         this(context, attrs,0);  
  13.     }  
  14.   
  15.     public MsgHeadView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {  
  16.         super(context, attrs, defStyleAttr);  
  17.         init();  
  18.     }  
  19.   
  20.     private void init(){  
  21.         mContainer = (LinearLayout) LayoutInflater.from(getContext()).inflate(R.layout.msg_head_view, null);  
  22.         LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);  
  23.         lp.setMargins(0000);  
  24.         this.setLayoutParams(lp);  
  25.         this.setPadding(0000);  
  26.         addView(mContainer, new LayoutParams(LayoutParams.MATCH_PARENT, 0));  
  27.         setGravity(Gravity.BOTTOM);  
  28.         int height = View.MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);  
  29.         int width = View.MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);  
  30.         mContainer.measure(width,height);  
  31.         mHeadHeight = mContainer.getMeasuredHeight();  
  32.     }  
  33.   
  34.     public int getHeadHeight(){  
  35.         return mHeadHeight;  
  36.     }  
  37.   
  38.     public void setVisibleHeight(int height) {  
  39.         if (height < 0) height = 0;  
  40.         LayoutParams lp = (LayoutParams) mContainer .getLayoutParams();  
  41.         lp.height = height;  
  42.         mContainer.setLayoutParams(lp);  
  43.     }  
  44.   
  45.     public int getVisibleHeight() {  
  46.         LayoutParams lp = (LayoutParams) mContainer.getLayoutParams();  
  47.         return lp.height;  
  48.     }  
  49.   
  50. }  

msg_head_view.xml

[java]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     android:id="@+id/msg_header_content"  
  5.     android:layout_width="match_parent"  
  6.     android:layout_height="wrap_content"  
  7.     android:orientation="vertical">  
  8.   
  9.     <ProgressBar  
  10.         android:id="@+id/progress"  
  11.         android:layout_width="match_parent"  
  12.         android:layout_height="20dp"  
  13.         android:indeterminate="true"  
  14.         android:indeterminateDrawable="@drawable/progress_bar_rotate"  
  15.         android:indeterminateBehavior="repeat"/>  

即图中的加载环




仝心:

这次实现了两个工具类的编程,日后用于注册账号和申请权限。

NimClientHandle

[java]  view plain  copy
  1. public static NimClientHandle getInstance() {  
  2.         if (instance == null) {  
  3.             synchronized (NimClientHandle.class) {  
  4.                 if (instance == null) {  
  5.                     instance = new NimClientHandle();  
  6.                 }  
  7.             }  
  8.         }  
  9.         return instance;  
  10.     }  
  11.   
  12.     private NimClientHandle() {  
  13.         initApi();  
  14.     }  
  15.   
  16.     private void initApi() {  
  17.         mOkHttpClient = new OkHttpClient();  
  18.     }  
  19.   
  20.     public void register(String account, String token, String name, final OnRegisterListener listener) {  
  21.   
  22.         RequestBody body = new FormBody.Builder()  
  23.                 .add("accid", account)  
  24.                 .add("token", token)  
  25.                 .add("name", name)  
  26.                 .build();  
  27.   
  28.         Request request = new Request.Builder()  
  29.                 .url(APP_SERVER_BASE_URL + mAppServerUserCreate)  
  30.                 .headers(createHeaders())  
  31.                 .post(body)  
  32.                 .build();  
  33.   
  34.         mOkHttpClient.newCall(request).enqueue(new Callback() {  
  35.             @Override  
  36.             public void onFailure(@NonNull Call call, @NonNull IOException e) {  
  37.                 listener.onFailed(e.getMessage());  
  38.             }  
  39.   
  40.             @Override  
  41.             public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {  
  42.                if (listener != null){  
  43.                    if (response.code() == 200){  
  44.                        listener.onSuccess();  
  45.                    }else {  
  46.                        listener.onFailed(response.message());  
  47.                    }  
  48.                }  
  49.             }  
  50.         });  
  51.   
  52.     }  
  53.   
  54.   
  55.     /** 
  56.      * 生成访问 NIM  APP-SERVICE 所要求的 HEADER 
  57.      * @return headers ,in OK HTTP3 
  58.      */  
  59.     private Headers createHeaders(){  
  60.         String nonce = CheckSumUtils.getNonce();  
  61.         String time = String.valueOf(System.currentTimeMillis() / 1000L);  
  62.         return new Headers.Builder()  
  63.                 .add("Content-Type","application/x-www-form-urlencoded;charset=utf-8")  
  64.                 .add("AppKey", readAppKey())  
  65.                 .add("Nonce", nonce)  
  66.                 .add("CurTime", time)  
  67.                 .add("CheckSum", CheckSumUtils.getCheckSum(Constant.APP_SECURY, nonce, time))  
  68.                 .build();  
  69.     }  
  70.     /** 
  71.      * 读取存储于manifest文件下的 APP KEY 
  72.      * 
  73.      * @return APP key 
  74.      */  
  75.     private String readAppKey() {  
  76.         try {  
  77.             ApplicationInfo appInfo = MyApplication.getInstance().getPackageManager()  
  78.                     .getApplicationInfo(MyApplication.getInstance().getPackageName(), PackageManager.GET_META_DATA);  
  79.             if (appInfo != null) {  
  80.                 return appInfo.metaData.getString("com.netease.nim.appKey");  
  81.             }  
  82.         } catch (Exception e) {  
  83.             e.printStackTrace();  
  84.             return "";  
  85.         }  
  86.         return "";  
  87.     }  
申请权限的PermissionUtils
[java]  view plain  copy
  1. @RequiresApi(api = Build.VERSION_CODES.M)  
  2.     public static boolean checkPermissions(Context context, String... permissions){  
  3.         for (String p : permissions){  
  4.             if (context.checkSelfPermission(p) != PackageManager.PERMISSION_GRANTED){  
  5.                 return false;  
  6.             }  
  7.         }  
  8.         return true;  
  9.     }  
  10.   
  11.     /** 
  12.      * 申请权限 
  13.      * @param activity Activity 
  14.      * @param requestCode 申请码 
  15.      * @param permissions 权限组 
  16.      */  
  17.     @RequiresApi(api = Build.VERSION_CODES.M)  
  18.     public static void requestPermissions(Activity activity, int requestCode, String... permissions){  
  19.         activity.requestPermissions(permissions,requestCode);  
  20.     }  
  21.   
  22.   
  23.     /** 
  24.      * 处理权限申请回调结果,分为 授权,拒绝未勾选不再提醒,拒绝并勾选不再提醒 三组结果返回 
  25.      * @param context 上下文 
  26.      * @param permission 申请的权限数组{@link ActivityCompat.OnRequestPermissionsResultCallback} 
  27.      * @param grantResult 申请结果数组{@link ActivityCompat.OnRequestPermissionsResultCallback} 
  28.      * @param callBack 处理回调接口 {@link RequestPermissionCallBack} 
  29.      */  
  30.     public static void dealPermissionResult(Context context,String[] permission,  
  31.                                             int[] grantResult,RequestPermissionCallBack callBack){  
  32.         List<String> grant = new ArrayList<>();  
  33.         List<String> denied = new ArrayList<>();  
  34.         List<String> neverAsk = new ArrayList<>();  
  35.         for (int i=0;i<grantResult.length;i++){  
  36.             if (grantResult[i] == PackageManager.PERMISSION_GRANTED){  
  37.                 grant.add(permission[i]);  
  38.             }else {  
  39.                 if (judgePermission(context,permission[i])){  
  40.                     denied.add(permission[i]);  
  41.                 }else {  
  42.                     neverAsk.add(permission[i]);  
  43.                 }  
  44.             }  
  45.         }  
  46.   
  47.         if (!grant.isEmpty()){  
  48.             callBack.onGrant(list2Array(grant));  
  49.         }  
  50.         if (!denied.isEmpty()){  
  51.             callBack.onDenied(list2Array(denied));  
  52.         }  
  53.         if (!neverAsk.isEmpty()){  
  54.             callBack.onDeniedAndNeverAsk(list2Array(neverAsk));  
  55.         }  
  56.     }  
  57.   
  58.     /** 
  59.      * 对于用户拒绝并勾选不再提醒的权限进行提示和辅助跳转到权限管理页面 
  60.      * @param context 上下文 
  61.      * @param message 权限需求说明 
  62.      */  
  63.     public static void requestPermissionDialog(final Context context, String message){  
  64.   
  65.         new AlertDialog.Builder(context)  
  66.                 .setTitle("权限申请")  
  67.                 .setMessage(message)  
  68.                 .setPositiveButton("授权"new DialogInterface.OnClickListener() {  
  69.                     @Override  
  70.                     public void onClick(DialogInterface dialog, int which) {  
  71.                         Intent intent = new Intent();  
  72.                         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  73.                         intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");  
  74.                         intent.setData(Uri.fromParts("package", context.getPackageName(), null));  
  75.                         context.startActivity(intent);  
  76.   
  77.                         // 跳转后请在 onRestart 在中再次检查权限是否已获取  
  78.                     }  
  79.                 })  
  80.                 .setNegativeButton("拒绝"new DialogInterface.OnClickListener() {  
  81.                     @Override  
  82.                     public void onClick(DialogInterface dialog, int which) {  
  83.                         ToastUtils.showMessage(context,"未能获取权限,部分功能将受限");  
  84.                     }  
  85.                 })  
  86.                 .show();  
  87.     }  
  88.   
  89.   
  90.     /** 
  91.      * 判断是否已拒绝过权限 
  92.      * 如果应用之前请求过此权限但用户拒绝,此方法将返回 true; 
  93.      * -----如果应用第一次请求权限或 用户在过去拒绝了权限请求, 
  94.      * -----并在权限请求系统对话框中选择了 Don't ask again 选项,此方法将返回 false。 
  95.      */  
  96.     private static boolean judgePermission(Context context, String permission) {  
  97.         return  ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, permission);  
  98.     }  
  99.   
  100.   
  101.     private static String[] list2Array(List<String> list){  
  102.         String[]  array = new String[list.size()];  
  103.         for (int i=0;i<list.size();i++){  
  104.             array[i] = list.get(i);  
  105.         }  
  106.         return array;  
  107.     }  
  108.   
  109.     /** 
  110.      * 权限处理返回接口 
  111.      */  
  112.     public interface RequestPermissionCallBack {  
  113.   
  114.         /** 
  115.          * 用户授予权限 
  116.          * @param  permissions 已获得授权的权限 
  117.          */  
  118.         void onGrant(String... permissions);  
  119.   
  120.         /** 
  121.          * 用户拒绝,(未勾选不再提醒) 
  122.          * @param permissions 被拒绝的权限 
  123.          */  
  124.         void onDenied(String... permissions);  
  125.   
  126.         /** 
  127.          * 用户拒绝,并且已勾选不再询问选项 
  128.          * @param permissions 被拒绝的权限 
  129.          */  
  130.         void onDeniedAndNeverAsk(String... permissions);  
  131.     }  

CheckSumUtils

[java]  view plain  copy
  1. private static final char[] HEX_DIGITS = { '0''1''2''3''4''5',  
  2.             '6''7''8''9''a''b''c''d''e''f' };  
  3.   
  4.     // 计算并获取CheckSum  
  5.     public static String getCheckSum(String appSecret, String nonce, String curTime) {  
  6.         return encode("sha1", appSecret + nonce + curTime);  
  7.     }  
  8.   
  9.     // 计算并获取md5值  
  10.     public static String getMD5(String requestBody) {  
  11.         return encode("md5", requestBody);  
  12.     }  
  13.   
  14.     // 生成随机字符串  
  15.     public static String getNonce(){  
  16.         String retStr;  
  17.         String strTable = "1234567890abcdefghijkmnpqrstuvwxyz";  
  18.         int len = strTable.length();  
  19.         boolean bDone = true;  
  20.         do {  
  21.             retStr = "";  
  22.             int count = 0;  
  23.             for (int i = 0; i < strTable.length(); i++) {  
  24.                 double dblR = Math.random() * len;  
  25.                 int intR = (int) Math.floor(dblR);  
  26.                 char c = strTable.charAt(intR);  
  27.                 if (('0' <= c) && (c <= '9')) {  
  28.                     count++;  
  29.                 }  
  30.                 retStr += strTable.charAt(intR);  
  31.             }  
  32.             if (count >= 2) {  
  33.                 bDone = false;  
  34.             }  
  35.         } while (bDone);  
  36.   
  37.         return retStr;  
  38.     }  
  39.   
  40.     private static String encode(String algorithm, String value) {  
  41.         if (value == null) {  
  42.             return null;  
  43.         }  
  44.         try {  
  45.             MessageDigest messageDigest  
  46.                     = MessageDigest.getInstance(algorithm);  
  47.             messageDigest.update(value.getBytes());  
  48.             return getFormattedText(messageDigest.digest());  
  49.         } catch (Exception e) {  
  50.             throw new RuntimeException(e);  
  51.         }  
  52.     }  
  53.   
  54.     private static String getFormattedText(byte[] bytes) {  
  55.         int len = bytes.length;  
  56.         StringBuilder buf = new StringBuilder(len * 2);  
  57.         for (byte aByte : bytes) {  
  58.             buf.append(HEX_DIGITS[(aByte >> 4) & 0x0f]);  
  59.             buf.append(HEX_DIGITS[aByte & 0x0f]);  
  60.         }  
  61.         return buf.toString();  
  62.     }  







张静:

接下来完成MeFragment中可选择进入的AccountInfoActivity(账号信息详情页),可修改个人信息

1. activity_account_info.xml

[java]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     xmlns:app="http://schemas.android.com/apk/res-auto"  
  7.     android:orientation="vertical"  
  8.     android:fitsSystemWindows="true">  
  9.   
  10.     <include layout="@layout/title_layout"/>  
  11.   
  12.     <LinearLayout  
  13.         android:layout_width="match_parent"  
  14.         android:layout_height="match_parent"  
  15.         android:orientation="vertical"  
  16.         android:background="@color/interval_color">  
  17.   
  18.         <View  
  19.             android:layout_width="match_parent"  
  20.             android:layout_height="10dp"/>  
  21.   
  22.         <RelativeLayout  
  23.             android:id="@+id/layout_head"  
  24.             android:background="@color/white_color"  
  25.             android:layout_width="match_parent"  
  26.             android:paddingLeft="10dp"  
  27.             android:paddingRight="10dp"  
  28.             android:layout_height="80dp">  
  29.   
  30.             <TextView  
  31.                 android:text="@string/account_head_picture"  
  32.                 android:gravity="center_vertical"  
  33.                 android:layout_width="wrap_content"  
  34.                 android:layout_height="match_parent"  
  35.                 android:textSize="16sp"  
  36.                 android:textColor="@color/app_black_color"/>  
  37.   
  38.             <com.joooonho.SelectableRoundedImageView  
  39.                 android:id="@+id/iv_head_picture"  
  40.                 android:layout_alignParentRight="true"  
  41.                 android:layout_marginTop="5dp"  
  42.                 android:layout_marginBottom="5dp"  
  43.                 android:layout_width="70dp"  
  44.                 android:scaleType="fitXY"  
  45.                 app:sriv_oval="true"  
  46.                 android:src="@mipmap/app_logo_main"  
  47.                 android:layout_height="70dp"/>  
  48.         </RelativeLayout>  
  49.         <View  
  50.             android:layout_width="match_parent"  
  51.             android:layout_height="0.8dp"/>  
  52.   
  53.         <RelativeLayout  
  54.             android:background="@color/white_color"  
  55.             android:layout_width="match_parent"  
  56.             android:paddingLeft="10dp"  
  57.             android:paddingRight="10dp"  
  58.             android:layout_height="40dp">  
  59.   
  60.             <TextView  
  61.                 android:id="@+id/tv_1"  
  62.                 android:text="账号"  
  63.                 android:gravity="center_vertical"  
  64.                 android:layout_width="wrap_content"  
  65.                 android:layout_height="match_parent"  
  66.                 android:textSize="16sp"  
  67.                 android:textColor="@color/app_black_color"/>  
  68.   
  69.             <TextView  
  70.                 android:layout_toRightOf="@+id/tv_1"  
  71.                 android:layout_marginLeft="10dp"  
  72.                 android:textSize="16sp"  
  73.                 android:textColor="@color/default_text_color"  
  74.                 android:id="@+id/tv_account"  
  75.                 android:gravity="center_vertical|right"  
  76.                 android:layout_width="match_parent"  
  77.                 android:layout_height="match_parent"/>  
  78.         </RelativeLayout>  
  79.   
  80.         <View  
  81.             android:layout_width="match_parent"  
  82.             android:layout_height="0.8dp"/>  
  83.   
  84.         <RelativeLayout  
  85.             android:background="@color/white_color"  
  86.             android:layout_width="match_parent"  
  87.             android:paddingLeft="10dp"  
  88.             android:paddingRight="10dp"  
  89.             android:layout_height="40dp">  
  90.             <TextView  
  91.                 android:id="@+id/tv_2"  
  92.                 android:text="@string/account_nick"  
  93.                 android:gravity="center_vertical"  
  94.                 android:layout_width="wrap_content"  
  95.                 android:layout_height="match_parent"  
  96.                 android:textSize="16sp"  
  97.                 android:textColor="@color/app_black_color"/>  
  98.   
  99.             <EditText  
  100.                 android:layout_toRightOf="@+id/tv_2"  
  101.                 android:layout_marginLeft="10dp"  
  102.                 android:textSize="16sp"  
  103.                 android:textColor="@color/default_text_color"  
  104.                 android:id="@+id/et_account_nick"  
  105.                 android:gravity="center_vertical|right"  
  106.                 android:layout_width="match_parent"  
  107.                 android:background="@null"  
  108.                 android:layout_height="match_parent"/>  
  109.         </RelativeLayout>  
  110.   
  111.         <View  
  112.             android:layout_width="match_parent"  
  113.             android:layout_height="0.8dp"/>  
  114.   
  115.         <RelativeLayout  
  116.             android:background="@color/white_color"  
  117.             android:layout_width="match_parent"  
  118.             android:paddingLeft="10dp"  
  119.             android:paddingRight="10dp"  
  120.             android:layout_height="40dp">  
  121.             <TextView  
  122.                 android:id="@+id/tv_3"  
  123.                 android:text="@string/account_sex"  
  124.                 android:gravity="center_vertical"  
  125.                 android:layout_width="wrap_content"  
  126.                 android:layout_height="match_parent"  
  127.                 android:textSize="16sp"  
  128.                 android:textColor="@color/app_black_color"/>  
  129.   
  130.             <TextView  
  131.                 android:layout_toRightOf="@+id/tv_3"  
  132.                 android:layout_marginLeft="10dp"  
  133.                 android:textSize="16sp"  
  134.                 android:textColor="@color/default_text_color"  
  135.                 android:id="@+id/tv_account_sex"  
  136.                 android:gravity="center_vertical|right"  
  137.                 android:layout_width="match_parent"  
  138.                 android:layout_height="match_parent"/>  
  139.         </RelativeLayout>  
  140.   
  141.         <View  
  142.             android:layout_width="match_parent"  
  143.             android:layout_height="0.8dp"/>  
  144.   
  145.         <RelativeLayout  
  146.             android:background="@color/white_color"  
  147.             android:layout_width="match_parent"  
  148.             android:paddingLeft="10dp"  
  149.             android:paddingRight="10dp"  
  150.             android:layout_height="40dp">  
  151.   
  152.             <TextView  
  153.                 android:id="@+id/tv_4"  
  154.                 android:text="@string/account_birth"  
  155.                 android:gravity="center_vertical"  
  156.                 android:layout_width="wrap_content"  
  157.                 android:layout_height="match_parent"  
  158.                 android:textSize="16sp"  
  159.                 android:textColor="@color/app_black_color"/>  
  160.   
  161.             <TextView  
  162.                 android:layout_toRightOf="@+id/tv_4"  
  163.                 android:layout_marginLeft="10dp"  
  164.                 android:textSize="16sp"  
  165.                 android:textColor="@color/default_text_color"  
  166.                 android:id="@+id/tv_account_birth"  
  167.                 android:gravity="center_vertical|right"  
  168.                 android:layout_width="match_parent"  
  169.                 android:layout_height="match_parent"/>  
  170.         </RelativeLayout>  
  171.   
  172.         <View  
  173.             android:layout_width="match_parent"  
  174.             android:layout_height="0.8dp"/>  
  175.   
  176.         <RelativeLayout  
  177.             android:background="@color/white_color"  
  178.             android:layout_width="match_parent"  
  179.             android:paddingLeft="10dp"  
  180.             android:paddingRight="10dp"  
  181.             android:layout_height="40dp">  
  182.             <TextView  
  183.                 android:id="@+id/tv_5"  
  184.                 android:text="@string/account_location"  
  185.                 android:gravity="center_vertical"  
  186.                 android:layout_width="wrap_content"  
  187.                 android:layout_height="match_parent"  
  188.                 android:textSize="16sp"  
  189.                 android:textColor="@color/app_black_color"/>  
  190.   
  191.             <TextView  
  192.                 android:layout_toRightOf="@+id/tv_5"  
  193.                 android:layout_marginLeft="10dp"  
  194.                 android:gravity="center_vertical|right"  
  195.                 android:textSize="16sp"  
  196.                 android:textColor="@color/default_text_color"  
  197.                 android:id="@+id/tv_account_location"  
  198.                 android:layout_width="match_parent"  
  199.                 android:layout_height="match_parent"/>  
  200.         </RelativeLayout>  
  201.         <View  
  202.             android:layout_width="match_parent"  
  203.             android:layout_height="0.8dp"/>  
  204.   
  205.         <RelativeLayout  
  206.             android:background="@color/white_color"  
  207.             android:layout_width="match_parent"  
  208.             android:paddingLeft="10dp"  
  209.             android:paddingRight="10dp"  
  210.             android:layout_height="60dp">  
  211.   
  212.             <TextView  
  213.                 android:id="@+id/tv_6"  
  214.                 android:text="@string/account_signature"  
  215.                 android:gravity="center_vertical"  
  216.                 android:layout_width="wrap_content"  
  217.                 android:layout_height="match_parent"  
  218.                 android:textSize="16sp"  
  219.                 android:textColor="@color/app_black_color"/>  
  220.   
  221.             <EditText  
  222.                 android:hint="@string/signature_hint"  
  223.                 android:layout_toRightOf="@+id/tv_6"  
  224.                 android:layout_marginLeft="10dp"  
  225.                 android:textSize="16sp"  
  226.                 android:textColor="@color/default_text_color"  
  227.                 android:id="@+id/et_account_signature"  
  228.                 android:gravity="center_vertical|right"  
  229.                 android:maxLines="2"  
  230.                 android:background="@null"  
  231.                 android:layout_width="match_parent"  
  232.                 android:layout_height="match_parent"/>  
  233.         </RelativeLayout>  
  234.     </LinearLayout>  
  235.   
  236. </LinearLayout>  


2. 显示数据

通过NimUserHandler获得本地账户,由在本地账户中设置的属性数据设置个人信息页并显示

[java]  view plain  copy
  1. private void showData() {  
  2.     mAccountBean = NimUserHandler.getInstance().getLocalAccount();  
  3.     if (mAccountBean != null) {  
  4.         ImageUtils.setImageByFile(this, mIvHead,  
  5.                 mAccountBean.getHeadImgUrl(), R.mipmap.bg_img_defalut);  
  6.         mTvAccount.setText(mAccountBean.getAccount());  
  7.         mEtNick.setText(mAccountBean.getNick());  
  8.         if (mAccountBean.getGenderEnum() == GenderEnum.FEMALE) {  
  9.             mTvSex.setText("女");  
  10.         } else if (mAccountBean.getGenderEnum() == GenderEnum.MALE) {  
  11.             mTvSex.setText("男");  
  12.         } else {  
  13.             mTvSex.setText("保密");  
  14.         }  
  15.         mEtSignature.setText(mAccountBean.getSignature());  
  16.         String birthday = mAccountBean.getBirthDay();  
  17.         if (TextUtils.isEmpty(birthday)) {  
  18.             mTvBirthDay.setText("未设置");  
  19.         } else {  
  20.             mTvBirthDay.setText(birthday);  
  21.         }  
  22.         String location = mAccountBean.getLocation();  
  23.         if (TextUtils.isEmpty(location)) {  
  24.             mTvLocation.setText("未设置");  
  25.         } else {  
  26.             mTvLocation.setText(location);  
  27.         }  
  28.     }  
  29. }  


3. 初始化

mInputMethodManager用于控制显示或隐藏输入法面板

然后在可以为设置头像,性别,生日,地区,编辑状态,回退这些控件上添加OnClickListener

为编辑昵称和签名的控件上添加OnTouchListener

[java]  view plain  copy
  1. private void init() {  
  2.         mInputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);  
  3.         // 文字  
  4.         mLayoutHead.setOnClickListener(this);  
  5.         mTvSex.setOnClickListener(this);  
  6.         mTvBirthDay.setOnClickListener(this);  
  7.         mTvLocation.setOnClickListener(this);  
  8.   
  9.         // 标题栏  
  10.         mIvBack.setOnClickListener(this);  
  11.         mIvMenu.setOnClickListener(this);  
  12.   
  13.         // 输入框  
  14.         mEtNick.setOnTouchListener(this);  
  15.         mEtSignature.setOnTouchListener(this);  
  16.   
  17.         // 结束编辑,相当于初始化为非编辑状态  
  18.         finishEdit();  
  19.     }  

4. onClick 

设置点击到不同控件时,可以设置对应的不同属性

[java]  view plain  copy
  1. @Override  
  2.     public void onClick(View v) {  
  3.         switch (v.getId()) {  
  4.             case R.id.layout_head:  
  5.                 setHeadImg();  
  6.                 break;  
  7.             case R.id.tv_account_sex:  
  8.                 setSex();  
  9.                 break;  
  10.             case R.id.tv_account_location:  
  11.                 setLocation();  
  12.                 break;  
  13.             case R.id.tv_account_birth:  
  14.                 setBirthday();  
  15.                 break;  
  16.             case R.id.iv_back_btn:  
  17.                 this.finish();  
  18.                 break;  
  19.             case R.id.iv_menu_btn:  
  20.                 if (isEditor) {  
  21.                     finishEdit();  
  22.                 } else {  
  23.                     startEdit();  
  24.                 }  
  25.                 break;  
  26.         }  
  27.     }  


5. onTouch——用于设置要自行输入的几项属性(昵称,签名)

如果是要设置昵称和签名时,获取焦点并将光标移动到末尾

显示软键盘

[java]  view plain  copy
  1. @Override  
  2. public boolean onTouch(View v, MotionEvent event) {  
  3.     if (isEditor) {  
  4.         if (v.getId() == R.id.et_account_nick) {  
  5.             mEtNick.requestFocus();  
  6.             mEtNick.setSelection(mEtNick.getText().length());  
  7.             mInputMethodManager.showSoftInput(mEtNick, 0);  
  8.         } else if (v.getId() == R.id.et_account_signature) {  
  9.             mEtSignature.requestFocus();  
  10.             mEtSignature.setSelection(mEtSignature.getText().length());  
  11.             mInputMethodManager.showSoftInput(mEtSignature, 0);  
  12.         }  
  13.         return true;  
  14.     }  
  15.     return false;  
  16. }  


6. 启动编辑

当右上方菜单栏为此图标时,处在编辑状态(即点击该图标,可进入结束编辑状态)

所有控件处于可点击(头像,性别,地区,生日)或可编辑(昵称,签名)状态

[java]  view plain  copy
  1. private void startEdit() {  
  2.     mIvMenu.setImageResource(R.mipmap.done);  
  3.     // 可点击  
  4.     mLayoutHead.setClickable(true);  
  5.     mTvSex.setClickable(true);  
  6.     mTvLocation.setClickable(true);  
  7.     mTvBirthDay.setClickable(true);  
  8.     // 可编辑  
  9.     mEtNick.setFocusable(true);  
  10.     mEtNick.setFocusableInTouchMode(true);  
  11.     mEtSignature.setFocusable(true);  
  12.     mEtSignature.setFocusableInTouchMode(true);  
  13.   
  14.     isEditor = true;  
  15. }  


7. 结束编辑

判断是否有修改

若有修改,通过NimUserHandler的setLocalAccount方法将数据更新到缓存,syncChange2Servive方法将数据更新到服务器

结束编辑后,右上方菜单栏图标变换为(即点击该图标,可重新进入编辑状态)

并将控件设置为不可点击(头像,性别,地区,生日),不可编辑(昵称,签名)状态

[java]  view plain  copy
  1. private void finishEdit() {  
  2.      if (!mEtNick.getText().toString()  
  3.              .equals(mAccountBean.getNick())) {  
  4.          mAccountBean.setNick(mEtNick.getText().toString());  
  5.          haveAccountChange = true;  
  6.      }  
  7.   
  8.      if (!mEtSignature.getText().toString()  
  9.              .equals(mAccountBean.getSignature())) {  
  10.          mAccountBean.setSignature(mEtSignature.getText().toString());  
  11.          haveAccountChange = true;  
  12.      }  
  13.   
  14.      if (haveAccountChange) {  
  15.   
  16.          // 将数据更新到缓存  
  17.          NimUserHandler.getInstance().setLocalAccount(mAccountBean);  
  18.          // 通知handler将数据更新到服务器  
  19.          NimUserHandler.getInstance().syncChange2Service();  
  20.   
  21.          haveAccountChange = false;  
  22.      }  
  23.   
  24.      mIvMenu.setImageResource(R.mipmap.editor);  
  25.      // 不可点击  
  26.      mLayoutHead.setClickable(false);  
  27.      mTvSex.setClickable(false);  
  28.      mTvLocation.setClickable(false);  
  29.      mTvBirthDay.setClickable(false);  
  30.      // 不可编辑  
  31.      mEtNick.setFocusable(false);  
  32.      mEtNick.setFocusableInTouchMode(false);  
  33.      mEtSignature.setFocusable(false);  
  34.      mEtSignature.setFocusableInTouchMode(false);  
  35.   
  36.      isEditor = false;  
  37.  }  


8. 设置性别

利用AlertDialog

[java]  view plain  copy
  1. private void setSex(){  
  2.     final int[] selected = new int[1];  
  3.     if (mAccountBean.getGenderEnum() == GenderEnum.MALE) {  
  4.         selected[0] = 0;  
  5.     } else if (mAccountBean.getGenderEnum() == GenderEnum.FEMALE) {  
  6.         selected[0] = 1;  
  7.     } else {  
  8.         selected[0] = 2;  
  9.     }  
  10.     final String[] items = new String[]{"男""女""保密"};  
  11.     new AlertDialog.Builder(this)  
  12.             .setTitle("性别")  
  13.             .setSingleChoiceItems(items, selected[0], new DialogInterface.OnClickListener() {  
  14.                 @Override  
  15.                 public void onClick(DialogInterface dialog, int which) {  
  16.                     if (which != selected[0]) {  
  17.                         if (which == 0) {  
  18.                             mAccountBean.setGenderEnum(GenderEnum.MALE);  
  19.                             mTvSex.setText("男");  
  20.                         } else if (which == 1) {  
  21.                             mAccountBean.setGenderEnum(GenderEnum.FEMALE);  
  22.                             mTvSex.setText("女");  
  23.                         } else {  
  24.                             mAccountBean.setGenderEnum(GenderEnum.UNKNOWN);  
  25.                             mTvSex.setText("保密");  
  26.                         }  
  27.                         haveAccountChange = true;  
  28.                     }  
  29.                     dialog.dismiss();  
  30.                 }  
  31.             }).create().show();  
  32. }  


9. 设置头像,拍照或选择照片

用LayoutInflater找到dialog_set_head_img.xml布局文件,并实例化

dialog_set_head_img.xml


[java]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     android:orientation="vertical"  
  5.     android:layout_width="match_parent"  
  6.     android:layout_height="match_parent"  
  7.     android:background="@color/white_color"  
  8.     android:id="@+id/layout_dialog">  
  9.   
  10.     <TextView  
  11.         android:id="@+id/tv_take_photo"  
  12.         android:layout_width="match_parent"  
  13.         android:layout_height="45dp"  
  14.         android:text="@string/dialog_take_photo"  
  15.         android:textColor="@color/app_black_color"  
  16.         android:textSize="18sp"  
  17.         android:gravity="center"/>  
  18.   
  19.     <View  
  20.         android:layout_width="match_parent"  
  21.         android:layout_height="1dp"  
  22.         android:background="@color/interval_color"/>  
  23.   
  24.     <TextView  
  25.         android:id="@+id/tv_select_img"  
  26.         android:layout_width="match_parent"  
  27.         android:layout_height="45dp"  
  28.         android:text="@string/dialog_select_photo"  
  29.         android:textColor="@color/app_black_color"  
  30.         android:textSize="18sp"  
  31.         android:gravity="center"/>  
  32. </LinearLayout>  

(1)为“拍照”控件添加OnClickListener

使用MediaStore.ACTION_IMAGE_CAPTURE打开照相机

设置图片路径,创建图片文件并保存

若出错,显示“启动相机出错!请重试”

(2)为“从相册中选择”控件添加OnClickListener

查询外置内存卡(EXTERNAL_CONTENT_URI)

选择类型为图片

[java]  view plain  copy
  1. private void setHeadImg() {  
  2.         View view = LayoutInflater.from(this).inflate(R.layout.dialog_set_head_img, null);  
  3.         final AlertDialog alertDialog = new AlertDialog.Builder(this).setView(view).create();  
  4.         TextView take = (TextView) view.findViewById(R.id.tv_take_photo);  
  5.         TextView select = (TextView) view.findViewById(R.id.tv_select_img);  
  6.         take.setOnClickListener(new View.OnClickListener() {  
  7.             @Override  
  8.             public void onClick(View v) {  
  9.                 alertDialog.dismiss();  
  10.                 try {  
  11.                     Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);  
  12.                     mHeadImgPath = Constant.APP_CACHE_PATH + File.separator + "image"  
  13.                             + File.separator + mAccountBean.getAccount() + ".jpg";  
  14.                     Uri uri = Uri.fromFile(new File(mHeadImgPath));  
  15.                     intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);//设置图像文件名  
  16.                     startActivityForResult(intent, TAKE_PHOTO);  
  17.                 } catch (Exception e) {  
  18.                     ToastUtils.showMessage(AccountInfoActivity.this"启动相机出错!请重试");  
  19.                     e.printStackTrace();  
  20.                 }  
  21.   
  22.             }  
  23.         });  
  24.         select.setOnClickListener(new View.OnClickListener() {  
  25.             @Override  
  26.             public void onClick(View v) {  
  27.                 alertDialog.dismiss();  
  28.                 Intent intent = new Intent(Intent.ACTION_PICK,  
  29.                         MediaStore.Images.Media.EXTERNAL_CONTENT_URI);  
  30.                 intent.setType("image/*");  
  31.                 startActivityForResult(Intent.createChooser(intent, "选择头像图片"), SELECT_PHOTO);  
  32.             }  
  33.         });  
  34.         alertDialog.show();  
  35.     }  


10. 处理拍照回传数据

获取图片旋转角度

从图像路径获取bitmap,并根据给定的显示宽高对bitmap进行压缩(600x400)

根据给定的角度(bitmapDegree),对bitmap进行旋转

将bitmap保存到本地

显示,记录更新,同步至网易云服务器

[java]  view plain  copy
  1. private void dealTakePhotoResult() {  
  2.     Flowable.just(mHeadImgPath)  
  3.             .map(new Function<String, Bitmap>() {  
  4.                 @Override  
  5.                 public Bitmap apply(String path) throws Exception {  
  6.                     // 调整旋转角度,压缩  
  7.                     int bitmapDegree = ImageUtils.getBitmapDegree(mHeadImgPath);  
  8.                     Bitmap bitmap = ImageUtils.getBitmapFromFile(mHeadImgPath, 600400);  
  9.                     bitmap = ImageUtils.rotateBitmapByDegree(bitmap, bitmapDegree);  
  10.                     ImageUtils.saveBitmap2Jpg(bitmap, path);  
  11.                     return bitmap;  
  12.                 }  
  13.             })  
  14.             .subscribeOn(Schedulers.io())  
  15.             .observeOn(AndroidSchedulers.mainThread())  
  16.             .subscribe(new Consumer<Bitmap>() {  
  17.                 @Override  
  18.                 public void accept(Bitmap bitmap) throws Exception {  
  19.                     // 显示,记录更新,同步至网易云服务器  
  20.                     if (bitmap != null) {  
  21.                         // 上传至服务器  
  22.                         uploadHeadImg(bitmap);  
  23.                     }  
  24.                 }  
  25.             });  
  26. }  


11. 得到回传数据

[java]  view plain  copy
  1. @Override  
  2. protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
  3.     super.onActivityResult(requestCode, resultCode, data);  
  4.     if (resultCode == RESULT_OK) {  
  5.         if (requestCode == TAKE_PHOTO) {  
  6.             dealTakePhotoResult();  
  7.         } else if (requestCode == SELECT_PHOTO) {  
  8.             mHeadImgPath = ImageUtils.getFilePathFromUri(AccountInfoActivity.this, data.getData());  
  9.             dealTakePhotoResult();  
  10.         }  
  11.     }  
  12. }  


12. 将头像数据上传至网易云服务器存储,获取服务器返回URL

通过NimClient的getService接口获取到NosService(网易云存储服务)服务实例,调用upload方法上传到网易云服务器存储图像

[java]  view plain  copy
  1.     private void uploadHeadImg(final Bitmap bitmap) {  
  2.         AbortableFuture<String> upload = NIMClient.getService(NosService.class)  
  3.                 .upload(new File(mHeadImgPath), "image/ipeg");  
  4.         upload.setCallback(new RequestCallback() {  
  5.             @Override  
  6.             public void onSuccess(Object param) {  
  7.                 Log.e(TAG,"uploadHeadImg onSuccess url = " + param.toString());  
  8.                 mIvHead.setImageBitmap(bitmap);  
  9.                 // 保存图片本地路径和服务器路径  
  10.                 mAccountBean.setHeadImgUrl(param.toString());  
  11.                 haveAccountChange = true;  
  12.             }  
  13.   
  14.             @Override  
  15.             public void onFailed(int code) {  
  16.                 Log.e(TAG,"uploadHeadImg onFailed code " + code);  
  17.                 ToastUtils.showMessage(AccountInfoActivity.this,  
  18.                         "修改失败,头像上传失败,code:" + code);  
  19.             }  
  20.   
  21.             @Override  
  22.             public void onException(Throwable exception) {  
  23.                 Log.e(TAG,"uploadHeadImg onException message " + exception.getMessage());  
  24.                 ToastUtils.showMessage(AccountInfoActivity.this,  
  25.                         "修改失败,图像上传出错:" + exception.getMessage());  
  26.             }  
  27.         });  
  28.     }  
  29.   
  30. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值