Android手势源码浅析-----手势的保存和加载(GestureLibrary)

目录(?)[+]

    前言:在《Android手势源码浅析------手势的形成(Gesture)》文章中,介绍了手势Gesture的形成。那么,有的时候,用户绘制的手势是需要保存的,以便用户需要时加载出来进行相关的手势识别处理;接下来将结合一个Demo重点介绍源码中手势的保存和加载流程机制;

    一. 关于手势保存和加载的Demo       

         手势保存概要:

           1. 在绘制完手势后,需要将手势存入手势库中,手势最终会被解析存放在指定路径创建的文件中。

           2.  一般是GestureOverlayView添加实现监听器OnGesturePerformedListener,当绘制完手势时,会调用监听器的onGesturePerformed(GestureOverlayViewoverlay, Gesture gesture);

           3. onGesturePerformed方法的第二个参数geture(Gesture对象)就代表用户绘制完成后形成的手势;

           4.  将得到的Gesture对象通过调用GestureLibrary的addGesture方法存入手势库创建的指定文件中;

        以下举一个简单的Demo来说明第三方应用开发实现手势的保存和加载:

           主类代码如下:

[java]  view plain  copy
  1. package com.stevenhu.hu.dgt;  
  2.   
  3. import java.io.File;  
  4.   
  5. import android.app.Activity;  
  6. import android.app.AlertDialog;  
  7. import android.app.AlertDialog.Builder;  
  8. import android.content.DialogInterface;  
  9. import android.content.DialogInterface.OnClickListener;  
  10. import android.content.Intent;  
  11. import android.gesture.Gesture;  
  12. import android.gesture.GestureLibraries;  
  13. import android.gesture.GestureLibrary;  
  14. import android.gesture.GestureOverlayView;  
  15. import android.gesture.GestureOverlayView.OnGesturePerformedListener;  
  16. import android.graphics.Bitmap;  
  17. import android.os.Bundle;  
  18. import android.os.Environment;  
  19. import android.view.Menu;  
  20. import android.view.MenuItem;  
  21. import android.view.MenuItem.OnMenuItemClickListener;  
  22. import android.view.View;  
  23. import android.widget.EditText;  
  24. import android.widget.ImageView;  
  25. import android.widget.Toast;  
  26.   
  27. public class DrawGestureTest extends Activity implements OnGesturePerformedListener  
  28. {  
  29.       
  30.     private GestureOverlayView mDrawGestureView;  
  31.     private static GestureLibrary sStore;  
  32.       
  33.     /** Called when the activity is first created. */  
  34.     @Override  
  35.     public void onCreate(Bundle savedInstanceState)  
  36.     {  
  37.         super.onCreate(savedInstanceState);  
  38.         setContentView(R.layout.main);  
  39.           
  40.         mDrawGestureView = (GestureOverlayView)findViewById(R.id.gesture);  
  41.           
  42.         //设置手势可多笔画绘制,默认情况为单笔画绘制  
  43.         mDrawGestureView.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE);  
  44.         //设置手势的颜色(蓝色)  
  45.         mDrawGestureView.setGestureColor(gestureColor(R.color.gestureColor));  
  46.         //设置还没未能形成手势绘制是的颜色(红色)  
  47.         mDrawGestureView.setUncertainGestureColor(gestureColor(R.color.ungestureColor));  
  48.         //设置手势的粗细  
  49.         mDrawGestureView.setGestureStrokeWidth(4);  
  50.         /*手势绘制完成后淡出屏幕的时间间隔,即绘制完手指离开屏幕后相隔多长时间手势从屏幕上消失; 
  51.          * 可以理解为手势绘制完成手指离开屏幕后到调用onGesturePerformed的时间间隔 
  52.          * 默认值为420毫秒,这里设置为0.5秒 
  53.          */  
  54.         mDrawGestureView.setFadeOffset(500);  
  55.           
  56.         //绑定监听器  
  57.         mDrawGestureView.addOnGesturePerformedListener(this);  
  58.         //创建保存手势的手势库  
  59.         createStore();  
  60.     }  
  61.       
  62.     private void createStore()  
  63.     {  
  64.         File mStoreFile = null;   
  65.         /*判断mStoreFile是为空。 
  66.          * 判断手机是否插入SD卡,并且应用程序是否具有访问SD卡的权限 
  67.          */  
  68.         if (mStoreFile == null && Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))  
  69.         {  
  70.             mStoreFile = new File(Environment.getExternalStorageDirectory(), "mygesture");  
  71.         }   
  72.           
  73.         if (sStore == null)  
  74.         {  
  75.             /* 另外三种创建保存手势文件的方式如下: 
  76.             //保存手势的文件在手机SD卡中 
  77.             sStore = GestureLibraries.fromFile(Environment.getExternalStorageDirectory().getAbsolutePath() + "mygesture"); 
  78.             sStore = GestureLibraries.fromPrivateFile(this, Environment.getExternalStorageDirectory().getAbsolutePath + "mygesture"); 
  79.             //保存手势的文件在应用程序的res/raw文件下 
  80.             sStore = GestureLibraries.fromRawResource(this, R.raw.gestures); 
  81.             */    
  82.             sStore = GestureLibraries.fromFile(mStoreFile);  
  83.         }  
  84.         testLoad();  
  85.     }  
  86.       
  87.     //测试保存手势的文件是否创建成功  
  88.     private void testLoad()  
  89.     {  
  90.         if (sStore.load())  
  91.         {  
  92.             showMessage("手势文件装载成功");  
  93.         }  
  94.         else  
  95.         {  
  96.             showMessage("手势文件装载失败");  
  97.         }  
  98.     }  
  99.       
  100.     public static GestureLibrary getStore()  
  101.     {  
  102.         return sStore;  
  103.     }  
  104.       
  105.     //手势绘制完成时调用  
  106.     @Override  
  107.     public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture)   
  108.     {  
  109.         // TODO Auto-generated method stub  
  110.         creatDialog(gesture);  
  111.     }  
  112.       
  113.     private void creatDialog(final Gesture gesture)  
  114.     {  
  115.         View dialogView = getLayoutInflater().inflate(R.layout.show_gesture, null);  
  116.         //imageView用于显示绘制的手势  
  117.         ImageView imageView = (ImageView) dialogView.findViewById(R.id.show);  
  118.         //获取用户保存手势的名字  
  119.         EditText editText = (EditText)dialogView.findViewById(R.id.name);  
  120.         final String name = editText.getText().toString();  
  121.         // 调用Gesture的toBitmap方法形成对应手势的位图  
  122.         final Bitmap bitmap = gesture.toBitmap(12812810, gestureColor(R.color.showColor));  
  123.         imageView.setImageBitmap(bitmap);  
  124.           
  125.         Builder dialogBuider = new AlertDialog.Builder(DrawGestureTest.this);  
  126.         dialogBuider.setView(dialogView);  
  127.         //绑定对话框的确认按钮监听事件  
  128.         dialogBuider.setPositiveButton(  
  129.                 "保存"new OnClickListener()  
  130.                 {  
  131.   
  132.                     @Override  
  133.                     public void onClick(DialogInterface dialog, int which)  
  134.                     {  
  135.                         // 添加手势  
  136.                         sStore.addGesture(name, gesture);  
  137.                         // 保存添加的手势  
  138.                         sStore.save();      
  139.                     }  
  140.                 });  
  141.         //绑定对话框的取消按钮监听事件  
  142.         dialogBuider.setNegativeButton("取消"new OnClickListener()  
  143.                 {  
  144.   
  145.                     @Override  
  146.                     public void onClick(DialogInterface dialog, int which)  
  147.                     {  
  148.                         // TODO Auto-generated method stub  
  149.                                                        
  150.                     }  
  151.                 });  
  152.         //显示对话框  
  153.         dialogBuider.show();  
  154.     }  
  155.       
  156.     private int gestureColor(int resId)  
  157.     {  
  158.         return getResources().getColor(resId);  
  159.     }  
  160.       
  161.     private void showMessage(String s)  
  162.     {  
  163.         Toast.makeText(this, s, Toast.LENGTH_SHORT).show();  
  164.     }  
  165.           
  166.     @Override  
  167.     protected void onDestroy()   
  168.     {  
  169.         // TODO Auto-generated method stub  
  170.         super.onDestroy();  
  171.         //移除绑定的监听器  
  172.         mDrawGestureView.removeOnGesturePerformedListener(this);  
  173.     }  
  174.   
  175. }  
         main.xml的代码如下:

