实训第二周(2)

李晨晨:

本次我主要实现了用户手写字体输入界面,重点是createActivity和相应的布局文件,布局经过多次更改确定为下图所示,即简洁又涵盖了所有内容。

实训第二周(2)      实训第二周(2)

最上方的蓝色标题栏为该app通用的标题栏;“!”为输入指示(提示当前应输入什么字符);下面四条辅助线包围的区域为手写输入区域;最后四个按钮分别为“保存”、“重写”、“全部删除”和“下一页”。保存用于将当前描绘的字符存入SQL数据库;重写用于清空画布重绘;全部删除用于将SQL数据库中保存的条目全部删除;下一页用于将页面刷新为下一个字符绘制窗口。

1.首先在页面创建时要判断该字符是否已写过,写过就显示在四线三格里,没有就显示空白。该方法需要用到判断SQL数据库中是否有某条目:

[cpp] view plain copy
  1. private boolean searchExistence(String value){  
  2.         ImageSQLiteHelper dbHelper = new ImageSQLiteHelper(CreateActivity.this,"my_nn_database");  
  3.         SQLiteDatabase db = dbHelper.getWritableDatabase();  
  4.         Cursor cursor = db.query("array",new String[]{"id","content","name"},"name=?",new String[]{value},null,null,"id",null);  
  5.         while (cursor.moveToNext()) {  
  6.             db.close();  
  7.             System.out.println("----------------------------数据库中有此条数据——————————————");  
  8.             return true;  
  9.         }  
  10.         db.close();  
  11.         System.out.println("----------------------------数据库中没没没此条数据——————————————");  
  12.         return false;  
  13.     }  

如果有,得到该图片数组的方法,用于onCreate:

[cpp] view plain copy
  1. private int[][] getImageArry(String value){  
  2.         int[][] myImageArray1 = new int[MY_ROW][MY_COL];  
  3.         ImageSQLiteHelper dbHelper = new ImageSQLiteHelper(CreateActivity.this,"my_nn_database");  
  4.         SQLiteDatabase db = dbHelper.getWritableDatabase();  
  5.         Cursor cursor = db.query("array",new String[]{"id","content","name"},"name=?",new String[]{value},null,null,"id",null);  
  6.         while (cursor.moveToNext()) {  
  7.             String content = cursor.getString(cursor.getColumnIndex("content"));  
  8.             String id = cursor.getString(cursor.getColumnIndex("id"));  
  9.             String num = cursor.getString(cursor.getColumnIndex("name"));//!的name是0  
  10.             System.out.println("" + num + "   " + content + "------------" + id);  
  11.   
  12.             String[] imageStr1 = content.split("[,]");  
  13.             for(int j = 0;j<MY_ROW;j++)  
  14.             {  
  15.                 for(int k = 0;k<MY_COL;k++)  
  16.                 {  
  17.                     myImageArray1[j][k] = Integer.parseInt(imageStr1[MY_COL*j+k]);  
  18.                     //System.out.println(myImageArray1[j][k]);  
  19.                 }  
  20.                 //System.out.println();  
  21.             }  
  22.         }  
  23.         return myImageArray1;  
  24.     }  

2.onCreate方法:

[cpp] view plain copy
  1. @Override  
  2.     protected void onCreate(Bundle savedInstanceState) {  
  3.         super.onCreate(savedInstanceState);  
  4.         setContentView(R.layout.activity_user_words_input);  
  5.         setTitleBar("字体库编辑",true,false);//设置标题栏  
  6.   
  7.         paint = new Paint();  
  8.         paint.setAntiAlias(true);  
  9.         tv = (TextView)findViewById(R.id.letter);  
  10.         char letter = (char)('!'+ count);  
  11.         tv.setText(""+letter);  
  12.         iv1 = (ImageView)findViewById(R.id.Create_up_a);  
  13.         b1 = (Button)findViewById(R.id.save_button);  
  14.         b2 = (Button)findViewById(R.id.show_button);  
  15.         b3 = (Button)findViewById(R.id.delete_btn);  
  16.         b5 = (Button)findViewById(R.id.next_button);  
  17.   
  18.   
  19.         ImageSQLiteHelper dbHelper = new ImageSQLiteHelper(CreateActivity.this,"my_nn_database");  
  20.         SQLiteDatabase db = dbHelper.getReadableDatabase();  
  21.         b1.setOnClickListener(new insertListener());  
  22.         b2.setOnClickListener(new resumeListener());  
  23.         b3.setOnClickListener(new deleteListener());  
  24.         b5.setOnClickListener(new nextListener());  
  25.         mIvBack.setOnClickListener(new mIvBackListener());  
  26.   
  27.         baseBitmap = Bitmap.createBitmap(MY_COL*4, MY_ROW*4, Bitmap.Config.ARGB_8888);  
  28.         //如果数据库已保存了,就显示出来  
  29.         if(searchExistence(count+"")){  
  30.             int[][] bitmapArray=getImageArry(count+"");  
  31.             Bitmap bb=arrayToBitmap(bitmapArray);  
  32.             baseBitmap=scaleBitmap(bb,4);  
  33.         }  
  34.   
  35.         canvas = new Canvas(baseBitmap);  
  36.         paint.setColor(Color.BLACK);  
  37.         paint.setStrokeWidth(2);  
  38.         paint.setColor(Color.RED);  
  39.         canvas.drawLine(0,350,300,350,paint);  
  40.         paint.setColor(Color.BLUE);  
  41.         canvas.drawLine(0,250,300,250,paint);  
  42.         paint.setColor(Color.RED);  
  43.         canvas.drawLine(0,150,300,150,paint);  
  44.         canvas.drawLine(0,50,300,50,paint);  
  45.         iv1.setImageBitmap(baseBitmap);  
  46.         iv1.setOnTouchListener(touch);  
  47.     }  

数组到bitmap转换方法:

[cpp] view plain copy
  1. private Bitmap arrayToBitmap(int[][] arr) {//二维数组的行数和列数  
  2.   
  3.        int row = arr.length;  
  4.        int col = arr[0].length;  
  5.        Bitmap bitmap = Bitmap.createBitmap(MY_COL, MY_ROW, Bitmap.Config.ARGB_8888);  
  6.        for (int i = 0; i < row; i++) {  
  7.            for (int j = 0; j < col; j++) {  
  8.                if (arr[i][j] == 0)  
  9.                    bitmap.setPixel(j,i,Color.BLACK);  
  10.            }  
  11.        }  
  12.        return bitmap;  
  13.    }  

