李晨晨:
本次主要实现点击图片消息显示原图(ShowImageActivity)非常简单的界面
- public class ShowImageActivity extends BaseActivity {
- private static final String TAG = ShowImageActivity.class.getSimpleName();
- @BindView(R.id.image_view)
- PhotoView mIvImage;
- private IMMessage mMessage;
- private Bitmap bitmap;
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- //隐藏系统状态栏
- if (getSupportActionBar() != null) {
- getSupportActionBar().hide();
- }
- //requestWindowFeature(Window.FEATURE_NO_TITLE);
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
- WindowManager.LayoutParams.FLAG_FULLSCREEN);
- setContentView(R.layout.activity_show_image);
- ButterKnife.bind(this);
- initImage();
- }
- private void initImage() {
- mIvImage.setMaxScale(4);
- mIvImage.enable();
- mMessage = (IMMessage) getIntent().getSerializableExtra("IMMessage");
- if (mMessage == null) {
- ToastUtils.showMessage(this, "图片无法显示,请重试~");
- finish();
- return;
- }
- String path = ((ImageAttachment) mMessage.getAttachment()).getPath();
- // 原图已经下载,显示原图
- if (mMessage.getAttachStatus() == AttachStatusEnum.transferred
- && !TextUtils.isEmpty(path)) {
- Bitmap origin_bitmap = BitmapFactory.decodeFile(path);
- int height = (int) (origin_bitmap.getHeight() * (512.0 / origin_bitmap.getWidth()));
- bitmap = Bitmap.createScaledBitmap(origin_bitmap, 512, height, true);
- if (bitmap != null) {
- mIvImage.setImageBitmap(bitmap);
- } else {
- ToastUtils.showMessage(ShowImageActivity.this, "原图 下载/显示 失败,请重试~");
- finish();
- }
- }
- }
- @Override
- protected void onResume() {
- super.onResume();
- }
- @Override
- protected void onDestroy() {
- if (bitmap != null && !bitmap.isRecycled())
- bitmap.recycle();//防止图片过大造成java.lang.OutOfMemoryError
- super.onDestroy();
- }
- }
有的图片比较大,在显示是会报错,通过上网搜素解决方法,最终决定缩放原图在显示:
- int height = (int) (origin_bitmap.getHeight() * (512.0 / origin_bitmap.getWidth()));
- bitmap = Bitmap.createScaledBitmap(origin_bitmap, 512, height, true);
最终效果如下图,因为用的PhotoView,所以自带两指缩放:
界面应该是隐藏系统状态栏的,但因为此手机截屏要下拉菜单,所以显示出了状态栏。
仝心:
本次的工作对整个工程中我负责的部分进行了收尾。
首先将ChatInputLayout中的所有功能进行了完善,首先是语音识别功能的输出形式,系统键盘模式下正常输出,自定义键盘模式下需要将识别出的句子的字母与个性化字体库中的字体进行匹配。
给开始识别按钮添加的监听器
- btStart.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- checkSoIsInstallSucceed();
- //mEtInput.setText("");
- //mIatResults.clear();
- // 设置参数
- setParam();
- boolean isShowDialog = mSharedPreferences.getBoolean(
- getResources().getString(R.string.pref_key_iat_show), true);
- if(isShowDialog){
- ret=mIat.startListening(mRecognizerListener);
- if(ret!= ErrorCode.SUCCESS)
- {
- showTip("听写失败,错误码:"+ret);
- }else{
- showTip("请开始说话");
- }
- }
- }
- });
其中showTip用来显示提示文字
- private void showTip(final String str) {
- mToast.setText(str);
- mToast.show();
- }
- private SpeechRecognizer mIat;
- public void setParam() {
- //参数设置
- // 清空参数
- mIat.setParameter(SpeechConstant.PARAMS, null);
- // 设置听写引擎
- mIat.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);
- // 设置返回结果格式
- mIat.setParameter(SpeechConstant.RESULT_TYPE, "json");
- mIat.setParameter(SpeechConstant.LANGUAGE,"en_us");
- // 设置语音前端点:静音超时时间,即用户多长时间不说话则当做超时处理
- mIat.setParameter(SpeechConstant.VAD_BOS, mSharedPreferences.getString("iat_vadbos_preference", "4000"));
- // 设置语音后端点:后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, 自动停止录音
- mIat.setParameter(SpeechConstant.VAD_EOS, mSharedPreferences.getString("iat_vadeos_preference", "1000"));
- // 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点
- mIat.setParameter(SpeechConstant.ASR_PTT, mSharedPreferences.getString("iat_punc_preference", "1"));
- // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
- // 注:AUDIO_FORMAT参数语记需要更新版本才能生效
- mIat.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
- mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/iat.wav");
- }
最后根据不同的输入模式来确定识别后的文本的输出形式,如果是自定义键盘模式,得到语音识别的文本后对文本进行的字母逐个判断并与字体库对应,根据音量进行粗细的变形。
- private RecognizerListener mRecognizerListener = new RecognizerListener() {
- @Override
- public void onBeginOfSpeech() {
- // 此回调表示:sdk内部录音机已经准备好了,用户可以开始语音输入
- showTip("开始说话");
- }
- @Override
- public void onError(SpeechError error) {
- // Tips:
- // 错误码:10118(您没有说话),可能是录音机权限被禁,需要提示用户打开应用的录音权限。
- // 如果使用本地功能(语记)需要提示用户开启语记的录音权限。
- showTip(error.getPlainDescription(true));
- }
- @Override
- public void onEndOfSpeech() {
- // 此回调表示:检测到了语音的尾端点,已经进入识别过程,不再接受语音输入
- showTip("结束说话");
- }
- @Override
- public void onResult(RecognizerResult results, boolean isLast) {
- //Log.L(results.getResultString());
- System.out.println("间断结果——————————————————————————————————");
- printResult(results);
- if(isLast){
- //因为是last,所以new_piece稳定到了最终结果,不再变化。
- result_string+=new_piece;
- //针对不同的文本显示方式,系统字体,手写个性化字体
- String tag=mChangeModeLayout.getTag().toString();
- switch (tag){
- case "1":
- //系统字体
- mEtInput.setText(result_string);
- break;
- case "2":
- //手写个性化字体
- //音量
- sound=sound/soundCount;
- showTip("平均音量"+sound);
- if(sound<=18){
- sound=2;
- }else{
- sound=sound/3;
- }
- for(int i=0;i<new_piece.length();i++){
- int start=mEtInput.getSelectionStart();
- char singleLetter=new_piece.charAt(i);
- int pos=singleLetter-33;
- Bitmap bmp;
- if(pos==-1){
- //空格键
- bmp = Bitmap.createBitmap(MY_COL/2,MY_ROW, Bitmap.Config.ARGB_8888);//空白图片
- }else if(myImageArrays[pos]!=null){
- bmp = paintNewImage(myImageArrays[pos],10,sound,0);
- }else{
- bmp = Bitmap.createBitmap(MY_COL/2,MY_ROW, Bitmap.Config.ARGB_8888);//空白图片
- showTip("个人字体库不完整!");
- }
- SpannableString ss=getBitmapMime1(bmp);
- insertPhotoToEditText(ss);
- count++;
- inputBmpList.add(start,bmp);
- }
- sound=0;
- soundCount=0;
- break;
- default:
- break;
- }
- }
- }
- @Override
- public void onVolumeChanged(int volume, byte[] data) {
- showTip("当前正在说话,音量大小:" + volume);
- //LogUtil.L("返回音频数据:"+data.length);
- if(volume>5){
- sound+=volume;
- soundCount+=1;
- }
- }
- @Override
- public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
- }
- };
张静:
接下来完成MyApplication
1. onCreate
因为引用的包过多,实现多包问题(加载MultiDex)
解决7.0(VERSION_CODES为N)以上系统照相机启动失败导致APP崩溃问题:虚拟机策略
SDK初始化,启动后台服务,若已存在用户登陆信息,SDK将完成自动登陆
- public void onCreate() {
- super.onCreate();
- mContext = getApplicationContext();
- MultiDex.install(this);
- instance = this;
- // 解决7.0 以上系统照相机启动失败导致 APP 崩溃问题
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
- StrictMode.setVmPolicy(builder.build());
- }
- sActivityStack = new Stack<>();
- // 初始化网易云通讯 SDK
- NIMClient.init(this,getLoginInfo(),getOptions());
- }
2. 获得SDK配置信息
SDK配置外置存储根目录内置SD卡
SDK配置用户资料提醒(用户资料)
SDK配置状态栏提醒的配置:不需响铃,点击通知栏跳转到MainActivity,需要振动
- private SDKOptions getOptions(){
- SDKOptions options = new SDKOptions();
- // 该目录目前包含 log, file, image, audio, video, thumb 这6个目录。
- // 如果第三方 APP 需要缓存清理功能, 清理这个目录下面个子目录的内容即可。
- if (!new File(Constant.APP_CACHE_PATH).exists()){
- FileUtils.mkDir(Constant.APP_CACHE_PATH);
- }
- options.sdkStorageRootPath = Constant.APP_CACHE_PATH;
- // 用户资料提供者, 目前主要用于提供用户资料,用于新消息通知栏中显示消息来源的头像和昵称
- options.userInfoProvider = new UserInfoProvider() {
- @Override
- public UserInfo getUserInfo(String account) {
- return null;
- }
- @Override
- public int getDefaultIconResId() {
- return R.mipmap.app_logo_main;
- }
- @Override
- public Bitmap getAvatarForMessageNotifier(String account) {
- return null;
- }
- @Override
- public String getDisplayNameForMessageNotifier(String account, String sessionId,
- SessionTypeEnum sessionType) {
- return account;
- }
- @Override
- public Bitmap getTeamIcon(String tid) {
- return null;
- }
- };
- // 配置是否需要预下载附件缩略图,默认为 true
- options.preloadAttach = true;
- StatusBarNotificationConfig config = new StatusBarNotificationConfig();
- config.ring = false;
- config.notificationEntrance = MainActivity.class;
- config.vibrate = true;
- options.statusBarNotificationConfig = config;
- return options;
- }
其中,FileUtils(文件工具类)
- package com.ezreal.ezchat.commonlibrary.utils;
- import java.io.File;
- /**
- * 文件工具类
- * Created by 张静
- */
- public class FileUtils {
- /**
- * 递归创建文件夹,从最上层文件夹开始,只要不存在就会新建
- * @param dirPath 文件夹完整路径
- */
- public static void mkDir(String dirPath) {
- String[] dirArray = dirPath.split("/");
- String pathTemp = "";
- for (int i = 1; i < dirArray.length; i++) {
- pathTemp = pathTemp + "/" + dirArray[i];
- File newF = new File(dirArray[0] + pathTemp);
- if (!newF.exists()) {
- newF.mkdir();
- }
- }
- }
- }
3. 登陆用户信息
如果已经存在登陆用户信息,通过NimUserHandler后台自动登陆
否则返回null
- private LoginInfo getLoginInfo(){
- String account = SharedPreferencesUtil.getStringSharedPreferences(this,
- Constant.LOCAL_LOGIN_TABLE, Constant.LOCAL_USER_ACCOUNT);
- String token = SharedPreferencesUtil.getStringSharedPreferences(this,
- Constant.LOCAL_LOGIN_TABLE, Constant.LOCAL_USER_TOKEN);
- if (!TextUtils.isEmpty(account) && !TextUtils.isEmpty(token)){
- LoginInfo info = new LoginInfo(account,token);
- NimUserHandler.getInstance().setMyAccount(account);
- return info;
- }
- return null;
- }
4.结束一个Activity
从堆栈中移除该activity,并finish该activity
- public void finishActivity(Activity activity){
- sActivityStack.remove(activity);
- activity.finish();
- }
5. 结束所有Activity
- public void finishAllActivity(){
- for (int i=0;i<sActivityStack.size();i++){
- if (sActivityStack.get(i) != null){
- sActivityStack.get(i).finish();
- }
- }
- }
6. 退出APP
结束进程,并释放资源
- public void AppExit(){
- try {
- finishAllActivity();
- Process.killProcess(Process.myPid());
- System.exit(0);
- }catch (Exception e){
- e.printStackTrace();
- }
- }
附上完整MyApplication.java
- package com.ezreal.ezchat;
- import android.app.Activity;
- import android.app.Application;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.os.Build;
- import android.os.Environment;
- import android.os.Process;
- import android.os.StrictMode;
- import android.support.multidex.MultiDex;
- import android.text.TextUtils;
- import com.ezreal.ezchat.activity.MainActivity;
- import com.ezreal.ezchat.handler.NimUserHandler;
- import com.ezreal.ezchat.utils.Constant;
- import com.netease.nimlib.sdk.NIMClient;
- import com.netease.nimlib.sdk.SDKOptions;
- import com.netease.nimlib.sdk.StatusBarNotificationConfig;
- import com.netease.nimlib.sdk.auth.LoginInfo;
- import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
- import com.netease.nimlib.sdk.uinfo.UserInfoProvider;
- import com.ezreal.ezchat.commonlibrary.utils.FileUtils;
- import com.ezreal.ezchat.commonlibrary.utils.SharedPreferencesUtil;
- import java.io.File;
- import java.util.Stack;
- /**
- * Created by 张静
- */
- public class MyApplication extends Application {
- // 默认存放图片的路径
- public final static String DEFAULT_SAVE_IMAGE_PATH = Environment.getExternalStorageDirectory() + File.separator + "CircleDemo" + File.separator + "Images"
- + File.separator;
- private static Context mContext;
- private static MyApplication instance;
- private static Stack<Activity> sActivityStack;
- @Override
- public void onCreate() {
- super.onCreate();
- mContext = getApplicationContext();
- MultiDex.install(this);
- instance = this;
- // 解决7.0 以上系统照相机启动失败导致 APP 崩溃问题
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
- StrictMode.setVmPolicy(builder.build());
- }
- sActivityStack = new Stack<>();
- // 初始化网易云通讯 SDK
- NIMClient.init(this,getLoginInfo(),getOptions());
- }
- @Override
- protected void attachBaseContext(Context base) {
- super.attachBaseContext(base);
- MultiDex.install(this);
- }
- private SDKOptions getOptions(){
- SDKOptions options = new SDKOptions();
- // 该目录目前包含 log, file, image, audio, video, thumb 这6个目录。
- // 如果第三方 APP 需要缓存清理功能, 清理这个目录下面个子目录的内容即可。
- if (!new File(Constant.APP_CACHE_PATH).exists()){
- FileUtils.mkDir(Constant.APP_CACHE_PATH);
- }
- options.sdkStorageRootPath = Constant.APP_CACHE_PATH;
- // 用户资料提供者, 目前主要用于提供用户资料,用于新消息通知栏中显示消息来源的头像和昵称
- options.userInfoProvider = new UserInfoProvider() {
- @Override
- public UserInfo getUserInfo(String account) {
- return null;
- }
- @Override
- public int getDefaultIconResId() {
- return R.mipmap.app_logo_main;
- }
- @Override
- public Bitmap getAvatarForMessageNotifier(String account) {
- return null;
- }
- @Override
- public String getDisplayNameForMessageNotifier(String account, String sessionId,
- SessionTypeEnum sessionType) {
- return account;
- }
- @Override
- public Bitmap getTeamIcon(String tid) {
- return null;
- }
- };
- // 配置是否需要预下载附件缩略图,默认为 true
- options.preloadAttach = true;
- StatusBarNotificationConfig config = new StatusBarNotificationConfig();
- config.ring = false;
- config.notificationEntrance = MainActivity.class;
- config.vibrate = true;
- options.statusBarNotificationConfig = config;
- return options;
- }
- private LoginInfo getLoginInfo(){
- String account = SharedPreferencesUtil.getStringSharedPreferences(this,
- Constant.LOCAL_LOGIN_TABLE, Constant.LOCAL_USER_ACCOUNT);
- String token = SharedPreferencesUtil.getStringSharedPreferences(this,
- Constant.LOCAL_LOGIN_TABLE, Constant.LOCAL_USER_TOKEN);
- if (!TextUtils.isEmpty(account) && !TextUtils.isEmpty(token)){
- LoginInfo info = new LoginInfo(account,token);
- NimUserHandler.getInstance().setMyAccount(account);
- return info;
- }
- return null;
- }
- public static MyApplication getInstance(){
- return instance;
- }
- public void addActivity(Activity activity){
- sActivityStack.add(activity);
- }
- public void finishActivity(Activity activity){
- sActivityStack.remove(activity);
- activity.finish();
- }
- public void finishAllActivity(){
- for (int i=0;i<sActivityStack.size();i++){
- if (sActivityStack.get(i) != null){
- sActivityStack.get(i).finish();
- }
- }
- }
- public void AppExit(){
- try {
- finishAllActivity();
- Process.killProcess(Process.myPid());
- System.exit(0);
- }catch (Exception e){
- e.printStackTrace();
- }
- }
- public static Context getContext(){
- return mContext;
- }
- }