开源夏令营第八周--添加SettingsActivity和手势密码

来源:互联网 发布:开设大数据专业的学校 编辑:程序博客网 时间:2024/06/06 17:44

不知不觉已经完成了最后一个功能,其实这个功能对我这个小白来说还是有些棘手的。期间遇到了很多困难,但经过不懈的努力,大量的查找资料,以及林老师的技术支持,最后的结果还是可喜的。


最后的任务是要给seadrod加个软件锁,但是由于安全性以及用户体验,我决定使用手势锁。因为安卓的开源性,手势锁的核心代码有源码的参考,网上的资料很齐全并且很相似,反而没有占用大量的时间。相反,我在设置界面(SettingsActivity)大费周章。


一、数据的保存与读取

安卓专门为settings提供了一种存储方式——SharedPreferences。这样可以将一些需要全局使用的变量放入XML文件中,这样既能保证数据的安全性,同时又可以在整个程序中使用。有三种获取系统中保存的持久化数据的方式:


1. public SharedPreferences getPreferences (int mode)
    通过Activity对象获取,获取的是本Activity私有的Preference,保存在系统中的xml形式的文件的名称为这个Activity的名字,因此一个Activity只能有一个,属于这个Activity。

2. public SharedPreferences getSharedPreferences (String name, int mode)
    因为Activity继承了ContextWrapper,因此也是通过Activity对象获取,但是属于整个应用程序,可以有多个,以第一参数的name为文件名保存在系统中。

3. public static SharedPreferences getDefaultSharedPreferences (Context context)
    PreferenceManager的静态函数,保存PreferenceActivity中的设置,属于整个应用程序,但是只有一个,Android会根据包名和PreferenceActivity的布局文件来起一个名字保存。

 通过以上方式取得SharedPreferences后就可以对数据进行读取或者保存了。


保存的方法:

        String STORE_NAME = "Settings";        SharedPreferences settings = getSharedPreferences(STORE_NAME, MODE_PRIVATE);        SharedPreferences.Editor editor = settings.edit();        editor.putInt("sourceType", 0);        editor.commit();


获得SharedPreferences,如果需要进行保存等修改操作,首先得通过其edit()方法获得SharedPreferences.Editor,然后就可以通过putInt、putString等方法以键值对(key-value)的方式保存数据,或者remove移除某个键(key),及调用clear方法删除所有内容。最后需要调用commit方法是使修改生效。


读取的方法:

        SharedPreferences settings = getSharedPreferences(STORE_NAME, MODE_PRIVATE);        int source = settings.getInt("sorceType", 1);

二、界面的设计

前几日我在网上搜索Preferences相关资料时,大多数的前辈使用PreferencesActivity以及它其中的Preferences控件来制作设置界面。但当我extends PreferenceActivity时Eclipse一条删除线划掉了,说明PreferenceActivity已经被谷歌舍弃。幸运的是谷歌用PreferenceFragment来取代PreferenceActivity。他们的区别只有在最开始的绘制界面,Preferences控件基本上没有改变,在Fragment里也可以使用getActivity()来调用Activity的控件。


除了要新建一个类extends PreferenceFragment外,还要新建一个Activity来装载这个Fragment。装载办法就是在Activity的onCreat()函数中运行如下代码:

setContentView(R.layout.settings_activity_layout);        FragmentManager fragmentManager = getFragmentManager();        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();        fragmentTransaction.add(R.id.settings_fragment_container, new SettingsPreferenceFragment());        fragmentTransaction.commit();

在绘制界面上Preference与其他不同的在于,他的界面并不能放在res/layout里,要放在res/xml文件夹下,并通过R文件来绘制出界面,具体绘制函数也有所不同:

addPreferencesFromResource(R.xml.settings);


因为手势密码需要一个开关以及给用户设置的界面。原本打算使用switch作为打开和关闭手势密码的控件,但是由于switch要求的版本很高,不得不改为checkbox。
控制Preference控件的函数有三个:Preference.OnPreferenceChangeListener、Preference.OnPreferenceClickListener以及onPreferenceTreeClick。

它的触发规则如下:
      1 先调用onPreferenceClick()方法,如果该方法返回true,则不再调用onPreferenceTreeClick方法 ;
       如果onPreferenceClick方法返回false,则继续调用onPreferenceTreeClick方法。
      2 onPreferenceChange的方法独立与其他两种方法的运行,如果返回true则接受控件值的改变,返回false则不接受。也就是说,它总是会运行。