[html]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:orientation="vertical" >  
  6.   
  7.    <android.gesture.GestureOverlayView   
  8.        android:id="@+id/gesture"  
  9.        android:layout_width="fill_parent"  
  10.        android:layout_height="fill_parent"  
  11.        >      
  12.    </android.gesture.GestureOverlayView>  
  13.   
  14. </LinearLayout>  

         对话框对应的布局文件show_gesture.xml代码如下:

[html]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:orientation="vertical" >  
  6.       
  7.     <LinearLayout   
  8.         android:orientation="horizontal"  
  9.         android:layout_width="fill_parent"  
  10.         android:layout_height="wrap_content">  
  11.           
  12.         <TextView   
  13.             android:layout_width="wrap_content"  
  14.             android:layout_height="wrap_content"  
  15.             android:layout_marginRight="8dip"  
  16.             android:text="@string/set_gesture_name"/>  
  17.         <EditText   
  18.             android:id="@+id/name"  
  19.             android:layout_width="wrap_content"  
  20.             android:layout_height="wrap_content"/>  
  21.             
  22.     </LinearLayout>  
  23.   
  24.     <ImageView   
  25.         android:id="@+id/show"  
  26.         android:layout_gravity="center"  
  27.         android:layout_width="128dp"  
  28.         android:layout_height="128dp"  
  29.         android:layout_marginTop="10dp"/>  
  30. </LinearLayout>  

        通过上面Demo代码的实现,可以知道手势库创建保存手势的文件有以下四种方式:

          1. GestureLibraries.fromFile(String path): GestureLibraries静态方法,参数path为文件的指定存放路径。返回的是FileGestureLibrary类型的对象;

          2. GestureLibraries.fromPrivateFile(Context context, String name):GestureLibraries静态方法,参数path为文件的指定存放路径;返回的是FileGestureLibrary类型的对象;

          3. GestureLibraries.fromFile(File path):GestureLibraries的静态方法,参数path为File对象,返回的是FileGestureLibrary类型的对象;

          4. GestureLibraries.romRawResource(Contextcontext, int resourceId):GestureLibraries的静态方法, 参数resourceId为文件所在的资源id,返回的是ResourceGestureLibrary类型的对象;

    二. 手势保存和加载源码浅析

         在分析源码之前,我们先来看看有关涉及到手势保存和加载源码类之间的关系,如下图:


    通过上图可以知道:

     1. GestureLibrary为抽象类,ResourceGestureLibrary和FileGestureLibrary均继承它;

     2. ResourceGestureLibrary和FileGestureLibrary又作为GestureLibraries的内部类;

     3. GestureLibrary类中的save和load方法为抽象方法,它们的具体实现在子类ResourceGestureLibrary和FileGestureLibrary中;

      通过上文Demo的介绍,我们知道,要想保持用户绘制的手势,前提是需要通过创建相应的手势库来实现;如下步骤:sStore = GestureLibraries.fromFile(mStoreFile)-->sStore.addGesture(name, gesture)-->sStore.save()

       接下来根据上面的保存手势步骤来分析源码中的实现:

        Step1: GestureLibraries.fromFile(mStoreFile):