bitmap缩放方法:

[cpp] view plain copy
  1. //按比例缩放图片  
  2.     private Bitmap scaleBitmap(Bitmap origin, float ratio) {  
  3.         if (origin == null) {  
  4.             return null;  
  5.         }  
  6.         int width = origin.getWidth();  
  7.         int height = origin.getHeight();  
  8.         Matrix matrix = new Matrix();  
  9.         matrix.preScale(ratio, ratio);  
  10.         Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);  
  11.         if (newBM.equals(origin)) {  
  12.             return newBM;  
  13.         }  
  14.         origin.recycle();  
  15.         return newBM;  
  16.     }  

标题栏设置方法:

[cpp] view plain copy
  1. /** 
  2.      * 设置标题栏 需确定 该页面的layout布局文件 include title_layout 
  3.      * @param titleName 标题 
  4.      * @param showBackIcon 是否显示返回按钮 
  5.      * @param showMenuIcon 是否显示菜单按钮 
  6.      */  
  7.     protected void setTitleBar(String titleName, boolean showBackIcon,boolean showMenuIcon){  
  8.         try {  
  9.             mTvTitle = (TextView) findViewById(R.id.tv_title);  
  10.             mTvTitle.setText(titleName);  
  11.             mIvBack = (ImageView) findViewById(R.id.iv_back_btn);  
  12.             mIvMenu = (ImageView) findViewById(R.id.iv_menu_btn);  
  13.             if (showBackIcon){  
  14.                 mIvBack.setVisibility(View.VISIBLE);  
  15.             }  
  16.             if (showMenuIcon){  
  17.                 mIvMenu.setVisibility(View.VISIBLE);  
  18.             }  
  19.         }catch (Exception e){  
  20.             e.printStackTrace();  
  21.         }  
  22.     }  

3.四线三格区的绘制方法

[cpp] view plain copy
  1. private View.OnTouchListener touch = new View.OnTouchListener() {  
  2.        // 定义手指开始触摸的坐标  
  3.        float startX;  
  4.        float startY;  
  5.   
  6.   
  7.        @Override  
  8.        public boolean onTouch(View v, MotionEvent event) {  
  9.            paint.setStrokeWidth(8);  
  10.            switch (event.getAction()) {  
  11.                // 用户按下动作  
  12.                case MotionEvent.ACTION_DOWN:  
  13.                    // 第一次绘图初始化内存图片,指定背景为白色  
  14.                    // 记录开始触摸的点的坐标  
  15.                    startX = event.getX();  
  16.                    startY = event.getY();  
  17.                    break;  
  18.                // 用户手指在屏幕上移动的动作  
  19.                case MotionEvent.ACTION_MOVE:  
  20.                    // 记录移动位置的点的坐标  
  21.                    float stopX = event.getX();  
  22.                    float stopY = event.getY();  
  23.   
  24.                    //根据两点坐标,绘制连线  
  25.                    paint.setARGB(255, 0, 0, 0);  
  26.                    canvas.drawLine(startX, startY, stopX, stopY, paint);  
  27.   
  28.                    // 更新开始点的位置  
  29.                    startX = event.getX();  
  30.                    startY = event.getY();  
  31.   
  32.                    // 把图片展示到ImageView中  
  33.                    iv1.setImageBitmap(baseBitmap);  
  34.                    break;  
  35.                case MotionEvent.ACTION_UP:  
  36.                    break;  
  37.                default:  
  38.                    break;  
  39.            }  
  40.            return true;  
  41.        }  
  42.    };  

4.保存按钮监听器:

[cpp] view plain copy
  1. //保存按钮监听器  
  2.     class insertListener implements View.OnClickListener{  
  3.   
  4.         @Override  
  5.         public void onClick(View view) {  
  6.   
  7.             int[][] pixel = saveScaledBitmapArray(baseBitmap);  
  8.             int row = pixel.length;  
  9.             int col = pixel[0].length;  
  10.   
  11.             for(int i = 0; i<row;i++)  
  12.             {  
  13.                 for(int j = 0;j<col;j++)  
  14.                 {  
  15.                     s += pixel[i][j]+",";  
  16.                 }  
  17.             }  
  18.   
  19.             ContentValues values = new ContentValues();  
  20.             char letter = (char)('!'+count);  
  21.             String str = ""+letter;  
  22.             values.put("id",str);  
  23.             values.put("content",s);  
  24.             values.put("name",count);  
  25.             ImageSQLiteHelper dbHelper = new ImageSQLiteHelper(CreateActivity.this,"my_nn_database");  
  26.             SQLiteDatabase db = dbHelper.getWritableDatabase();  
  27.             db.insert("array",null,values);  
  28.             s="";  
  29.         }  
  30.     }  
[cpp] view plain copy
  1. //保存的为缩放后的bitmap(并且只保存黑色像素)  
  2.     protected int[][] saveScaledBitmapArray(Bitmap bmp) {  
  3.         Bitmap new_bmp = scaleBitmap(bmp,0.25f);  
  4.         int width = new_bmp.getWidth();  
  5.         int height = new_bmp.getHeight();  
  6.         //bmp.getPixels(pixels,0,width,0,0,width,height);  
  7.         int[][] ps = new int[height][width];//存成一个长*宽的矩阵  
  8.         for (int i = 0; i < height; i++) {  
  9.             for (int j = 0; j < width; j++) {  
  10.                 int p = new_bmp.getPixel(j, i);//p是-1是白色,p是-16777216是黑色  
  11.                 if (p == -16777216)  
  12.                     ps[i][j] = 0;  
  13.                 else  
  14.                     ps[i][j] = 1;  
  15.             }  
  16.         }  
  17.         return ps;  
  18.     }  

5.重画按钮监听器,将该条目从数据库删除,并清空画布:

[cpp] view plain copy
  1. class resumeListener implements View.OnClickListener{//重画  
  2.   
  3.         @Override  
  4.         public void onClick(View view) {  
  5.             ImageSQLiteHelper dbHelper = new ImageSQLiteHelper(CreateActivity.this,"my_nn_database");  
  6.             SQLiteDatabase db = dbHelper.getWritableDatabase();  
  7.             db.delete("array","name=?",new String[]{count+""});  
  8.             resumeCanvas();  
  9.         }  
  10.     }  
