实训第二周(2)
本次我主要实现了用户手写字体输入界面,重点是createActivity和相应的布局文件,布局经过多次更改确定为下图所示,即简洁又涵盖了所有内容。
最上方的蓝色标题栏为该app通用的标题栏;“!”为输入指示(提示当前应输入什么字符);下面四条辅助线包围的区域为手写输入区域;最后四个按钮分别为“保存”、“重写”、“全部删除”和“下一页”。保存用于将当前描绘的字符存入SQL数据库;重写用于清空画布重绘;全部删除用于将SQL数据库中保存的条目全部删除;下一页用于将页面刷新为下一个字符绘制窗口。
1.首先在页面创建时要判断该字符是否已写过,写过就显示在四线三格里,没有就显示空白。该方法需要用到判断SQL数据库中是否有某条目:
- private boolean searchExistence(String value){
- ImageSQLiteHelper dbHelper = new ImageSQLiteHelper(CreateActivity.this,"my_nn_database");
- SQLiteDatabase db = dbHelper.getWritableDatabase();
- Cursor cursor = db.query("array",new String[]{"id","content","name"},"name=?",new String[]{value},null,null,"id",null);
- while (cursor.moveToNext()) {
- db.close();
- System.out.println("----------------------------数据库中有此条数据——————————————");
- return true;
- }
- db.close();
- System.out.println("----------------------------数据库中没没没此条数据——————————————");
- return false;
- }
如果有,得到该图片数组的方法,用于onCreate:
- private int[][] getImageArry(String value){
- int[][] myImageArray1 = new int[MY_ROW][MY_COL];
- ImageSQLiteHelper dbHelper = new ImageSQLiteHelper(CreateActivity.this,"my_nn_database");
- SQLiteDatabase db = dbHelper.getWritableDatabase();
- Cursor cursor = db.query("array",new String[]{"id","content","name"},"name=?",new String[]{value},null,null,"id",null);
- while (cursor.moveToNext()) {
- String content = cursor.getString(cursor.getColumnIndex("content"));
- String id = cursor.getString(cursor.getColumnIndex("id"));
- String num = cursor.getString(cursor.getColumnIndex("name"));//!的name是0
- System.out.println("" + num + " " + content + "------------" + id);
- String[] imageStr1 = content.split("[,]");
- for(int j = 0;j<MY_ROW;j++)
- {
- for(int k = 0;k<MY_COL;k++)
- {
- myImageArray1[j][k] = Integer.parseInt(imageStr1[MY_COL*j+k]);
- //System.out.println(myImageArray1[j][k]);
- }
- //System.out.println();
- }
- }
- return myImageArray1;
- }
2.onCreate方法:
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_user_words_input);
- setTitleBar("字体库编辑",true,false);//设置标题栏
- paint = new Paint();
- paint.setAntiAlias(true);
- tv = (TextView)findViewById(R.id.letter);
- char letter = (char)('!'+ count);
- tv.setText(""+letter);
- iv1 = (ImageView)findViewById(R.id.Create_up_a);
- b1 = (Button)findViewById(R.id.save_button);
- b2 = (Button)findViewById(R.id.show_button);
- b3 = (Button)findViewById(R.id.delete_btn);
- b5 = (Button)findViewById(R.id.next_button);
- ImageSQLiteHelper dbHelper = new ImageSQLiteHelper(CreateActivity.this,"my_nn_database");
- SQLiteDatabase db = dbHelper.getReadableDatabase();
- b1.setOnClickListener(new insertListener());
- b2.setOnClickListener(new resumeListener());
- b3.setOnClickListener(new deleteListener());
- b5.setOnClickListener(new nextListener());
- mIvBack.setOnClickListener(new mIvBackListener());
- baseBitmap = Bitmap.createBitmap(MY_COL*4, MY_ROW*4, Bitmap.Config.ARGB_8888);
- //如果数据库已保存了,就显示出来
- if(searchExistence(count+"")){
- int[][] bitmapArray=getImageArry(count+"");
- Bitmap bb=arrayToBitmap(bitmapArray);
- baseBitmap=scaleBitmap(bb,4);
- }
- canvas = new Canvas(baseBitmap);
- paint.setColor(Color.BLACK);
- paint.setStrokeWidth(2);
- paint.setColor(Color.RED);
- canvas.drawLine(0,350,300,350,paint);
- paint.setColor(Color.BLUE);
- canvas.drawLine(0,250,300,250,paint);
- paint.setColor(Color.RED);
- canvas.drawLine(0,150,300,150,paint);
- canvas.drawLine(0,50,300,50,paint);
- iv1.setImageBitmap(baseBitmap);
- iv1.setOnTouchListener(touch);
- }
数组到bitmap转换方法:
- private Bitmap arrayToBitmap(int[][] arr) {//二维数组的行数和列数
- int row = arr.length;
- int col = arr[0].length;
- Bitmap bitmap = Bitmap.createBitmap(MY_COL, MY_ROW, Bitmap.Config.ARGB_8888);
- for (int i = 0; i < row; i++) {
- for (int j = 0; j < col; j++) {
- if (arr[i][j] == 0)
- bitmap.setPixel(j,i,Color.BLACK);
- }
- }
- return bitmap;
- }
bitmap缩放方法:
- //按比例缩放图片
- private Bitmap scaleBitmap(Bitmap origin, float ratio) {
- if (origin == null) {
- return null;
- }
- int width = origin.getWidth();
- int height = origin.getHeight();
- Matrix matrix = new Matrix();
- matrix.preScale(ratio, ratio);
- Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);
- if (newBM.equals(origin)) {
- return newBM;
- }
- origin.recycle();
- return newBM;
- }
标题栏设置方法:
- /**
- * 设置标题栏 需确定 该页面的layout布局文件 include title_layout
- * @param titleName 标题
- * @param showBackIcon 是否显示返回按钮
- * @param showMenuIcon 是否显示菜单按钮
- */
- protected void setTitleBar(String titleName, boolean showBackIcon,boolean showMenuIcon){
- try {
- mTvTitle = (TextView) findViewById(R.id.tv_title);
- mTvTitle.setText(titleName);
- mIvBack = (ImageView) findViewById(R.id.iv_back_btn);
- mIvMenu = (ImageView) findViewById(R.id.iv_menu_btn);
- if (showBackIcon){
- mIvBack.setVisibility(View.VISIBLE);
- }
- if (showMenuIcon){
- mIvMenu.setVisibility(View.VISIBLE);
- }
- }catch (Exception e){
- e.printStackTrace();
- }
- }
3.四线三格区的绘制方法
- private View.OnTouchListener touch = new View.OnTouchListener() {
- // 定义手指开始触摸的坐标
- float startX;
- float startY;
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- paint.setStrokeWidth(8);
- switch (event.getAction()) {
- // 用户按下动作
- case MotionEvent.ACTION_DOWN:
- // 第一次绘图初始化内存图片,指定背景为白色
- // 记录开始触摸的点的坐标
- startX = event.getX();
- startY = event.getY();
- break;
- // 用户手指在屏幕上移动的动作
- case MotionEvent.ACTION_MOVE:
- // 记录移动位置的点的坐标
- float stopX = event.getX();
- float stopY = event.getY();
- //根据两点坐标,绘制连线
- paint.setARGB(255, 0, 0, 0);
- canvas.drawLine(startX, startY, stopX, stopY, paint);
- // 更新开始点的位置
- startX = event.getX();
- startY = event.getY();
- // 把图片展示到ImageView中
- iv1.setImageBitmap(baseBitmap);
- break;
- case MotionEvent.ACTION_UP:
- break;
- default:
- break;
- }
- return true;
- }
- };
4.保存按钮监听器:
- //保存按钮监听器
- class insertListener implements View.OnClickListener{
- @Override
- public void onClick(View view) {
- int[][] pixel = saveScaledBitmapArray(baseBitmap);
- int row = pixel.length;
- int col = pixel[0].length;
- for(int i = 0; i<row;i++)
- {
- for(int j = 0;j<col;j++)
- {
- s += pixel[i][j]+",";
- }
- }
- ContentValues values = new ContentValues();
- char letter = (char)('!'+count);
- String str = ""+letter;
- values.put("id",str);
- values.put("content",s);
- values.put("name",count);
- ImageSQLiteHelper dbHelper = new ImageSQLiteHelper(CreateActivity.this,"my_nn_database");
- SQLiteDatabase db = dbHelper.getWritableDatabase();
- db.insert("array",null,values);
- s="";
- }
- }
- //保存的为缩放后的bitmap(并且只保存黑色像素)
- protected int[][] saveScaledBitmapArray(Bitmap bmp) {
- Bitmap new_bmp = scaleBitmap(bmp,0.25f);
- int width = new_bmp.getWidth();
- int height = new_bmp.getHeight();
- //bmp.getPixels(pixels,0,width,0,0,width,height);
- int[][] ps = new int[height][width];//存成一个长*宽的矩阵
- for (int i = 0; i < height; i++) {
- for (int j = 0; j < width; j++) {
- int p = new_bmp.getPixel(j, i);//p是-1是白色,p是-16777216是黑色
- if (p == -16777216)
- ps[i][j] = 0;
- else
- ps[i][j] = 1;
- }
- }
- return ps;
- }
5.重画按钮监听器,将该条目从数据库删除,并清空画布:
- class resumeListener implements View.OnClickListener{//重画
- @Override
- public void onClick(View view) {
- ImageSQLiteHelper dbHelper = new ImageSQLiteHelper(CreateActivity.this,"my_nn_database");
- SQLiteDatabase db = dbHelper.getWritableDatabase();
- db.delete("array","name=?",new String[]{count+""});
- resumeCanvas();
- }
- }
- protected void resumeCanvas() {
- // 手动清除画板的绘图,重新创建一个画板
- paint.setStrokeWidth(2);
- if (baseBitmap != null) {
- baseBitmap = Bitmap.createBitmap(iv1.getWidth(),
- iv1.getHeight(), Bitmap.Config.ARGB_8888);
- canvas = new Canvas(baseBitmap);
- canvas.drawColor(Color.WHITE);
- paint.setColor(Color.RED);
- canvas.drawLine(0,350,300,350,paint);
- paint.setColor(Color.BLUE);
- canvas.drawLine(0,250,300,250,paint);
- paint.setColor(Color.RED);
- canvas.drawLine(0,150,300,150,paint);
- canvas.drawLine(0,50,300,50,paint);
- iv1.setImageBitmap(baseBitmap);
- }
- }
6.“下一页”按钮监听器,将count加一,并将指示区字符替换,同时判断该字符是否已绘制。
- class nextListener implements View.OnClickListener{
- @Override
- public void onClick(View view) {
- count++;
- char letter = (char)('!'+ count);
- tv.setText(""+letter);
- baseBitmap = Bitmap.createBitmap(MY_COL*4, MY_ROW*4, Bitmap.Config.ARGB_8888);
- //如果数据库已保存了,就显示出来
- if(searchExistence(count+"")){
- int[][] bitmapArray=getImageArry(count+"");
- Bitmap bb=arrayToBitmap(bitmapArray);
- baseBitmap=scaleBitmap(bb,4);
- }
- canvas = new Canvas(baseBitmap);
- paint.setColor(Color.BLACK);
- paint.setStrokeWidth(2);
- paint.setColor(Color.RED);
- canvas.drawLine(0,350,300,350,paint);
- paint.setColor(Color.BLUE);
- canvas.drawLine(0,250,300,250,paint);
- paint.setColor(Color.RED);
- canvas.drawLine(0,150,300,150,paint);
- canvas.drawLine(0,50,300,50,paint);
- iv1.setImageBitmap(baseBitmap);
- }
- }
7.全部删除按钮监听器:
- class deleteListener implements View.OnClickListener{
- @Override
- public void onClick(View view) {
- ImageSQLiteHelper dbHelper = new ImageSQLiteHelper(CreateActivity.this,"my_nn_database");
- SQLiteDatabase db = dbHelper.getWritableDatabase();
- db.delete("array",null,null);
- }
- }
8.标题栏和系统返回按钮监听器:
- class mIvBackListener implements View.OnClickListener{
- @Override
- public void onClick(View view){
- getImageArry();
- finish();
- }
- }
- public void onBackPressed() {
- getImageArry();
- finish();
- }
因为返回时数据库可能以改变,所以对应的myImageArrays数组也要更新,用于后续的使用:
- private int[][] getImageArry(String value){
- int[][] myImageArray1 = new int[MY_ROW][MY_COL];
- ImageSQLiteHelper dbHelper = new ImageSQLiteHelper(CreateActivity.this,"my_nn_database");
- SQLiteDatabase db = dbHelper.getWritableDatabase();
- Cursor cursor = db.query("array",new String[]{"id","content","name"},"name=?",new String[]{value},null,null,"id",null);
- while (cursor.moveToNext()) {
- String content = cursor.getString(cursor.getColumnIndex("content"));
- String id = cursor.getString(cursor.getColumnIndex("id"));
- String num = cursor.getString(cursor.getColumnIndex("name"));//!的name是0
- System.out.println("" + num + " " + content + "------------" + id);
- String[] imageStr1 = content.split("[,]");
- for(int j = 0;j<MY_ROW;j++)
- {
- for(int k = 0;k<MY_COL;k++)
- {
- myImageArray1[j][k] = Integer.parseInt(imageStr1[MY_COL*j+k]);
- //System.out.println(myImageArray1[j][k]);
- }
- //System.out.println();
- }
- }
- return myImageArray1;
- }
仝心:
通过上次的工作基础,我们本次进行了更加深入的个人工作,完成了语音识别功能。
1.因为我们的应用是基于英文环境,所以经过调查我们选择了科大讯飞语音云。
首先申请一个appid,然后添加语音听写服务,下载对应的SDK
2.下载完成,解压压缩包如下图所示
3.将assets文件夹中的内容拷贝到项目assets文件夹(新建)中,将Msc.jar和Sunflower.jar拷贝到文件夹libs中,在和res同级的目录下创建jniLibs文件夹(),并将下载下来的libs目录下的所有libmsc.so文件拷贝到该文件夹下(很重要,目录结构一定不要创建错,否则会报错误“创建对象失败,请确认 libmsc.so 放置正确,且有调用 createUtility 进行初始化”)
4.在AndroidMainfest.xml中添加如下权限
- <uses-permission android:name="android.permission.RECORD_AUDIO" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
- <uses-permission android:name="android.permission.READ_PHONE_STATE" />
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- <uses-permission android:name="android.permission.READ_CONTACTS" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.WRITE_SETTINGS" />
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
将申请的APPID记录下来,并保存到string文件中
5.在入口处初始化SpeechUtility对象
- protected void onCreate(Bundle savedInstanceState) {
- SpeechUtility.createUtility(MainActivity.this,"appid="+getString(R.string.app_id));
6.初始化所需对象数据
- private void initData() {
- context = MainActivity.this; // 初始化识别无UI识别对象 // 使用SpeechRecognizer对象,可根据回调消息自定义界面; mIat = SpeechRecognizer.createRecognizer(context, mInitListener); // 初始化听写Dialog,如果只使用有UI听写功能,无需创建SpeechRecognizer // 使用UI听写功能,请根据sdk文件目录下的notice.txt,放置布局文件和图片资源 mIatDialog = new RecognizerDialog(context, mInitListener); mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT); mSharedPreferences = getSharedPreferences(MainActivity.PREFER_NAME, Activity.MODE_PRIVATE);}
7.点击开始按钮时,设置所需要的参数,弹出话筒框,并设置监听到的信息的监听
- private void setOnclickListener() {
- btStart.setOnClickListener(new View.OnClickListener() {
- @Override public void onClick(View v) {
- checkSoIsInstallSucceed();
- etContent.setText(null);// 清空显示内容
- mIatResults.clear(); // 设置参数
- setParam();
- boolean isShowDialog = mSharedPreferences.getBoolean(
- getString(R.string.pref_key_iat_show), true);
- if (isShowDialog) {
- // 显示听写对话框
- mIatDialog.setListener(mRecognizerDialogListener);
- mIatDialog.show();
- showTip(getString(R.string.text_begin));
- } else {
- // 不显示听写对话框
- ret = mIat.startListening(mRecognizerListener);
- if (ret != ErrorCode.SUCCESS) {
- showTip("听写失败,错误码:" + ret);
- } else {
- showTip(getString(R.string.text_begin));
- 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");
8.在界面销毁的时候,释放连接
- protected void onDestroy() {
- super.onDestroy();
- if (null != mIat) {
- // 退出时释放连接
- mIat.cancel();
- mIat.destroy();
- }
- }
9.对于结果的显示,要写一个JsonParser类
- String text = JsonParser.parseIatResult(results.getResultString());
- package com.example.liche.voicerecog2;
- import org.json.JSONObject;
- import org.json.JSONTokener;
- import org.json.JSONArray;
- /** * Created by liche on 2018/4/25. */
- public class JsonParser {
- public static String parseIatResult(String json) {
- StringBuffer ret = new StringBuffer();
- try {
- JSONTokener tokener = new JSONTokener(json);
- JSONObject joResult = new JSONObject(tokener);
- JSONArray words = joResult.getJSONArray("ws");
- for (int i = 0; i < words.length(); i++) {
- // 转写结果词,默认使用第一个结果
- JSONArray items = words.getJSONObject(i).getJSONArray("cw");
- JSONObject obj = items.getJSONObject(0);
- ret.append(obj.getString("w")); }
- } catch (Exception e) {
- e.printStackTrace(); }
- return ret.toString(); }
- public static String parseGrammarResult(String json) {
- StringBuffer ret = new StringBuffer();
- try {
- JSONTokener tokener = new JSONTokener(json);
- JSONObject joResult = new JSONObject(tokener);
- JSONArray words = joResult.getJSONArray("ws");
- for (int i = 0; i < words.length(); i++) {
- JSONArray items = words.getJSONObject(i).getJSONArray("cw");
- for(int j = 0; j < items.length(); j++)
- {
- JSONObject obj = items.getJSONObject(j);
- if(obj.getString("w").contains("nomatch"))
- {
- ret.append("没有匹配结果.");
- return ret.toString(); }
- ret.append("【结果】" + obj.getString("w"));
- ret.append("【置信度】" + obj.getInt("sc"));
- ret.append("\n"); }
- }
- } catch (Exception e) {
- e.printStackTrace();
- ret.append("没有匹配结果."); }
- return ret.toString(); }
- }
10.在Android Studio中使用C/C++(否则报错)
使用 SDK Manager 来安装组件:
1. 打开一个项目,从菜单栏中选择 Tools > Android > SDK Manager。
2. 点击 SDK Tools 选项卡。
3. 勾选 LLDB,CMake 和 NDK。
然后在新建项目时勾选Include C++ Support,运行时就不会报错。但我的项目已经建好,在此基础上添加c++支持我参考了以下网站:https://blog.csdn.net/wl9739/article/details/52607010
另外,我还完成了传感器数据的获取,主要是加速度计数据的获取,然后对这些数据进行加工成可以传入之前完成的方法的数据,传入字体抖动和字体倾斜的方法。
- /**
- * 传感器监听器
- * */
- SensorEventListener sensorListener = new SensorEventListener() {
- //传感器改变时,一般是通过这个方法里面的参数确定传感器状态的改变
- @Override
- public void onSensorChanged(SensorEvent sensorEvent) {
- if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
- {
- accelerometerValues = sensorEvent.values.clone();
- float[] values = sensorEvent.values;//获取传感器的数据
- //float max = sensor.getMaximumRange();//获取最大值范围
- if (values.length >= 3) {
- float x = values[0];//右侧面向上时为g(9.8)
- float y = values[1];//上侧面向上时为g(9.8)
- float z = values[2];
- //抖动
- float xx = values[0] - usedValues[0];
- float yy = values[1] - usedValues[1];
- float zz = values[2] - usedValues[2];
- float Tense = Math.abs(xx)+Math.abs(yy)+Math.abs(zz);
- //System.out.println(values[2]+" " +usedValues[2]+" "+Tense);
- usedValues[0] = x;
- usedValues[1] = y;
- usedValues[2] = z;
- if(Tense >=15)
- tempTense = 1;
- else if(Tense >=6&&Tense < 15)
- tempTense = 2;
- else if(Tense>=4&&Tense < 6)
- tempTense = 6;
- else if(Tense >=2&&Tense<4)
- tempTense = 7;
- else if(Tense>=1&&Tense<2)
- tempTense = 8;
- else
- tempTense = 10;
- //倾斜
- float angle;
- if(y>0)
- {
- angle = x*8;
- if(angle>25)
- angle = 25;
- }
- else
- angle = 0;
- //System.out.println(angle);
- myKeyboard.getSkewData(angle);
- //抖动
- //float Tense = Math.abs(x)+Math.abs(y)+Math.abs(z);
- }
- //System.out.println(accelerometerValues[0]+" "+accelerometerValues[1]+" "+accelerometerValues[2]);
- myKeyboard.getSensorData(tempTense);
- }else if (sensorEvent.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {// 注意赋值时要调用clone()方法
- magneticValues = sensorEvent.values.clone();
- //System.out.println(magneticValues[0]+" "+magneticValues[1]+" "+magneticValues[2]);
- }
- }
- @Override
- public void onAccuracyChanged(Sensor sensor, int i) {
- }
- };
通过按下和抬起的时间差获取按键时间,经过加工后传入字体加粗的方法。
- /**
- * 获得触键时间
- * */
- class touchKeyListener implements View.OnTouchListener{
- @Override
- public boolean onTouch(View view, MotionEvent motionEvent) {
- //timer = new Chronometer(MainActivity.this);
- switch (motionEvent.getAction()) {
- case MotionEvent.ACTION_DOWN:
- Calendar calendar = Calendar.getInstance();
- int YY = calendar.get(Calendar.YEAR);
- int MM = calendar.get(Calendar.MONTH)+1;
- int DD = calendar.get(Calendar.DATE);
- int HH = calendar.get(Calendar.HOUR_OF_DAY);
- int mm = calendar.get(Calendar.MINUTE);
- int SS = calendar.get(Calendar.SECOND);
- int MI = calendar.get(Calendar.MILLISECOND);
- String string = YY+" "+MM+" "+DD+" "+HH+" "+mm+" "+SS+" "+MI+"";
- second1 = SS;
- millisecond1 = MI;
- //timer.setBase(SystemClock.elapsedRealtime());//计时器清零
- //timer.start();
- System.out.println("down");
- System.out.println(string);
- break;
- case MotionEvent.ACTION_UP:
- //timer.stop();
- Calendar c = Calendar.getInstance();
- int Y = c.get(Calendar.YEAR);
- int M = c.get(Calendar.MONTH)+1;
- int D = c.get(Calendar.DATE);
- int H = c.get(Calendar.HOUR_OF_DAY);
- int m = c.get(Calendar.MINUTE);
- int S = c.get(Calendar.SECOND);
- int mi = c.get(Calendar.MILLISECOND);
- String s = Y+" "+M+" "+D+" "+H+" "+m+" "+S+" "+mi+"";
- second2 = S;
- millisecond2 = mi;
- totalMilliSecond = (second2-second1)*1000+millisecond2-millisecond1;
- int thick;
- if(totalMilliSecond<300)
- thick = 2;
- else if(totalMilliSecond>=300&&totalMilliSecond<600)
- thick = 5;
- else if(totalMilliSecond>=600&&totalMilliSecond<800)
- thick = 6;
- else if(totalMilliSecond>=800&&totalMilliSecond<1000)
- thick = 7;
- else thick = 8;
- myKeyboard.getTouchTime(thick);
- System.out.println("up");
- break;
- case MotionEvent.ACTION_MOVE:
- break;
- default:
- break;
- }
- return false;
- }
- }
张静:
这周接下来我完成MainActivity中的initHandler中声明的四个handler实现(完成了三个,第四个未完成):
1. NimOnlineStatusHandler
a. 使用getInstance()实例化
- public static NimOnlineStatusHandler getInstance(){
- if (instance == null){
- synchronized (NimOnlineStatusHandler.class){
- if (instance == null){
- instance = new NimOnlineStatusHandler();
- }
- }
- }
- return instance;
- }
b. 初始化
通过NimClient的getService接口获取到AuthServiceObserver(用户状态观察者接口)服务实例
可监听用户在线状态,登录成功后,SDK回负责维护与服务器的长连接以及断线重连等工作
当用户在线状态发生改变时,会发出通知
定义了三种情况,会导致MainActivity的initHandler中重写的requestReLogin或networkBroken:
- @Override
- public void requestReLogin(String message) {
- ToastUtils.showMessage(MainActivity.this,"自动登陆失败或被踢出,请手动登陆~");
- startActivity(new Intent(MainActivity.this,LoginActivity.class));
- }
- @Override
- public void networkBroken() {
- }
(1) StatusCode为UNLOGIN(未登录/登录失败)或FORBIDDEN(被服务器禁止登陆)
调用requestReLogin("UN_LOGIN"), 跳转到登录页面,显示“自动登录失败或被踢出,请手动登陆~”
(2) StatusCode为KICK_BY_OTHER_CLIENT(被同时在线的其他端主动踢掉)或KICKOUT(被其他端的登录踢掉)
调用requestReLogin("UN_LOGIN"), 跳转到登录页面,显示“自动登录失败或被踢出,请手动登陆~”
(3) StatusCode为NET_BROKEN(网络连接已断开)
调用networkBroken
- public void init(){
- mListeners = new ArrayList<>();
- NIMClient.getService(AuthServiceObserver.class)
- .observeOnlineStatus(new Observer<StatusCode>() {
- @Override
- public void onEvent(StatusCode statusCode) {
- if (statusCode == StatusCode.UNLOGIN || statusCode == StatusCode.FORBIDDEN){
- Log.e(TAG,"OnlineObserver---UN_LOGIN");
- if (mListeners != null && !mListeners.isEmpty()){
- for (OnStatusChangeListener listener : mListeners){
- listener.requestReLogin("UN_LOGIN");
- }
- }
- }else if (statusCode == StatusCode.KICK_BY_OTHER_CLIENT
- || statusCode == StatusCode.KICKOUT){
- Log.e(TAG,"OnlineObserver---KICK_OUT");
- if (mListeners != null && !mListeners.isEmpty()){
- for (OnStatusChangeListener listener : mListeners){
- listener.requestReLogin("KICK_OUT");
- }
- }
- } else if (statusCode == StatusCode.NET_BROKEN){
- Log.e(TAG,"OnlineObserver---NET_BROKEN");
- if (mListeners != null && !mListeners.isEmpty()){
- for (OnStatusChangeListener listener : mListeners){
- listener.networkBroken();
- }
- }
- }
- }
- },true);
- }
附上完整代码:
- package com.ezreal.ezchat.handler;
- import android.util.Log;
- import com.netease.nimlib.sdk.NIMClient;
- import com.netease.nimlib.sdk.Observer;
- import com.netease.nimlib.sdk.StatusCode;
- import com.netease.nimlib.sdk.auth.AuthServiceObserver;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * Created by 张静 .
- */
- public class NimOnlineStatusHandler {
- private static final String TAG = NimOnlineStatusHandler.class.getSimpleName();
- private static NimOnlineStatusHandler instance;
- private List<OnStatusChangeListener> mListeners;
- public static NimOnlineStatusHandler getInstance(){
- if (instance == null){
- synchronized (NimOnlineStatusHandler.class){
- if (instance == null){
- instance = new NimOnlineStatusHandler();
- }
- }
- }
- return instance;
- }
- public void init(){
- mListeners = new ArrayList<>();
- //用户状态观察者接口
- //监听用户在线状态,登录成功后,SDK会负责维护与服务器的长连接以及断线重连等工作
- //用户在线状态发生改变时,会发出通知
- NIMClient.getService(AuthServiceObserver.class)
- .observeOnlineStatus(new Observer<StatusCode>() {
- @Override
- public void onEvent(StatusCode statusCode) {
- if (statusCode == StatusCode.UNLOGIN || statusCode == StatusCode.FORBIDDEN){
- Log.e(TAG,"OnlineObserver---UN_LOGIN");
- if (mListeners != null && !mListeners.isEmpty()){
- for (OnStatusChangeListener listener : mListeners){
- listener.requestReLogin("UN_LOGIN");
- }
- }
- }else if (statusCode == StatusCode.KICK_BY_OTHER_CLIENT
- || statusCode == StatusCode.KICKOUT){
- Log.e(TAG,"OnlineObserver---KICK_OUT");
- if (mListeners != null && !mListeners.isEmpty()){
- for (OnStatusChangeListener listener : mListeners){
- listener.requestReLogin("KICK_OUT");
- }
- }
- } else if (statusCode == StatusCode.NET_BROKEN){
- Log.e(TAG,"OnlineObserver---NET_BROKEN");
- if (mListeners != null && !mListeners.isEmpty()){
- for (OnStatusChangeListener listener : mListeners){
- listener.networkBroken();
- }
- }
- }
- }
- },true);
- }
- public void setStatusChangeListener(OnStatusChangeListener listener){
- mListeners.add(listener);
- }
- public void removeStatusChangeListener(OnStatusChangeListener listener){
- mListeners.remove(listener);
- }
- public interface OnStatusChangeListener {
- void requestReLogin(String message);
- void networkBroken();
- }
- }
2. NimSysMsgHandler
(1)通过NimClient的getService接口获取到SystemMessageObserver(系统通知观察者)服务实例
添加好友请求发出后,对方会收到一条SystemMessage,可以通过SystemMessageObserver的observeReceiveSystemMsg函数来监听系统通知,通过getAttachObject函数可以获取添加好友的通知
- public void init(){
- mMessageListener = new ArrayList<>();
- NIMClient.getService(SystemMessageObserver.class)
- .observeReceiveSystemMsg(new Observer<SystemMessage>() {
- @Override
- public void onEvent(SystemMessage message) {
- AddFriendNotify notify = (AddFriendNotify) message.getAttachObject();
- if (notify != null){
- for (SystemMessageListener l : mMessageListener){
- l.addFriendNotify();
- }
- }
- }
- },true);
- }
- public class AddFriendNotify {
- private SystemMessage mMessage;
- private NimUserInfo mUserInfo;//用户资料
- private boolean isMyFriend;
- public SystemMessage getMessage() {
- return mMessage;
- }
- public void setMessage(SystemMessage message) {
- mMessage = message;
- }
- public NimUserInfo getUserInfo() {
- return mUserInfo;
- }
- public void setUserInfo(NimUserInfo userInfo) {
- mUserInfo = userInfo;
- }
- public boolean isMyFriend() {
- return isMyFriend;
- }
- public void setMyFriend(boolean myFriend) {
- isMyFriend = myFriend;
- }
- }
(3)附上NimSysMsgHandler完整代码:
- package com.ezreal.ezchat.handler;
- import android.util.Log;
- import com.netease.nimlib.sdk.NIMClient;
- import com.netease.nimlib.sdk.Observer;
- import com.netease.nimlib.sdk.friend.model.AddFriendNotify;
- import com.netease.nimlib.sdk.msg.SystemMessageObserver;
- import com.netease.nimlib.sdk.msg.model.SystemMessage;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.TimeZone;
- /**
- * Created by 张静.
- */
- public class NimSysMsgHandler {
- private static final String TAG = NimSysMsgHandler.class.getSimpleName();
- private static NimSysMsgHandler instance;
- private List<SystemMessageListener> mMessageListener;
- public static NimSysMsgHandler getInstance(){
- if (instance == null){
- synchronized (NimSysMsgHandler.class){
- if (instance == null){
- instance = new NimSysMsgHandler();
- }
- }
- }
- return instance;
- }
- public void init(){
- mMessageListener = new ArrayList<>();
- NIMClient.getService(SystemMessageObserver.class)
- .observeReceiveSystemMsg(new Observer<SystemMessage>() {
- @Override
- public void onEvent(SystemMessage message) {
- AddFriendNotify notify = (AddFriendNotify) message.getAttachObject();
- if (notify != null){
- for (SystemMessageListener l : mMessageListener){
- l.addFriendNotify();
- }
- }
- }
- },true);
- }
- public void setMessageListener(SystemMessageListener listener){
- mMessageListener.add(listener);
- }
- public interface SystemMessageListener{
- void addFriendNotify();
- }
- }
3. NimFriendHandler
(1)通过NimClient的getService接口获取到FriendServiceObserve(好友关系、黑名单变更通知)服务实例来监听好友关系变化通知
- public void init() {
- mFriendAccounts = new ArrayList<>();
- mFriends = new ArrayList<>();
- mFriendInfos = new ArrayList<>();
- // 初始化好友列表更新监听
- NIMClient.getService(FriendServiceObserve.class)
- .observeFriendChangedNotify(new Observer<FriendChangedNotify>() {
- @Override
- public void onEvent(FriendChangedNotify notify) {
- loadFriendData();
- }
- }, true);
- loadFriendData();
- }
(2)读取账户好友列表数据
通过NimClient的getService接口获取到FriendService(好友管理/好友关系/黑名单关系/消息提醒相关操作)服务实例
调用getFriendAccounts获取我所有的好友账号
调用getFriendByAccount根据用户账号获取好友关系
通过NimClient的getService接口获取到UserService(用户资料操作相关接口)服务实例
调用getUserInfoList从本地数据库中批量获取用户资料(同步接口)
- private void loadFriendData() {
- mFriendAccounts.clear();
- List<String> friendAccounts = NIMClient.getService(FriendService.class).getFriendAccounts();
- if (friendAccounts == null || friendAccounts.isEmpty()) {
- return;
- }
- mFriendAccounts.addAll(friendAccounts);
- mFriends.clear();
- Friend friend;
- for (String account : mFriendAccounts) {
- friend = NIMClient.getService(FriendService.class).getFriendByAccount(account);
- mFriends.add(friend);
- }
- mFriendInfos.clear();
- List<NimUserInfo> userInfoList = NIMClient.getService(UserService.class)
- .getUserInfoList(mFriendAccounts);
- mFriendInfos.addAll(userInfoList);
- //更新用户界面
- if (mUpdateListener != null){
- mUpdateListener.friendUpdate();
- }
- }
- public void setUpdateListener(OnFriendUpdateListener listener){
- this.mUpdateListener = listener;
- }
(4)检查该账户是否为我的好友
通过NimClient的getService接口获取到FriendService(好友管理/好友关系/黑名单关系/消息提醒相关操作)服务实例
- public boolean CheckIsMyFriend(String account) {
- return NIMClient.getService(FriendService.class).isMyFriend(account);
- }
- package com.ezreal.ezchat.handler;
- import android.util.Log;
- import com.netease.nimlib.sdk.NIMClient;
- import com.netease.nimlib.sdk.Observer;
- import com.netease.nimlib.sdk.friend.FriendService;
- import com.netease.nimlib.sdk.friend.FriendServiceObserve;
- import com.netease.nimlib.sdk.friend.model.Friend;
- import com.netease.nimlib.sdk.friend.model.FriendChangedNotify;
- import com.netease.nimlib.sdk.uinfo.UserService;
- import com.netease.nimlib.sdk.uinfo.model.NimUserInfo;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * Created by 张静.
- */
- public class NimFriendHandler {
- private static final String TAG = NimFriendHandler.class.getSimpleName();
- private static NimFriendHandler instance;
- private List<String> mFriendAccounts;
- private List<NimUserInfo> mFriendInfos;
- private List<Friend> mFriends;
- private OnFriendUpdateListener mUpdateListener;
- public static NimFriendHandler getInstance() {
- if (instance == null) {
- synchronized (NimFriendHandler.class) {
- if (instance == null) {
- instance = new NimFriendHandler();
- }
- }
- }
- return instance;
- }
- /**
- * 初始化好友列表工具类
- * 根据账户获取好友列表
- * 同步本地数据库的好友账户数据
- */
- public void init() {
- mFriendAccounts = new ArrayList<>();
- mFriends = new ArrayList<>();
- mFriendInfos = new ArrayList<>();
- // 初始化好友列表更新监听
- NIMClient.getService(FriendServiceObserve.class)
- .observeFriendChangedNotify(new Observer<FriendChangedNotify>() {
- @Override
- public void onEvent(FriendChangedNotify notify) {
- loadFriendData();
- }
- }, true);
- loadFriendData();
- }
- public List<String> getFriendAccounts() {
- return mFriendAccounts;
- }
- public List<NimUserInfo> getFriendInfos() {
- return mFriendInfos;
- }
- public List<Friend> getFriends() {
- return mFriends;
- }
- /**
- * 读取账户好友列表数据
- */
- private void loadFriendData() {
- mFriendAccounts.clear();
- List<String> friendAccounts = NIMClient.getService(FriendService.class).getFriendAccounts();
- if (friendAccounts == null || friendAccounts.isEmpty()) {
- return;
- }
- mFriendAccounts.addAll(friendAccounts);
- mFriends.clear();
- Friend friend;
- for (String account : mFriendAccounts) {
- friend = NIMClient.getService(FriendService.class).getFriendByAccount(account);
- mFriends.add(friend);
- }
- mFriendInfos.clear();
- List<NimUserInfo> userInfoList = NIMClient.getService(UserService.class)
- .getUserInfoList(mFriendAccounts);
- mFriendInfos.addAll(userInfoList);
- //更新用户界面
- if (mUpdateListener != null){
- mUpdateListener.friendUpdate();
- }
- }
- /**
- * 设置好友列表更新监听
- * @param listener listener
- */
- public void setUpdateListener(OnFriendUpdateListener listener){
- this.mUpdateListener = listener;
- }
- /**
- * 检查该账户是否为我的好友
- *
- * @param account 待检查账户
- * @return true 如果对方是好友,否则返回 false
- */
- public boolean CheckIsMyFriend(String account) {
- return NIMClient.getService(FriendService.class).isMyFriend(account);
- }
- public void syncFriendInfo(List<String> accounts) {
- NIMClient.getService(UserService.class).fetchUserInfo(accounts);
- }
- public interface OnFriendUpdateListener{
- void friendUpdate();
- }
- }