[java]  view plain  copy
  1. public final class GestureLibraries {  
  2. ...  
  3. public static GestureLibrary fromFile(File path) {  
  4.         return new FileGestureLibrary(path);  
  5.     }  
  6. ...  
  7. }  
   该方法返回的是FileGestureLibrary对象,FileGestureLibrary为GestureLibraries内部类;

    FileGestureLibrary类的代码如下:

[java]  view plain  copy
  1. public final class GestureLibraries {  
  2. ...  
  3. private static class FileGestureLibrary extends GestureLibrary {  
  4.         private final File mPath;  
  5.   
  6.         public FileGestureLibrary(File path) {  
  7.             mPath = path;  
  8.         }  
  9.   
  10.         //手势库只读  
  11.         @Override  
  12.         public boolean isReadOnly() {  
  13.             return !mPath.canWrite();  
  14.         }  
  15.   
  16.         public boolean save() {  
  17.             if (!mStore.hasChanged()) return true;  
  18.   
  19.             final File file = mPath;  
  20.   
  21.             final File parentFile = file.getParentFile();  
  22.             if (!parentFile.exists()) {  
  23.                 if (!parentFile.mkdirs()) {  
  24.                     return false;  
  25.                 }  
  26.             }  
  27.   
  28.             boolean result = false;  
  29.             try {  
  30.                 //noinspection ResultOfMethodCallIgnored  
  31.                 file.createNewFile();  
  32.                 //通过文件输出流保存手势的相关信息  
  33.                 mStore.save(new FileOutputStream(file), true);  
  34.                 result = true;  
  35.             } catch (FileNotFoundException e) {  
  36.                 Log.d(LOG_TAG, "Could not save the gesture library in " + mPath, e);  
  37.             } catch (IOException e) {  
  38.                 Log.d(LOG_TAG, "Could not save the gesture library in " + mPath, e);  
  39.             }  
  40.   
  41.             return result;  
  42.         }  
  43.   
  44.         public boolean load() {  
  45.             boolean result = false;  
  46.             final File file = mPath;  
  47.             if (file.exists() && file.canRead()) {  
  48.                 try {  
  49.                     //通过文件输出流加载之前保存的手势信息  
  50.                     mStore.load(new FileInputStream(file), true);  
  51.                     result = true;  
  52.                 } catch (FileNotFoundException e) {  
  53.                     Log.d(LOG_TAG, "Could not load the gesture library from " + mPath, e);  
  54.                 } catch (IOException e) {  
  55.                     Log.d(LOG_TAG, "Could not load the gesture library from " + mPath, e);  
  56.                 }  
  57.             }  
  58.   
  59.             return result;  
  60.         }  
  61.     }  
  62. ...  
  63. }  

   FileGestureLibrary类中的代码实现简介:

   1).  isReadOnly():该方法实现判断所创建的保存手势文件是否可读;

    2). save():实现保存手势的重要方法,在该方法中,实例化所创建文件的输出流,然后根据输出流调用GestureStore的save(OutputStream stream, Boolean closeStream)方法,然后将GestureStore得到的有关手势的信息通过输出流写入文件;

    3). Load():该方法实现加载当前已保存手势的文件,当我们需要取出已保存的手势和当前手势进行相似度匹配时,就需要通过手势库加载之前保存的手势文件;

  Step2: FileGestureLibrary类没有addGesture方法,所以sStore.addGesture(name, gesture)方法的实现应该在它的父类GestureLibrary中,代码如下:

[java]  view plain  copy
  1. public abstract class GestureLibrary {  
  2. ...  
  3.     protected final GestureStore mStore;  
  4. ...  
  5.     //调用执行该方法后,接着要调用执行save(),否则添加不成功  
  6.     public void addGesture(String entryName, Gesture gesture) {  
  7.         mStore.addGesture(entryName, gesture);  
  8.     }  
  9. ...  
  10. }  
    Step3: 接着调用到GestureStore中的addGesture方法,如下:

[java]  view plain  copy
  1. public class GestureStore {  
  2. ...  
  3.     private final HashMap<String, ArrayList<Gesture>> mNamedGestures =  
  4.             new HashMap<String, ArrayList<Gesture>>();  
  5.   
  6.     private Learner mClassifier;  
  7. ...  
  8.     /** 
  9.      * Add a gesture for the entry 
  10.      *  
  11.      * @param entryName entry name 
  12.      * @param gesture 
  13.      */  
  14.       
  15.     //手势保存在一个ArrayList集合里,ArrayList又以entryName为key值保存在HashMap集合里  
  16.     public void addGesture(String entryName, Gesture gesture) {  
  17.         if (entryName == null || entryName.length() == 0) {  
  18.             return;  
  19.         }  
  20.         ArrayList<Gesture> gestures = mNamedGestures.get(entryName);  
  21.         if (gestures == null) {  
  22.             gestures = new ArrayList<Gesture>();  
  23.             mNamedGestures.put(entryName, gestures);  
  24.         }  
  25.         gestures.add(gesture);  
  26.         //通过gesture得到的Instance对象,存放到mClassifier对象的成员mInstances集合中  
  27.         mClassifier.addInstance(  
  28.                 Instance.createInstance(mSequenceType, mOrientationStyle, gesture, entryName));  
  29.         mChanged = true;  
  30.     }  
  31. ...  
  32. }  
     GestureStore的addGesture方法中代码实现如下:

       1). 实现将用户绘制的手势存放到mNamedGestures(HashMap类型)中;

       2). 通过用户绘制的gesture得到的Instance类型的对象(Instance.createInstance);

       3). 将Instance类型的对象存放到mClassifier对象(Learner类型)的成员mInstances集合中;
   Step4: 执行完sStore.addGesture(name, gesture)添加手势后,我们接着执行sStore.save()保存所添加的手势相关的信息。sStore.save()方法的实现在FileGestureLibrary中,代码如下:

[java]  view plain  copy
  1. public final class GestureLibraries {  
  2. ...  
  3.     private static class FileGestureLibrary extends GestureLibrary {  
  4.         private final File mPath;  
  5.     ...  
  6.         public boolean save() {  
  7.             if (!mStore.hasChanged()) return true;  
  8.   
  9.             final File file = mPath;  
  10.   
  11.             final File parentFile = file.getParentFile();  
  12.             if (!parentFile.exists()) {  
  13.                 if (!parentFile.mkdirs()) {  
  14.                     return false;  
  15.                 }  
  16.             }  
  17.   
  18.             boolean result = false;  
  19.             try {  
  20.                 //noinspection ResultOfMethodCallIgnored  
  21.                 file.createNewFile();  
  22.                 //通过文件输出流保存手势的相关信息  
  23.                 mStore.save(new FileOutputStream(file), true);  
  24.                 result = true;  
  25.             } catch (FileNotFoundException e) {  
  26.                 Log.d(LOG_TAG, "Could not save the gesture library in " + mPath, e);  
  27.             } catch (IOException e) {  
  28.                 Log.d(LOG_TAG, "Could not save the gesture library in " + mPath, e);  
  29.             }  
  30.   
  31.             return result;  
  32.         }  
  33.     ...  
  34.     }  
  35. ...  
  36. }  

      FileGestureLibrary的save方法中的代码实现:
      1). 通过传进来的File对象创建其对应的输出流(new FileOutputStream(file))
      2). 通过创建的输出流执行调用GestureStore的save方法(mStore.save(new FileOutputStream(file), true))
   Step5: GestureStore的save方法代码实现如下:

[java]  view plain  copy
  1. public class GestureStore {  
  2. ...  
  3.     private static final short FILE_FORMAT_VERSION = 1;  
  4.     private final HashMap<String, ArrayList<Gesture>> mNamedGestures =  
  5.             new HashMap<String, ArrayList<Gesture>>();  
  6. ...  
  7.     public void save(OutputStream stream, boolean closeStream) throws IOException {  
  8.         DataOutputStream out = null;  
  9.   
  10.         try {  
  11.             long start;  
  12.             if (PROFILE_LOADING_SAVING) {  
  13.                 start = SystemClock.elapsedRealtime();  
  14.             }  
  15.   
  16.             final HashMap<String, ArrayList<Gesture>> maps = mNamedGestures;  
  17.   
  18.             out = new DataOutputStream((stream instanceof BufferedOutputStream) ? stream :  
  19.                     new BufferedOutputStream(stream, GestureConstants.IO_BUFFER_SIZE));  
  20.             // Write version number  
  21.             //往文件中写入FILE_FORMAT_VERSION  
  22.             out.writeShort(FILE_FORMAT_VERSION);  
  23.             // Write number of entries  
  24.             //将ArrayList<Gesture>在mNamedGestures集合中的个数通过输出流写入文件  
  25.             out.writeInt(maps.size());  
  26.   
  27.             //遍历maps  
  28.             for (Map.Entry<String, ArrayList<Gesture>> entry : maps.entrySet()) {  
  29.                 final String key = entry.getKey();  
  30.                 final ArrayList<Gesture> examples = entry.getValue();  
  31.                 final int count = examples.size();  
  32.   
  33.                 // Write entry name  
  34.                 out.writeUTF(key); //将key值通过输出流写入文件  
  35.                 // Write number of examples for this entry  
  36.                 out.writeInt(count); //将rrayList<Gesture>集合中Gesture的个数通过输出流写入文件  
  37.   
  38.                 //遍历ArrayList<Gesture>中的Gesture且调用Gesture的serialize函数进行序列化写入相关信息  
  39.                 for (int i = 0; i < count; i++) {  
  40.                     examples.get(i).serialize(out);  
  41.                 }  
  42.             }  
  43.   
  44.             out.flush();  
  45.   
  46.             if (PROFILE_LOADING_SAVING) {  
  47.                 long end = SystemClock.elapsedRealtime();  
  48.                 Log.d(LOG_TAG, "Saving gestures library = " + (end - start) + " ms");  
  49.             }  
  50.   
  51.             mChanged = false;  
  52.         } finally {  
  53.             if (closeStream) GestureUtils.closeStream(out);  
  54.         }  
  55.     }  
  56. ...  
  57. }  

     GestureStore的save方法中代码实现如下:

      1). 将执行Step3中得到的mNamedGestures赋值给maps;

      2). 通过传进来的输出流创建对应的DataOutputStream类型对象out;

      3). 将FILE_FORMAT_VERSION和maps.size()写入out中;

      4). 遍历maps,将遍历出的每个ArrayList<Gesture>在maps中的key值和自身存放Gesture的个数count值,分别写入out中;

      5). 遍历ArrayList<Gesture>中的Gesture,然后将out作为实参调用执行Gesture的serialize方法;

     Step6:继续跟踪到 Gesture的serialize方法,代码如下:

[java]  view plain  copy
  1. public class Gesture implements Parcelable {  
  2. ...  
  3.     private long mGestureID;  
  4.     private final ArrayList<GestureStroke> mStrokes = new ArrayList<GestureStroke>();  
  5. ...  
  6.     public Gesture() {  
  7.         mGestureID = GESTURE_ID_BASE + sGestureCount.incrementAndGet();  
  8.     }  
  9. ...  
  10.     void serialize(DataOutputStream out) throws IOException {  
  11.         final ArrayList<GestureStroke> strokes = mStrokes;  
  12.         final int count = strokes.size();  
  13.   
  14.         // Write gesture ID  
  15.         out.writeLong(mGestureID); //写入GestureID  
  16.         // Write number of strokes   
  17.         out.writeInt(count);  //写入ArrayList<GestureStroke>集合中GestureStroke的个数  
  18.   
  19.         /*遍历ArrayList<GestureStroke>集合, 
  20.          * 同时调用GestureStroke的serialize函数向输出流中进行序列化写入相关信息 
  21.          */  
  22.         for (int i = 0; i < count; i++) {  
  23.             strokes.get(i).serialize(out);  
  24.         }  
  25.     }  
  26. ...  
  27. }  
      Gesture的serialize方法中代码实现如下:

      1). 将Gesture对应的mStrokes赋值给strokes;

      2). 将Gesture的mGestureID和GestureStroke在strokes中的个数count分别写入DataOutputStream类型的对象out;

      3). 遍历strokes中的GestureStroke,然后将out作为实参调用执行GestureStroke的serialize方法;

   Step7: 继续跟踪到 GestureStroke的serialize方法,代码如下:

[java]  view plain  copy
  1. public class GestureStroke {  
  2. ...  
  3.     public final float[] points; //保存组成手势行程的多数个点的x,y坐标值   
  4.     private final long[] timestamps;//保存组成手势行程的多数个点的时间戳  
  5. ...  
  6.     void serialize(DataOutputStream out) throws IOException {  
  7.         //points、timestamps分别由ArrayList<GesturePoint>中拆分得到  
  8.         final float[] pts = points;  
  9.         final long[] times = timestamps;  
  10.         final int count = points.length;  
  11.   
  12.         // Write number of points  
  13.         out.writeInt(count / 2);  
  14.   
  15.         for (int i = 0; i < count; i += 2) {  
  16.             // Write X  
  17.             out.writeFloat(pts[i]); //写入x轴对应的坐标值  
  18.             // Write Y  
  19.             out.writeFloat(pts[i + 1]); //写入y轴对应的坐标值  
  20.             // Write timestamp  
  21.             out.writeLong(times[i / 2]); //写入时间戳  
  22.         }  
  23.     }  
  24. ...  
  25. }  
     GestureStroke的serialize方法中代码实现如下:

     1). 将GestureStroke中对应的点数组points和时间戳数组timestamps分别赋值给数组pts和times

     2). 将GestureStroke中组成手势的点数count / 2写入DataOutputStream类型的对象out;(pts数组中每两个元素保存一个点对应的x,y值,所以,总点数为数组所有元素个数count除以2)

     3). 遍历数组pts,将每个点对应的x,y轴坐标值和时间戳分别写入out;

  关于手势保存源码的浅析就到此结束了,至于手势的加载sStore.load(),其实和手势的保存就是一个逆过程(一个是写入信息,一个读取加载信息)。如果熟悉了手势的保存机制,那么手势的加载机制就不言而喻了!

0
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值