重画中用到的清空画布方法:
[cpp] view plain copy
  1. protected void resumeCanvas() {  
  2.         // 手动清除画板的绘图,重新创建一个画板  
  3.         paint.setStrokeWidth(2);  
  4.         if (baseBitmap != null) {  
  5.             baseBitmap = Bitmap.createBitmap(iv1.getWidth(),  
  6.                    iv1.getHeight(), Bitmap.Config.ARGB_8888);  
  7.             canvas = new Canvas(baseBitmap);  
  8.             canvas.drawColor(Color.WHITE);  
  9.             paint.setColor(Color.RED);  
  10.             canvas.drawLine(0,350,300,350,paint);  
  11.             paint.setColor(Color.BLUE);  
  12.             canvas.drawLine(0,250,300,250,paint);  
  13.             paint.setColor(Color.RED);  
  14.             canvas.drawLine(0,150,300,150,paint);  
  15.             canvas.drawLine(0,50,300,50,paint);  
  16.             iv1.setImageBitmap(baseBitmap);  
  17.         }  
  18.     }  

6.“下一页”按钮监听器,将count加一,并将指示区字符替换,同时判断该字符是否已绘制。

[cpp] view plain copy
  1. class nextListener implements View.OnClickListener{  
  2.   
  3.         @Override  
  4.         public void onClick(View view) {  
  5.             count++;  
  6.             char letter = (char)('!'+ count);  
  7.             tv.setText(""+letter);  
  8.             baseBitmap = Bitmap.createBitmap(MY_COL*4, MY_ROW*4, Bitmap.Config.ARGB_8888);  
  9.             //如果数据库已保存了,就显示出来  
  10.             if(searchExistence(count+"")){  
  11.                 int[][] bitmapArray=getImageArry(count+"");  
  12.                 Bitmap bb=arrayToBitmap(bitmapArray);  
  13.                 baseBitmap=scaleBitmap(bb,4);  
  14.             }  
  15.   
  16.             canvas = new Canvas(baseBitmap);  
  17.             paint.setColor(Color.BLACK);  
  18.             paint.setStrokeWidth(2);  
  19.             paint.setColor(Color.RED);  
  20.             canvas.drawLine(0,350,300,350,paint);  
  21.             paint.setColor(Color.BLUE);  
  22.             canvas.drawLine(0,250,300,250,paint);  
  23.             paint.setColor(Color.RED);  
  24.             canvas.drawLine(0,150,300,150,paint);  
  25.             canvas.drawLine(0,50,300,50,paint);  
  26.             iv1.setImageBitmap(baseBitmap);  
  27.   
  28.         }  
  29.     }  

7.全部删除按钮监听器:

[cpp] view plain copy
  1. class deleteListener implements View.OnClickListener{  
  2.   
  3.         @Override  
  4.         public void onClick(View view) {  
  5.             ImageSQLiteHelper dbHelper = new ImageSQLiteHelper(CreateActivity.this,"my_nn_database");  
  6.             SQLiteDatabase db = dbHelper.getWritableDatabase();  
  7.             db.delete("array",null,null);  
  8.         }  
  9.     }  

8.标题栏和系统返回按钮监听器:

[cpp] view plain copy
  1. class mIvBackListener implements View.OnClickListener{  
  2.         @Override  
  3.         public void onClick(View view){  
  4.             getImageArry();  
  5.             finish();  
  6.         }  
  7.     }  
  8.   
  9.     public void onBackPressed() {  
  10.         getImageArry();  
  11.         finish();  
  12.     }  

因为返回时数据库可能以改变,所以对应的myImageArrays数组也要更新,用于后续的使用:

[cpp] view plain copy
  1. private int[][] getImageArry(String value){  
  2.         int[][] myImageArray1 = new int[MY_ROW][MY_COL];  
  3.         ImageSQLiteHelper dbHelper = new ImageSQLiteHelper(CreateActivity.this,"my_nn_database");  
  4.         SQLiteDatabase db = dbHelper.getWritableDatabase();  
  5.         Cursor cursor = db.query("array",new String[]{"id","content","name"},"name=?",new String[]{value},null,null,"id",null);  
  6.         while (cursor.moveToNext()) {  
  7.             String content = cursor.getString(cursor.getColumnIndex("content"));  
  8.             String id = cursor.getString(cursor.getColumnIndex("id"));  
  9.             String num = cursor.getString(cursor.getColumnIndex("name"));//!的name是0  
  10.             System.out.println("" + num + "   " + content + "------------" + id);  
  11.   
  12.             String[] imageStr1 = content.split("[,]");  
  13.             for(int j = 0;j<MY_ROW;j++)  
  14.             {  
  15.                 for(int k = 0;k<MY_COL;k++)  
  16.                 {  
  17.                     myImageArray1[j][k] = Integer.parseInt(imageStr1[MY_COL*j+k]);  
  18.                     //System.out.println(myImageArray1[j][k]);  
  19.                 }  
  20.                 //System.out.println();  
  21.             }  
  22.         }  
  23.         return myImageArray1;  
  24.     }  


仝心:

通过上次的工作基础,我们本次进行了更加深入的个人工作,完成了语音识别功能。

1.因为我们的应用是基于英文环境,所以经过调查我们选择了科大讯飞语音云。

首先申请一个appid,然后添加语音听写服务,下载对应的SDK

实训第二周(2)

2.下载完成,解压压缩包如下图所示

实训第二周(2)

3.assets文件夹中的内容拷贝到项目assets文件夹(新建)中,将Msc.jar和Sunflower.jar拷贝到文件夹libs中,在和res同级的目录下创建jniLibs文件夹(),并将下载下来的libs目录下的所有libmsc.so文件拷贝到该文件夹下(很重要,目录结构一定不要创建错,否则会报错误“创建对象失败,请确认 libmsc.so 放置正确,且有调用 createUtility 进行初始化”)

4.在AndroidMainfest.xml中添加如下权限


[java] view plain copy
  1. <uses-permission android:name="android.permission.RECORD_AUDIO" />  
  2. <uses-permission android:name="android.permission.INTERNET" />  
  3. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />  
  4. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />  
  5. <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />  
  6. <uses-permission android:name="android.permission.READ_PHONE_STATE" />  
  7. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />  
  8. <uses-permission android:name="android.permission.READ_CONTACTS" />  
  9. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
  10. <uses-permission android:name="android.permission.WRITE_SETTINGS" />  
  11. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />  