继续回到我们的设置界面。我们要达到的目标是:当Checkbox不为对勾时,用户点击,触发手势密码的设置界面(即跳转Activity),设置界面结束时,会有两种状态,用户设置成功或是设置失败。若是设置成功,Checkbox变为对勾状,否则不改变。当checkbox是对勾状时,用户点击,对勾取消,并且清除SharePreference中的密码。

根据需求来看,我们必定要在onPreferenceClick中加入startActivityForResult(); 并且需要得到用户是否将手势密码设置成功(setupSuccess),于是我们要重写onActivityResult:

public void onActivityResult(int requestCode, int resultCode, Intent data) {        switch (requestCode) {        case Gesture_Lock_REQUEST:            if (resultCode == getActivity().RESULT_OK) {                setupSuccess = data.getBooleanExtra("setupSuccess", true);                SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getActivity());                SharedPreferences.Editor editor = settings.edit();                                if (setupSuccess == true) {                    showToast(R.string.setup_gesture_lock_success);                    editor.putBoolean(BrowserActivity.GESTURE_LOCK_SWITCH_KEY, true);                    gestureLockSwitch.setChecked(true);                } else {                    editor.putBoolean(BrowserActivity.GESTURE_LOCK_SWITCH_KEY, false);                    gestureLockSwitch.setChecked(false);                }                    editor.commit();            }        }    }


这时候难点便出现:因为JAVA是面向对象的语言,所以必须将onPreferenceClick执行完毕后才能新开个Activity。而控制checkbox的状态的是onPreferenceChange,同时它是UI控件,我们不能在onPreferenceChange运行一半时将它暂停,等待用户设置手势密码完毕,再继续执行后面的语句。这便是我遇到的最大的难题。


网上对于checkbox的控制基本上都是使用onPreferenceChange,因为它可塑性很高,很明显它无法满足我们的要求。通过请教林老师,我们可以用另一种办法绕开这种机制:首先将onPreferenceChange设为始终返回false,屏蔽它,然后Checkbox.setChecked()来手动控制checkbox的值,这样便可以达到我们的要求。

部分代码如下:

if (setupSuccess == true) {                    showToast(R.string.setup_gesture_lock_success);                    editor.putBoolean(BrowserActivity.GESTURE_LOCK_SWITCH_KEY, true);                    gestureLockSwitch.setChecked(true);                } else {                    editor.putBoolean(BrowserActivity.GESTURE_LOCK_SWITCH_KEY, false);                    gestureLockSwitch.setChecked(false);                }

三、手势密码

正如上文所说,手势密码的核心代码在安卓源程序中可以参考。手势密码锁的Activity原理很简单,就是根据手势密码的核心代码绘制出手势密码(需要引用核心代码中的一些函数和接口),作为Activity弹出,当用户绘制完成后进行比对,若一致,则finish(),若不一致则弹出提示。具体代码这里并不多述,可去我的CODE中查看。


对于手势密码的设置

界面上除了绘制密码的区域,还需要增加两个按钮:取消\重试按钮 和 继续\完成按钮。 大致思路是,用户第一次绘制完成时可以选择取消,也可以继续第二次绘制确认。只有当两次绘制的图形一样时才算设置成功,在第二次绘制时也可选择重试,重新绘制第一次的图案。

因为这个思路我们大致分为四步:

第一步为等待用户设置手势图案,将界面绘制,并设置取消键和继续键,这时继续键不可用。

第二步为用户第一次绘制完成,继续键可用,用户可以选择取消或是继续。

第三步为等待用户设置第二次的手势图案,设置重试和完成键,这时完成键不可用。

第四步为用户第二次绘制完成,两次设置的图案相同时完成按钮变为可用,点击后将密码转为字串保存。


具体实现代码很长,全贴出来并不方便,可进入我的CODE查看


至于如何在程序开始时弹出手势锁,其实只是在程序主界面生成前弹出一个Activity覆盖在最前,手势密码输入正确finish()便可。代码如下(要放在MainActivity的onCreate函数中):

SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);        String lockPattenString = settings.getString(LOCK_KEY, null);        if (lockPattenString != null) {            Intent intent = new Intent(this, GestureLockActivity.class);            startActivity(intent);        }

至此,我们的任务就全部完成了!

0 0
原创粉丝点击