将申请的APPID记录下来,并保存到string文件中

5.在入口处初始化SpeechUtility对象

[java] view plain copy
  1. protected void onCreate(Bundle savedInstanceState) {  
  2.     SpeechUtility.createUtility(MainActivity.this,"appid="+getString(R.string.app_id));  

6.初始化所需对象数据

[java] view plain copy
  1. private void initData() {  
  2.     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.点击开始按钮时,设置所需要的参数,弹出话筒框,并设置监听到的信息的监听

[java] view plain copy
  1. private void setOnclickListener() {  
  2.     btStart.setOnClickListener(new View.OnClickListener() {  
  3.         @Override        public void onClick(View v) {  
  4.             checkSoIsInstallSucceed();  
  5.             etContent.setText(null);// 清空显示内容  
  6.             mIatResults.clear();            // 设置参数  
  7.             setParam();  
  8.             boolean isShowDialog = mSharedPreferences.getBoolean(  
  9.                     getString(R.string.pref_key_iat_show), true);  
  10.             if (isShowDialog) {  
  11.                 // 显示听写对话框                  
  12.                 mIatDialog.setListener(mRecognizerDialogListener);  
  13.                 mIatDialog.show();  
  14.                 showTip(getString(R.string.text_begin));  
  15.             } else {  
  16.                 // 不显示听写对话框  
  17.                 ret = mIat.startListening(mRecognizerListener);  
  18.                 if (ret != ErrorCode.SUCCESS) {  
  19.                     showTip("听写失败,错误码:" + ret);  
  20.                 } else {  
  21.                     showTip(getString(R.string.text_begin));  
  22. public void setParam() {  
  23.     // 清空参数     
  24.     mIat.setParameter(SpeechConstant.PARAMS, null);  
  25.     // 设置听写引擎  
  26.     mIat.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);  
  27.     // 设置返回结果格式  
  28.     mIat.setParameter(SpeechConstant.RESULT_TYPE,"json");  
  29.     mIat.setParameter(SpeechConstant.LANGUAGE,"en_us");  
  30.     // 设置语音前端点:静音超时时间,即用户多长时间不说话则当做超时处理  
  31.     mIat.setParameter(SpeechConstant.VAD_BOS, mSharedPreferences.getString("iat_vadbos_preference""4000"));  
  32.     // 设置语音后端点:后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, 自动停止录音  
  33.     mIat.setParameter(SpeechConstant.VAD_EOS, mSharedPreferences.getString("iat_vadeos_preference""1000"));  
  34.     // 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点  
  35.     mIat.setParameter(SpeechConstant.ASR_PTT, mSharedPreferences.getString("iat_punc_preference""1"));  
  36.     // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限  
  37.     // 注:AUDIO_FORMAT参数语记需要更新版本才能生效  
  38.     mIat.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");  
  39.     mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/iat.wav");  

8.在界面销毁的时候,释放连接

[java] view plain copy
  1. protected void onDestroy() {  
  2. super.onDestroy();  
  3.     if (null != mIat) {  
  4.         // 退出时释放连接  
  5.         mIat.cancel();  
  6.         mIat.destroy();   
  7.    }  
  8. }  

9.对于结果的显示,要写一个JsonParser类

[java] view plain copy
  1. String text = JsonParser.parseIatResult(results.getResultString());  
  2. package com.example.liche.voicerecog2;  
  3. import org.json.JSONObject;  
  4. import org.json.JSONTokener;  
  5. import org.json.JSONArray;  
  6. /** * Created by liche on 2018/4/25. */  
  7. public class JsonParser {  
  8.     public static String parseIatResult(String json) {  
  9.         StringBuffer ret = new StringBuffer();  
  10.         try {  
  11.             JSONTokener tokener = new JSONTokener(json);  
  12.             JSONObject joResult = new JSONObject(tokener);  
  13.             JSONArray words = joResult.getJSONArray("ws");  
  14.             for (int i = 0; i < words.length(); i++) {  
  15.                 // 转写结果词,默认使用第一个结果  
  16.                 JSONArray items = words.getJSONObject(i).getJSONArray("cw");                 
  17.           JSONObject obj = items.getJSONObject(0);  
  18.                 ret.append(obj.getString("w"));           }  
  19.         } catch (Exception e) {  
  20.             e.printStackTrace();        }  
  21.         return ret.toString();    }  
  22.   
  23.     public static String parseGrammarResult(String json) {  
  24.         StringBuffer ret = new StringBuffer();  
  25.         try {  
  26.             JSONTokener tokener = new JSONTokener(json);  
  27.             JSONObject joResult = new JSONObject(tokener);  
  28.             JSONArray words = joResult.getJSONArray("ws");  
  29.             for (int i = 0; i < words.length(); i++) {  
  30.                 JSONArray items = words.getJSONObject(i).getJSONArray("cw");  
  31.                 for(int j = 0; j < items.length(); j++)  
  32.                 {  
  33.                     JSONObject obj = items.getJSONObject(j);  
  34.                     if(obj.getString("w").contains("nomatch"))  
  35.                     {  
  36.                         ret.append("没有匹配结果.");  
  37.                         return ret.toString();                    }  
  38.                     ret.append("【结果】" + obj.getString("w"));  
  39.                     ret.append("【置信度】" + obj.getInt("sc"));  
  40.                     ret.append("\n");                }  
  41.             }  
  42.         } catch (Exception e) {  
  43.             e.printStackTrace();  
  44.             ret.append("没有匹配结果.");        }  
  45.         return ret.toString();    }  
  46. }  

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

另外,我还完成了传感器数据的获取,主要是加速度计数据的获取,然后对这些数据进行加工成可以传入之前完成的方法的数据,传入字体抖动和字体倾斜的方法。

[java] view plain copy
  1. /** 
  2.      * 传感器监听器 
  3.      * */  
  4.     SensorEventListener sensorListener = new SensorEventListener() {  
  5.         //传感器改变时,一般是通过这个方法里面的参数确定传感器状态的改变  
  6.         @Override  
  7.         public void onSensorChanged(SensorEvent sensorEvent) {  
  8.             if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER)  
  9.             {  
  10.                 accelerometerValues = sensorEvent.values.clone();  
  11.                 float[] values = sensorEvent.values;//获取传感器的数据  
  12.                 //float max = sensor.getMaximumRange();//获取最大值范围  
  13.                 if (values.length >= 3) {  
  14.                     float x = values[0];//右侧面向上时为g(9.8)  
  15.                     float y = values[1];//上侧面向上时为g(9.8)  
  16.                     float z = values[2];  
  17.   
  18.                     //抖动  
  19.                     float xx = values[0] - usedValues[0];  
  20.                     float yy = values[1] - usedValues[1];  
  21.                     float zz = values[2] - usedValues[2];  
  22.                     float Tense = Math.abs(xx)+Math.abs(yy)+Math.abs(zz);  
  23.   
  24.                     //System.out.println(values[2]+"  " +usedValues[2]+"                "+Tense);  
  25.                     usedValues[0] = x;  
  26.                     usedValues[1] = y;  
  27.                     usedValues[2] = z;  
  28.                     if(Tense >=15)  
  29.                         tempTense = 1;  
  30.                     else if(Tense >=6&&Tense < 15)  
  31.                         tempTense = 2;  
  32.                     else if(Tense>=4&&Tense < 6)  
  33.                         tempTense = 6;  
  34.                     else if(Tense >=2&&Tense<4)  
  35.                         tempTense = 7;  
  36.                     else if(Tense>=1&&Tense<2)  
  37.                         tempTense = 8;  
  38.                     else  
  39.                         tempTense = 10;  
  40.                     //倾斜  
  41.                     float angle;  
  42.                     if(y>0)  
  43.                     {  
  44.                         angle = x*8;  
  45.                         if(angle>25)  
  46.                             angle = 25;  
  47.                     }  
  48.                     else  
  49.                         angle = 0;  
  50.                     //System.out.println(angle);  
  51.                     myKeyboard.getSkewData(angle);  
  52.                     //抖动  
  53.                     //float Tense = Math.abs(x)+Math.abs(y)+Math.abs(z);  
  54.                 }  
  55.                 //System.out.println(accelerometerValues[0]+" "+accelerometerValues[1]+" "+accelerometerValues[2]);  
  56.                 myKeyboard.getSensorData(tempTense);  
  57.             }else if (sensorEvent.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {// 注意赋值时要调用clone()方法  
  58.                 magneticValues = sensorEvent.values.clone();  
  59.                 //System.out.println(magneticValues[0]+" "+magneticValues[1]+" "+magneticValues[2]);  
  60.             }  
  61.         }  
  62.   
  63.         @Override  
  64.         public void onAccuracyChanged(Sensor sensor, int i) {  
  65.   
  66.         }  
  67.     };  

通过按下和抬起的时间差获取按键时间,经过加工后传入字体加粗的方法。

[java] view plain copy
  1. /** 
  2.      * 获得触键时间 
  3.      * */  
  4.     class touchKeyListener implements View.OnTouchListener{  
  5.   
  6.         @Override  
  7.         public boolean onTouch(View view, MotionEvent motionEvent) {  
  8.             //timer = new Chronometer(MainActivity.this);  
  9.             switch (motionEvent.getAction()) {  
  10.                 case MotionEvent.ACTION_DOWN:  
  11.                     Calendar calendar = Calendar.getInstance();  
  12.                     int YY = calendar.get(Calendar.YEAR);  
  13.                     int MM = calendar.get(Calendar.MONTH)+1;  
  14.                     int DD = calendar.get(Calendar.DATE);  
  15.                     int HH = calendar.get(Calendar.HOUR_OF_DAY);  
  16.                     int mm = calendar.get(Calendar.MINUTE);  
  17.                     int SS = calendar.get(Calendar.SECOND);  
  18.                     int MI = calendar.get(Calendar.MILLISECOND);  
  19.                     String string = YY+" "+MM+" "+DD+" "+HH+" "+mm+" "+SS+" "+MI+"";  
  20.   
  21.                     second1 = SS;  
  22.                     millisecond1 = MI;  
  23.                     //timer.setBase(SystemClock.elapsedRealtime());//计时器清零  
  24.                     //timer.start();  
  25.                     System.out.println("down");  
  26.                     System.out.println(string);  
  27.                     break;  
  28.                 case MotionEvent.ACTION_UP:  
  29.                     //timer.stop();  
  30.                     Calendar c = Calendar.getInstance();  
  31.                     int Y = c.get(Calendar.YEAR);  
  32.                     int M = c.get(Calendar.MONTH)+1;  
  33.                     int D = c.get(Calendar.DATE);  
  34.                     int H = c.get(Calendar.HOUR_OF_DAY);  
  35.                     int m = c.get(Calendar.MINUTE);  
  36.                     int S = c.get(Calendar.SECOND);  
  37.                     int mi = c.get(Calendar.MILLISECOND);  
  38.                     String s = Y+" "+M+" "+D+" "+H+" "+m+" "+S+" "+mi+"";  
  39.                     second2 = S;  
  40.                     millisecond2 = mi;  
  41.                     totalMilliSecond = (second2-second1)*1000+millisecond2-millisecond1;  
  42.                     int thick;  
  43.                     if(totalMilliSecond<300)  
  44.                         thick = 2;  
  45.                     else if(totalMilliSecond>=300&&totalMilliSecond<600)  
  46.                         thick = 5;  
  47.                     else if(totalMilliSecond>=600&&totalMilliSecond<800)  
  48.                         thick = 6;  
  49.                     else if(totalMilliSecond>=800&&totalMilliSecond<1000)  
  50.                         thick = 7;  
  51.                     else  thick = 8;  
  52.                     myKeyboard.getTouchTime(thick);  
  53.                     System.out.println("up");  
  54.                     break;  
  55.                 case MotionEvent.ACTION_MOVE:  
  56.                     break;  
  57.                 default:  
  58.                     break;  
  59.             }  
  60.             return false;  
  61.         }  
  62.     }  


张静:

这周接下来我完成MainActivity中的initHandler中声明的四个handler实现(完成了三个,第四个未完成):

1. NimOnlineStatusHandler 

a. 使用getInstance()实例化

[java] view plain copy
  1. public static NimOnlineStatusHandler getInstance(){  
  2.         if (instance == null){  
  3.             synchronized (NimOnlineStatusHandler.class){  
  4.                 if (instance == null){  
  5.                     instance = new NimOnlineStatusHandler();  
  6.                 }  
  7.             }  
  8.         }  
  9.   
  10.         return instance;  
  11.     }  

b. 初始化

通过NimClient的getService接口获取到AuthServiceObserver(用户状态观察者接口)服务实例

可监听用户在线状态,登录成功后,SDK回负责维护与服务器的长连接以及断线重连等工作

当用户在线状态发生改变时,会发出通知

定义了三种情况,会导致MainActivity的initHandler中重写的requestReLogin或networkBroken:

[java] view plain copy
  1. @Override  
  2. public void requestReLogin(String message) {  
  3.     ToastUtils.showMessage(MainActivity.this,"自动登陆失败或被踢出,请手动登陆~");  
  4.     startActivity(new Intent(MainActivity.this,LoginActivity.class));  
  5.     }  
  6. @Override  
  7. public void networkBroken() {  
  8.     }  

(1) StatusCode为UNLOGIN(未登录/登录失败)或FORBIDDEN(被服务器禁止登陆)

调用requestReLogin("UN_LOGIN"), 跳转到登录页面,显示“自动登录失败或被踢出,请手动登陆~”

(2) StatusCode为KICK_BY_OTHER_CLIENT(被同时在线的其他端主动踢掉)或KICKOUT(被其他端的登录踢掉)

调用requestReLogin("UN_LOGIN"), 跳转到登录页面,显示“自动登录失败或被踢出,请手动登陆~”

(3) StatusCode为NET_BROKEN(网络连接已断开)

调用networkBroken

[java] view plain copy
  1. public void init(){  
  2.         mListeners = new ArrayList<>();  
  3.         NIMClient.getService(AuthServiceObserver.class)  
  4.                 .observeOnlineStatus(new Observer<StatusCode>() {  
  5.             @Override  
  6.             public void onEvent(StatusCode statusCode) {  
  7.                 if (statusCode == StatusCode.UNLOGIN || statusCode == StatusCode.FORBIDDEN){  
  8.                     Log.e(TAG,"OnlineObserver---UN_LOGIN");  
  9.                     if (mListeners != null && !mListeners.isEmpty()){  
  10.                         for (OnStatusChangeListener listener : mListeners){  
  11.                             listener.requestReLogin("UN_LOGIN");  
  12.                         }  
  13.                     }  
  14.                 }else if (statusCode == StatusCode.KICK_BY_OTHER_CLIENT  
  15.                         || statusCode == StatusCode.KICKOUT){  
  16.                     Log.e(TAG,"OnlineObserver---KICK_OUT");  
  17.                     if (mListeners != null && !mListeners.isEmpty()){  
  18.                         for (OnStatusChangeListener listener : mListeners){  
  19.                             listener.requestReLogin("KICK_OUT");  
  20.                         }  
  21.                     }  
  22.                 } else if (statusCode == StatusCode.NET_BROKEN){  
  23.                     Log.e(TAG,"OnlineObserver---NET_BROKEN");  
  24.                     if (mListeners != null && !mListeners.isEmpty()){  
  25.                         for (OnStatusChangeListener listener : mListeners){  
  26.                             listener.networkBroken();  
  27.                         }  
  28.                     }  
  29.                 }  
  30.             }  
  31.         },true);  
  32.     }  


附上完整代码:

[java] view plain copy
  1. package com.ezreal.ezchat.handler;  
  2.   
  3. import android.util.Log;  
  4.   
  5. import com.netease.nimlib.sdk.NIMClient;  
  6. import com.netease.nimlib.sdk.Observer;  
  7. import com.netease.nimlib.sdk.StatusCode;  
  8. import com.netease.nimlib.sdk.auth.AuthServiceObserver;  
  9.   
  10. import java.util.ArrayList;  
  11. import java.util.List;  
  12.   
  13. /** 
  14.  * Created by 张静 . 
  15.  */  
  16.   
  17. public class NimOnlineStatusHandler {  
  18.   
  19.     private static final String TAG = NimOnlineStatusHandler.class.getSimpleName();  
  20.     private static NimOnlineStatusHandler instance;  
  21.     private List<OnStatusChangeListener> mListeners;  
  22.   
  23.     public static NimOnlineStatusHandler getInstance(){  
  24.         if (instance == null){  
  25.             synchronized (NimOnlineStatusHandler.class){  
  26.                 if (instance == null){  
  27.                     instance = new NimOnlineStatusHandler();  
  28.                 }  
  29.             }  
  30.         }  
  31.   
  32.         return instance;  
  33.     }  
  34.   
  35.     public void init(){  
  36.         mListeners = new ArrayList<>();  
  37.         //用户状态观察者接口  
  38.         //监听用户在线状态,登录成功后,SDK会负责维护与服务器的长连接以及断线重连等工作  
  39.         //用户在线状态发生改变时,会发出通知  
  40.         NIMClient.getService(AuthServiceObserver.class)  
  41.                 .observeOnlineStatus(new Observer<StatusCode>() {  
  42.             @Override  
  43.             public void onEvent(StatusCode statusCode) {  
  44.                 if (statusCode == StatusCode.UNLOGIN || statusCode == StatusCode.FORBIDDEN){  
  45.                     Log.e(TAG,"OnlineObserver---UN_LOGIN");  
  46.                     if (mListeners != null && !mListeners.isEmpty()){  
  47.                         for (OnStatusChangeListener listener : mListeners){  
  48.                             listener.requestReLogin("UN_LOGIN");  
  49.                         }  
  50.                     }  
  51.                 }else if (statusCode == StatusCode.KICK_BY_OTHER_CLIENT  
  52.                         || statusCode == StatusCode.KICKOUT){  
  53.                     Log.e(TAG,"OnlineObserver---KICK_OUT");  
  54.                     if (mListeners != null && !mListeners.isEmpty()){  
  55.                         for (OnStatusChangeListener listener : mListeners){  
  56.                             listener.requestReLogin("KICK_OUT");  
  57.                         }  
  58.                     }  
  59.                 } else if (statusCode == StatusCode.NET_BROKEN){  
  60.                     Log.e(TAG,"OnlineObserver---NET_BROKEN");  
  61.                     if (mListeners != null && !mListeners.isEmpty()){  
  62.                         for (OnStatusChangeListener listener : mListeners){  
  63.                             listener.networkBroken();  
  64.                         }  
  65.                     }  
  66.                 }  
  67.             }  
  68.         },true);  
  69.     }  
  70.   
  71.     public void setStatusChangeListener(OnStatusChangeListener listener){  
  72.         mListeners.add(listener);  
  73.     }  
  74.   
  75.     public void removeStatusChangeListener(OnStatusChangeListener listener){  
  76.         mListeners.remove(listener);  
  77.     }  
  78.   
  79.     public interface OnStatusChangeListener {  
  80.         void requestReLogin(String message);  
  81.         void networkBroken();  
  82.     }  
  83.   
  84. }  


2. NimSysMsgHandler

(1)通过NimClient的getService接口获取到SystemMessageObserver(系统通知观察者)服务实例

添加好友请求发出后,对方会收到一条SystemMessage,可以通过SystemMessageObserver的observeReceiveSystemMsg函数来监听系统通知,通过getAttachObject函数可以获取添加好友的通知

[java] view plain copy
  1. public void init(){  
  2.         mMessageListener = new ArrayList<>();  
  3.         NIMClient.getService(SystemMessageObserver.class)  
  4.                 .observeReceiveSystemMsg(new Observer<SystemMessage>() {  
  5.             @Override  
  6.             public void onEvent(SystemMessage message) {  
  7.                 AddFriendNotify notify = (AddFriendNotify) message.getAttachObject();  
  8.                 if (notify != null){  
  9.                     for (SystemMessageListener l : mMessageListener){  
  10.                         l.addFriendNotify();  
  11.                     }  
  12.                 }  
  13.             }  
  14.         },true);  
  15.     }  
(2)其中,AddFriendNotify(为bean类):
[java] view plain copy
  1. public class AddFriendNotify {  
  2.     private SystemMessage mMessage;  
  3.     private NimUserInfo mUserInfo;//用户资料  
  4.     private boolean isMyFriend;  
  5.   
  6.     public SystemMessage getMessage() {  
  7.         return mMessage;  
  8.     }  
  9.   
  10.     public void setMessage(SystemMessage message) {  
  11.         mMessage = message;  
  12.     }  
  13.   
  14.     public NimUserInfo getUserInfo() {  
  15.         return mUserInfo;  
  16.     }  
  17.   
  18.     public void setUserInfo(NimUserInfo userInfo) {  
  19.         mUserInfo = userInfo;  
  20.     }  
  21.   
  22.     public boolean isMyFriend() {  
  23.         return isMyFriend;  
  24.     }  
  25.   
  26.     public void setMyFriend(boolean myFriend) {  
  27.         isMyFriend = myFriend;  
  28.     }  
  29. }  

(3)附上NimSysMsgHandler完整代码:

[java] view plain copy
  1. package com.ezreal.ezchat.handler;  
  2.   
  3. import android.util.Log;  
  4.   
  5. import com.netease.nimlib.sdk.NIMClient;  
  6. import com.netease.nimlib.sdk.Observer;  
  7. import com.netease.nimlib.sdk.friend.model.AddFriendNotify;  
  8. import com.netease.nimlib.sdk.msg.SystemMessageObserver;  
  9. import com.netease.nimlib.sdk.msg.model.SystemMessage;  
  10.   
  11. import java.util.ArrayList;  
  12. import java.util.List;  
  13. import java.util.TimeZone;  
  14.   
  15. /** 
  16.  * Created by 张静. 
  17.  */  
  18.   
  19. public class NimSysMsgHandler {  
  20.   
  21.     private static final String TAG = NimSysMsgHandler.class.getSimpleName();  
  22.     private static NimSysMsgHandler instance;  
  23.     private List<SystemMessageListener> mMessageListener;  
  24.     public static NimSysMsgHandler getInstance(){  
  25.         if (instance == null){  
  26.             synchronized (NimSysMsgHandler.class){  
  27.                 if (instance == null){  
  28.                     instance = new NimSysMsgHandler();  
  29.                 }  
  30.             }  
  31.         }  
  32.         return instance;  
  33.     }  
  34.   
  35.     public void init(){  
  36.         mMessageListener = new ArrayList<>();  
  37.         NIMClient.getService(SystemMessageObserver.class)  
  38.                 .observeReceiveSystemMsg(new Observer<SystemMessage>() {  
  39.             @Override  
  40.             public void onEvent(SystemMessage message) {  
  41.                 AddFriendNotify notify = (AddFriendNotify) message.getAttachObject();  
  42.                 if (notify != null){  
  43.                     for (SystemMessageListener l : mMessageListener){  
  44.                         l.addFriendNotify();  
  45.                     }  
  46.                 }  
  47.             }  
  48.         },true);  
  49.     }  
  50.   
  51.     public void setMessageListener(SystemMessageListener listener){  
  52.         mMessageListener.add(listener);  
  53.     }  
  54.   
  55.     public interface SystemMessageListener{  
  56.         void addFriendNotify();  
  57.     }  
  58. }  


3. NimFriendHandler

(1)通过NimClient的getService接口获取到FriendServiceObserve(好友关系、黑名单变更通知)服务实例来监听好友关系变化通知

[java] view plain copy
  1. public void init() {  
  2.        mFriendAccounts = new ArrayList<>();  
  3.        mFriends = new ArrayList<>();  
  4.        mFriendInfos = new ArrayList<>();  
  5.   
  6.        // 初始化好友列表更新监听  
  7.        NIMClient.getService(FriendServiceObserve.class)  
  8.                .observeFriendChangedNotify(new Observer<FriendChangedNotify>() {  
  9.                    @Override  
  10.                    public void onEvent(FriendChangedNotify notify) {  
  11.                        loadFriendData();  
  12.                    }  
  13.                }, true);  
  14.        loadFriendData();  
  15.    }  

(2)读取账户好友列表数据

通过NimClient的getService接口获取到FriendService(好友管理/好友关系/黑名单关系/消息提醒相关操作)服务实例

调用getFriendAccounts获取我所有的好友账号

调用getFriendByAccount根据用户账号获取好友关系

通过NimClient的getService接口获取到UserService(用户资料操作相关接口)服务实例

调用getUserInfoList从本地数据库中批量获取用户资料(同步接口)

[java] view plain copy
  1. private void loadFriendData() {  
  2.         mFriendAccounts.clear();  
  3.         List<String> friendAccounts = NIMClient.getService(FriendService.class).getFriendAccounts();  
  4.         if (friendAccounts == null || friendAccounts.isEmpty()) {  
  5.             return;  
  6.         }  
  7.         mFriendAccounts.addAll(friendAccounts);  
  8.   
  9.         mFriends.clear();  
  10.         Friend friend;  
  11.         for (String account : mFriendAccounts) {  
  12.             friend = NIMClient.getService(FriendService.class).getFriendByAccount(account);  
  13.             mFriends.add(friend);  
  14.         }  
  15.   
  16.         mFriendInfos.clear();  
  17.         List<NimUserInfo> userInfoList = NIMClient.getService(UserService.class)  
  18.                 .getUserInfoList(mFriendAccounts);  
  19.         mFriendInfos.addAll(userInfoList);  
  20.   
  21.         //更新用户界面  
  22.         if (mUpdateListener != null){  
  23.             mUpdateListener.friendUpdate();  
  24.         }  
  25.     }  
(3)设置好友列表更新监听
[java] view plain copy
  1. public void setUpdateListener(OnFriendUpdateListener listener){  
  2.         this.mUpdateListener = listener;  
  3.     }  

(4)检查该账户是否为我的好友

通过NimClient的getService接口获取到FriendService(好友管理/好友关系/黑名单关系/消息提醒相关操作)服务实例

[java] view plain copy
  1. public boolean CheckIsMyFriend(String account) {  
  2.         return NIMClient.getService(FriendService.class).isMyFriend(account);  
  3.     }  
(5)附上完整代码
[java] view plain copy
  1. package com.ezreal.ezchat.handler;  
  2.   
  3. import android.util.Log;  
  4.   
  5. import com.netease.nimlib.sdk.NIMClient;  
  6. import com.netease.nimlib.sdk.Observer;  
  7. import com.netease.nimlib.sdk.friend.FriendService;  
  8. import com.netease.nimlib.sdk.friend.FriendServiceObserve;  
  9. import com.netease.nimlib.sdk.friend.model.Friend;  
  10. import com.netease.nimlib.sdk.friend.model.FriendChangedNotify;  
  11. import com.netease.nimlib.sdk.uinfo.UserService;  
  12. import com.netease.nimlib.sdk.uinfo.model.NimUserInfo;  
  13.   
  14. import java.util.ArrayList;  
  15. import java.util.List;  
  16.   
  17.   
  18. /** 
  19.  * Created by 张静. 
  20.  */  
  21.   
  22. public class NimFriendHandler {  
  23.     private static final String TAG = NimFriendHandler.class.getSimpleName();  
  24.     private static NimFriendHandler instance;  
  25.     private List<String> mFriendAccounts;  
  26.     private List<NimUserInfo> mFriendInfos;  
  27.     private List<Friend> mFriends;  
  28.     private OnFriendUpdateListener mUpdateListener;  
  29.   
  30.     public static NimFriendHandler getInstance() {  
  31.         if (instance == null) {  
  32.             synchronized (NimFriendHandler.class) {  
  33.                 if (instance == null) {  
  34.                     instance = new NimFriendHandler();  
  35.                 }  
  36.             }  
  37.         }  
  38.         return instance;  
  39.     }  
  40.   
  41.     /** 
  42.      * 初始化好友列表工具类 
  43.      * 根据账户获取好友列表 
  44.      * 同步本地数据库的好友账户数据 
  45.      */  
  46.     public void init() {  
  47.         mFriendAccounts = new ArrayList<>();  
  48.         mFriends = new ArrayList<>();  
  49.         mFriendInfos = new ArrayList<>();  
  50.   
  51.         // 初始化好友列表更新监听  
  52.         NIMClient.getService(FriendServiceObserve.class)  
  53.                 .observeFriendChangedNotify(new Observer<FriendChangedNotify>() {  
  54.                     @Override  
  55.                     public void onEvent(FriendChangedNotify notify) {  
  56.                         loadFriendData();  
  57.                     }  
  58.                 }, true);  
  59.         loadFriendData();  
  60.     }  
  61.   
  62.     public List<String> getFriendAccounts() {  
  63.         return mFriendAccounts;  
  64.     }  
  65.   
  66.     public List<NimUserInfo> getFriendInfos() {  
  67.         return mFriendInfos;  
  68.     }  
  69.   
  70.     public List<Friend> getFriends() {  
  71.         return mFriends;  
  72.     }  
  73.   
  74.     /** 
  75.      * 读取账户好友列表数据 
  76.      */  
  77.     private void loadFriendData() {  
  78.         mFriendAccounts.clear();  
  79.         List<String> friendAccounts = NIMClient.getService(FriendService.class).getFriendAccounts();  
  80.         if (friendAccounts == null || friendAccounts.isEmpty()) {  
  81.             return;  
  82.         }  
  83.         mFriendAccounts.addAll(friendAccounts);  
  84.   
  85.         mFriends.clear();  
  86.         Friend friend;  
  87.         for (String account : mFriendAccounts) {  
  88.             friend = NIMClient.getService(FriendService.class).getFriendByAccount(account);  
  89.             mFriends.add(friend);  
  90.         }  
  91.   
  92.         mFriendInfos.clear();  
  93.         List<NimUserInfo> userInfoList = NIMClient.getService(UserService.class)  
  94.                 .getUserInfoList(mFriendAccounts);  
  95.         mFriendInfos.addAll(userInfoList);  
  96.   
  97.         //更新用户界面  
  98.         if (mUpdateListener != null){  
  99.             mUpdateListener.friendUpdate();  
  100.         }  
  101.     }  
  102.   
  103.     /** 
  104.      * 设置好友列表更新监听 
  105.      * @param listener listener 
  106.      */  
  107.     public void setUpdateListener(OnFriendUpdateListener listener){  
  108.         this.mUpdateListener = listener;  
  109.     }  
  110.   
  111.     /** 
  112.      * 检查该账户是否为我的好友 
  113.      * 
  114.      * @param account 待检查账户 
  115.      * @return true 如果对方是好友,否则返回 false 
  116.      */  
  117.     public boolean CheckIsMyFriend(String account) {  
  118.         return NIMClient.getService(FriendService.class).isMyFriend(account);  
  119.     }  
  120.   
  121.     public void syncFriendInfo(List<String> accounts) {  
  122.         NIMClient.getService(UserService.class).fetchUserInfo(accounts);  
  123.     }  
  124.   
  125.     public interface OnFriendUpdateListener{  
  126.         void friendUpdate();  
  127.     }  
  128. }