-
Python 重新加载模块
2017-07-20 19:14:29在进行模块化编程时,经常会遇到这样一种场景: > 编写了一个 Python 模块,并用 ...当对该模块进行更改后,即使重新导入,其中的任何改变都不会被识别,这使得模块调试变得非常困难。 那么,该如何解决这个问题?简述
在进行模块化编程时,经常会遇到这样一种场景:
编写了一个 Python 模块,并用
import my_module
的形式进行导入。当对该模块进行更改后,即使重新导入,其中的任何改变都不会被识别,这使得模块调试变得非常困难。那么,该如何解决这个问题?
| 版权声明:一去、二三里,未经博主允许不得转载。
模块仅被导入一次
出于效率原因(导入必须找到文件,将其编译成字节码,并且运行代码),Python shell 在每次会话中,只对每个模块导入一次。
例如,有一个名为
hello.py
的模块,包含以下代码:print('Hello, Python!')
如果多次导入,会出现什么效果?
>>> import hello Hello, Python! >>> >>> import hello >>> import hello
可以看到,代码只执行了一次。也就是说,模块仅被导入了一次。
重新加载模块
倘若,更改了已经在 Python shell 中导入的模块,然后重新导入该模块,Python 会认为“我已经导入了该模块,不需要再次读取该文件”,所以更改将无效。
要解决这个问题,有以下几种方式:
- 最简单、最有效的方法:重新启动 Python shell。但是,这也有缺点,特别是丢失了 Python shell 名称空间中存在的数据以及其他导入模块中的数据。
- 对于简单的情况,可以使用 Python 的
reload()
函数。在许多情况下,在编辑一个模块之后就足够了。 - 对于更复杂的情况,重新加载被编辑的模块也需要重新加载其依赖/导入的模块(因为它们必须作为被编辑模块初始化的一部分进行初始化),所以 IPython 的 autoreload 扩展很有用。
PS: 下面主要介绍第 2 种方式 -
reload()
,其他方式自行尝试。reload()
是 Python 提供的一种简洁的方式,在不同的 Python 版本中有不同的表现形式:- 在 Python 2.x 中,reload() 是内置函数。
- 在 Python 3.0 - 3.3 中,可以使用 imp.reload(module)。
- 在 Python 3.4 中,imp 已经被废弃,取而代之的是 importlib。
>>> import importlib >>> import hello Hello, Python! # 修改前的内容 >>> >>> importlib.reload(hello) I am coming... # 修改后的内容 <module 'hello' from '/home/wang/Projects/hello.py'>
-
设置指纹识别模块分析
2017-09-14 11:41:36设置指纹识别模块分析 一, 指纹项的加载 首先我们从指纹项的布局加载开始分析,从手机设置下边直观的可以发现,指纹项是放在二级菜单安全菜单里边的,下面我们就从代码里边分析一下,指纹项是如何被加载进来的。...设置指纹识别模块分析
一, 指纹项的加载
首先我们从指纹项的布局加载开始分析,从手机设置下边直观的可以发现,指纹项是放在二级菜单安全菜单里边的,下面我们就从代码里边分析一下,指纹项是如何被加载进来的。
首先我们应该从SecuritySettings.java的加载开始分析,在该类起来之后,在它的
@Override
public void onResume() {
super.onResume();
// Make sure wereload the preference hierarchy since some of these settings
// depend on others...
createPreferenceHierarchy();//省略代码
}我们可以看到调用了createPreferenceHierarchy();方法,下面看看这个方法:
private PreferenceScreen createPreferenceHierarchy() { PreferenceScreen root = getPreferenceScreen(); if (root != null) { root.removeAll(); } addPreferencesFromResource(R.xml.security_settings);//通过布局文件加载一些基础的布局 root = getPreferenceScreen(); //代码省略
if (mProfileChallengeUserId != UserHandle.USER_NULL && mLockPatternUtils.isSeparateProfileChallengeAllowed(mProfileChallengeUserId)) { addPreferencesFromResource(R.xml.security_settings_profile); addPreferencesFromResource(R.xml.security_settings_unification); final int profileResid = getResIdForLockUnlockScreen( getActivity(), mLockPatternUtils, mManagedPasswordProvider, mProfileChallengeUserId); addPreferencesFromResource(profileResid); maybeAddFingerprintPreference(root, mProfileChallengeUserId);
//从这里看到了我们想要的加载指纹的布局,下边看看这个方法内容:
//代码省略 }
private void maybeAddFingerprintPreference(PreferenceGroup securityCategory, int userId) { Preference fingerprintPreference = FingerprintSettings.getFingerprintPreferenceForUser( securityCategory.getContext(), userId); if (fingerprintPreference != null) { securityCategory.addPreference(fingerprintPreference); } }
这个方法看起来比较简单,首先是获取到这个fingerprintPreference,然后直接加载到securityCategory,从而让指纹项显示出来。但是点击事件却是在下边这个方法的,该方法getFingerprintPreferenceForUser()是在FingerprintSettings的一个全局方法,如下:
public static Preference getFingerprintPreferenceForUser(Context context, final int userId) { FingerprintManager fpm = (FingerprintManager) context.getSystemService( Context.FINGERPRINT_SERVICE); if (fpm == null || !fpm.isHardwareDetected()) { Log.v(TAG, "No fingerprint hardware detected!!"); return null; } Preference fingerprintPreference = new Preference(context); fingerprintPreference.setKey(KEY_FINGERPRINT_SETTINGS);//设置点击的键 fingerprintPreference.setTitle(R.string.security_settings_fingerprint_preference_title); final List<Fingerprint> items = fpm.getEnrolledFingerprints(userId); final int fingerprintCount = items != null ? items.size() : 0; final String clazz;
//这个直接决定点击指纹项要启动的是哪个界面 if (fingerprintCount > 0) { fingerprintPreference.setSummary(context.getResources().getQuantityString( R.plurals.security_settings_fingerprint_preference_summary, fingerprintCount, fingerprintCount)); clazz = FingerprintSettings.class.getName(); } else { fingerprintPreference.setSummary( R.string.security_settings_fingerprint_preference_summary_none); //slt yangxinzhao modified for lenovo UI clazz = FingerprintEnrollIntroduction.class.getName(); }
//这里是最关键的地方,为指纹项设置点击监听, fingerprintPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { final Context context = preference.getContext(); final UserManager userManager = UserManager.get(context); if (Utils.startQuietModeDialogIfNecessary(context, userManager, userId)) { return false; } Intent intent = new Intent(); intent.setClassName("com.android.settings", clazz); intent.putExtra(Intent.EXTRA_USER_ID, userId); context.startActivity(intent); return true; } }); return fingerprintPreference; }
从这个方法中可以看出主要是做了一些指纹界面的初始化工作。其中有个比较关键的判断条件就是fingerprintCount,如果指纹的个数不为0,那么就点击菜单项打开的是指纹注册引导界面,即FingerprintEnrollIntroduction,否则打开的就是指纹项界面,即FingerprintSettings。到此,整个指纹界面的加载流程就梳理完了。
二, 指纹界面处理逻辑
1,首先来看一下指纹界面(FingerprintSettings.java),该类继承SubSettings.java
而此类又是继承自SettingsActivity.java,首先我们从OnCreate()函数开始看:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); CharSequence msg = getText(R.string.security_settings_fingerprint_preference_title); setTitle(msg); }
可以看到这个函数里边仅仅只是设置了这个activity的title。下边再看一个方法:
@Override public Intent getIntent() { Intent modIntent = new Intent(super.getIntent()); modIntent.putExtra(EXTRA_SHOW_FRAGMENT,
FingerprintSettingsFragment.class.getName()); return modIntent; }
从此方法可以看到这个activity是绑定的FingerprintSettingsFragment,所以我们接下来只需要分析这个fragment就可以了。
2,分析此fragment还是先从onCreate()函数开始分析:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { mToken = savedInstanceState.getByteArray( ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN); mLaunchedConfirm = savedInstanceState.getBoolean( KEY_LAUNCHED_CONFIRM, false); } mUserId = getActivity().getIntent().getIntExtra( Intent.EXTRA_USER_ID, UserHandle.myUserId()); Activity activity = getActivity(); mFingerprintManager = (FingerprintManager) activity.getSystemService( Context.FINGERPRINT_SERVICE); // Need to authenticate a session token if none if (mToken == null && mLaunchedConfirm == false) { mLaunchedConfirm = true;//当进入该界面,就把标志位置为true launchChooseOrConfirmLock();//启动密码确认界面 } }
从这个方法可以看到这里其实并没有做什么,只是进行了一些相关数据的初始化。但有一点需要注意,mLaunchedConfirm这变量表示是否需要进行密码确认,如果为false就需要进行密码确认,从而启动对应的密码确认界面,具体的方法如下:
private void launchChooseOrConfirmLock() { Intent intent = new Intent(); long challenge = mFingerprintManager.preEnroll(); ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(getActivity(), this); if (!helper.launchConfirmationActivity(CONFIRM_REQUEST, getString(R.string.security_settings_fingerprint_preference_title), null, null, challenge, mUserId)) { intent.setClassName("com.android.settings", ChooseLockGeneric.class.getName()); intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true); intent.putExtra(Intent.EXTRA_USER_ID, mUserId); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge); intent.putExtra(Intent.EXTRA_USER_ID, mUserId); startActivityForResult(intent, CHOOSE_LOCK_GENERIC_REQUEST); } }
接下来我们就看看这个fragment的onResume()方法:
@Override public void onResume() { super.onResume(); // Make sure we reload the preference hierarchy since fingerprints may be added, // deleted or renamed. updatePreferences(); }
从这里可以看到整个指纹界面就是从这里开始创建的,具体代码如下:
private void updatePreferences() { createPreferenceHierarchy();//进行界面的创建 retryFingerprint();//认证指纹,也就是在这个activity起来之后就可以直接认证指纹了 }
下面我们具体看看指纹界面是如何创建的,指纹界面包含两个部分,一部分是最下边的指纹使用介绍,这部分仅仅是一个textview,还有一部分就是每个指纹选项和添加指纹选项,我们稍后介绍,先来看看指纹介绍是如何添加的,代码如下:
@Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); TextView v = (TextView) LayoutInflater.from(view.getContext()).inflate( R.layout.fingerprint_settings_footer, null); EnforcedAdmin admin = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled( getActivity(), DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT, mUserId); v.setText(getText(admin != null ? R.string.security_settings_fingerprint_enroll_disclaimer_lockscreen_disabled : R.string.security_settings_fingerprint_enroll_disclaimer)); /*end of slt yangxinzhao modified for lenovo UI */ setFooterView(v); }
这部分代码很简单,仅仅是在onViewCreated()方法里边添加一个布局文件fingerprint_settings_footer.xml,这个布局文件仅仅是一个LinkTextView,仅作为显示文字之用,我们主要看看第二部分的指纹选项和添加指纹选项是如何加载的,代码如下:
private PreferenceScreen createPreferenceHierarchy() { PreferenceScreen root = getPreferenceScreen(); if (root != null) { root.removeAll(); } addPreferencesFromResource(R.xml.security_settings_fingerprint);//加载基础布局,实际上是一个空布局 root = getPreferenceScreen(); addFingerprintItemPreferences(root);//添加指纹条目,最多能够添加五个指纹 setPreferenceScreen(root); return root; }
我们从security_settings_fingerprint.xml可以看到这是一个空的布局文件,里边的选项都是通过动态加载进去的,具体代码可以看方法addFingerprintItemPreferences(root),
private void addFingerprintItemPreferences(PreferenceGroup root) { root.removeAll(); final List<Fingerprint> items = mFingerprintManager.getEnrolledFingerprints(mUserId); final int fingerprintCount = items.size();
//通过for循环进行指纹条目的添加,同时设置各个属性已经点击监听 for (int i = 0; i < fingerprintCount; i++) { final Fingerprint item = items.get(i); FingerprintPreference pref = new FingerprintPreference(root.getContext()); pref.setKey(genKey(item.getFingerId())); pref.setTitle(item.getName()); pref.setFingerprint(item); pref.setPersistent(false); pref.setIcon(R.drawable.ic_fingerprint_24dp); root.addPreference(pref); pref.setOnPreferenceChangeListener(this); /*slt yangxinzhao added for lenovo UI 20170118*/ pref.setIcon(R.drawable.ic_fingerprint_list_icon); /*end of added*/ }
//添加指纹选项,并且设置对应的属性以及点击监听 Preference addPreference = new Preference(root.getContext()); addPreference.setKey(KEY_FINGERPRINT_ADD); addPreference.setTitle(R.string.fingerprint_add_title); addPreference.setIcon(R.drawable.ic_add_24dp); root.addPreference(addPreference); addPreference.setOnPreferenceChangeListener(this); updateAddPreference(); }
这部分其实主要也是分为两部分进行添加的,第一部分就是指纹条目,通过final List<Fingerprint> items = mFingerprintManager.getEnrolledFingerprints(mUserId);
将所有的指纹条目读取出来,使用for循环进行创建的条目,每一个条目包含了指纹条目的键,指纹的id,对应的图标等属性,同时为每个条目设置点击监听,pref.setOnPreferenceChangeListener(this);
同时在这个里边也添加了添加指纹选项,到此,整个指纹界面的的布局已经添加完成了,后边这个界面还会进行冬天更新,比如添加和删除指纹的操作都会更新这个界面,后面继续分析。3,指纹的添加
我们前边说过为添加指纹选项设置了点击事件监听,我们看看这个点击事件:
@Override public boolean onPreferenceTreeClick(Preference pref) { final String key = pref.getKey(); if (KEY_FINGERPRINT_ADD.equals(key)) { Intent intent = new Intent(); intent.setClassName("com.android.settings", FingerprintEnrollEnrolling.class.getName()); intent.putExtra(Intent.EXTRA_USER_ID, mUserId); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken); startActivityForResult(intent, ADD_FINGERPRINT_REQUEST); } else if (pref instanceof FingerprintPreference) { FingerprintPreference fpref = (FingerprintPreference) pref; final Fingerprint fp =fpref.getFingerprint(); showRenameDeleteDialog(fp); return super.onPreferenceTreeClick(pref); } return true; }
通过不同的Key判断,处理对应的事件,当点击添加指纹选项时,执行了如下代码:
Intent intent = new Intent();
intent.setClassName("com.android.settings",
FingerprintEnrollEnrolling.class.getName());
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
startActivityForResult(intent, ADD_FINGERPRINT_REQUEST);
我们可以看到是启动了FingerprintEnrollEnrolling这个类进行指纹的添加,并且给返回了ADD_FINGERPRINT_REQUEST这个结果。这个指纹注册的过程我们暂时不作关注,只要知道注册完指纹之后返回了结果就可以了,有兴趣的可以继续研究一下指纹的注册。
当添加完指纹返回之后,重新回到onResume()方法,执行界面更新,这时候新添加的指纹就会出现在指纹界面。
4,指纹的删除
前边也说过,添加指纹条目的时候已经为指纹条目设置了点击事件监听,当点击指纹条目的时候直接调用了方法showRenameDeleteDialog(fp);参数为传入的指纹,具体方法如下:
private void showRenameDeleteDialog(final Fingerprint fp) { RenameDeleteDialog renameDeleteDialog = new RenameDeleteDialog(); Bundle args = new Bundle(); args.putParcelable("fingerprint", fp); renameDeleteDialog.setArguments(args); renameDeleteDialog.setTargetFragment(this, 0); renameDeleteDialog.show(getFragmentManager(), RenameDeleteDialog.class.getName()); }
从代码中可以看到该方法主要是新建了一个RenameDeleteDialog,并且将指纹这个数据传进去了,那么我们就看看这个dialog,因为这个dialog的代码比较多,我们只关注他的删除按钮和确定按钮事件,先看确定按钮事件,也就是为指纹进行改名操作,其代码如下:@Override public void onClick(DialogInterface dialog, int which) { final String newName = mDialogTextField.getText().toString().trim(); final CharSequence name = mFp.getName(); if (!newName.equals(name)) { if (DEBUG) { Log.v(TAG, "rename " + name + " to " + newName); } MetricsLogger.action(getContext(), MetricsEvent.ACTION_FINGERPRINT_RENAME, mFp.getFingerId()); FingerprintSettingsFragment parent = (FingerprintSettingsFragment) getTargetFragment(); parent.renameFingerPrint(mFp.getFingerId(), newName); } } dialog.dismiss(); }
从这个代码中可以看到在修改指纹名称的时候会首先判断新的名称是否与旧的名称一致,如果一致不作操作,否则才会进行改名,具体调用了renameFingerPrint(),参数为对应的指纹ID和对应的新名称,具体看一下这个方法:
private void renameFingerPrint(int fingerId, String newName) { mFingerprintManager.rename(fingerId, mUserId, newName); updatePreferences(); }
这里方法比较简单,首先直接调用了指纹管理服务的rename接口进行改名的操作,然后又调用的界面更新方法对界面进行更新,指纹改名还是比较简单的。下面我们着重看一下指纹的删除逻辑,先看一下具体代码:
public void onClick(DialogInterface dialog, int which) { onDeleteClick(dialog); }
点击事件很简单,仅仅调用了onDeleteClick()方法,接着往下追:
private void onDeleteClick(DialogInterface dialog) { if (DEBUG) Log.v(TAG, "Removing fpId=" + mFp.getFingerId()); MetricsLogger.action(getContext(), MetricsEvent.ACTION_FINGERPRINT_DELETE, mFp.getFingerId()); FingerprintSettingsFragment parent = (FingerprintSettingsFragment) getTargetFragment(); final boolean isProfileChallengeUser = Utils.isManagedProfile(UserManager.get(getContext()), parent.mUserId); if (parent.mFingerprintManager.getEnrolledFingerprints(parent.mUserId).size() > 1) { parent.deleteFingerPrint(mFp); } else { ConfirmLastDeleteDialog lastDeleteDialog = new ConfirmLastDeleteDialog(); Bundle args = new Bundle(); args.putParcelable("fingerprint", mFp); args.putBoolean("isProfileChallengeUser", isProfileChallengeUser); lastDeleteDialog.setArguments(args); lastDeleteDialog.setTargetFragment(getTargetFragment(), 0); lastDeleteDialog.show(getFragmentManager(), ConfirmLastDeleteDialog.class.getName()); } dialog.dismiss(); }
这个函数的代码稍微有点多,其实主要是分为两个逻辑,首先判断当前指纹是否大于一个,如果大于一个,则直接调用deleteFingerPrint()方法对指纹进行删除,否则新建一个确认删除最后一个指纹对话框,其实这个对话框主要是对删除最后一个指纹进行二次确认,其最终还是调用了deleteFingerPrint()这个方法,下面看一下删除指纹的方法:
private void deleteFingerPrint(Fingerprint fingerPrint) { mFingerprintManager.remove(fingerPrint, mUserId, mRemoveCallback); }
一看这个代码更简单了,仅仅调用指纹管理服务的remove接口对指纹进行删除,但是这里就有一个问题了,对指纹进行删除,但是如何对指纹界面进行更新的呢?按照正常的逻辑来说,在指纹删除之后应该立即对界面进行更新的,从表面是看没有界面更新的操作,实际上我们可以看到删除指纹的接口有一个非常重要的参数,mRemoveCallback,为什么说这个参数非常重要呢,因为这个参数与界面的更新有关系,这个参数其实是一个回调接口,既然是一个回调接口,那么必然有地方对这个回调接口进行了注册,我们继续追代码就会找到这个地方:
我们可以看一下这个删除指纹的接口,在FingerprintManager.java中:
@RequiresPermission(MANAGE_FINGERPRINT) public void remove(Fingerprint fp, int userId, RemovalCallback callback) { if (mService != null) try { mRemovalCallback = callback; mRemovalFingerprint = fp; mService.remove(mToken, fp.getFingerId(), fp.getGroupId(), userId, mServiceReceiver); } catch (RemoteException e) { Log.w(TAG, "Remote exception in remove: ", e); if (callback != null) { callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE, getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE)); } } }
从代码中可以看到,回调接口是通过参数传进来的,那么我们就看看这个回调接口注册指纹删除的地方:
private void sendRemovedResult(long deviceId, int fingerId, int groupId) { if (mRemovalCallback != null) { int reqFingerId = mRemovalFingerprint.getFingerId(); int reqGroupId = mRemovalFingerprint.getGroupId(); if (reqFingerId != 0 && fingerId != 0 && fingerId != reqFingerId) { Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId); return; } if (groupId != reqGroupId) { Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId); return; } mRemovalCallback.onRemovalSucceeded(new Fingerprint(null, groupId, fingerId, deviceId)); } }
在这个方法中,我们可以看到对onRemovalSucceeded()这个方法进行了注册。所以在应用层我们就能够使用这个接口进行一些操作了,接来我们看看应用层是如何进行操作的。先看代码:
private RemovalCallback mRemoveCallback = new RemovalCallback() { @Override public void onRemovalSucceeded(Fingerprint fingerprint) { mHandler.obtainMessage(MSG_REFRESH_FINGERPRINT_TEMPLATES, fingerprint.getFingerId(), 0).sendToTarget(); } @Override public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) { final Activity activity = getActivity(); if (activity != null) { Toast.makeText(activity, errString, Toast.LENGTH_SHORT); } } };
可以看到这边应用层仅仅是发送了一个消息MSG_REFRESH_FINGERPRINT_TEMPLATES,并且将对应的指纹ID传了过去,我们看一下消息处理的地方:
case MSG_REFRESH_FINGERPRINT_TEMPLATES: removeFingerprintPreference(msg.arg1); updateAddPreference(); retryFingerprint(); break;
看到这里恍然大悟,原来是通过删除指纹的回调接口对指纹选项进行了界面更新,通过调用removeFingerprintPreference()这个方法将指纹选项删除掉了,具体可以看一下这个方法:
protected void removeFingerprintPreference(int fingerprintId) { String name = genKey(fingerprintId); Preference prefToRemove = findPreference(name); if (prefToRemove != null) { if (!getPreferenceScreen().removePreference(prefToRemove)) { Log.w(TAG, "Failed to remove preference with key " + name); } } else { Log.w(TAG, "Can't find preference to remove: " + name); } }
这个方法也很简单,主要是调用getPreferenceScreen().removePreference(prefToRemove),这个方法删除了指纹选项,在删除的时候同时更新了界面,到这里删除指纹的逻辑与界面的同步我们已经明白了,下面还需要看一下指纹识别的逻辑:
5,指纹的识别
其实指纹的识别在刚开始界面更新的时候就进行了注册,我们现在返回去看一下界面更细你的代码:
private void updatePreferences() { createPreferenceHierarchy(); retryFingerprint(); }
我们发现在新建界面的时候就对指纹识别进行了注册,retryFingerprint();看看这个方法:
private void retryFingerprint() { if (!mInFingerprintLockout) { mFingerprintCancel = new CancellationSignal(); mFingerprintManager.authenticate(null, mFingerprintCancel, 0 /* flags */, mAuthCallback, null, mUserId); } }
从这里可以看到直接调用了指纹认证的接口,其中有一个重要的参数mAuthCallback,指纹认证的回调接口,我们主要看看这个回调接口:
private AuthenticationCallback mAuthCallback = new AuthenticationCallback() { @Override public void onAuthenticationSucceeded(AuthenticationResult result) { int fingerId = result.getFingerprint().getFingerId(); mHandler.obtainMessage(MSG_FINGER_AUTH_SUCCESS, fingerId, 0).sendToTarget(); } @Override public void onAuthenticationFailed() { mHandler.obtainMessage(MSG_FINGER_AUTH_FAIL).sendToTarget(); }; @Override public void onAuthenticationError(int errMsgId, CharSequence errString) { mHandler.obtainMessage(MSG_FINGER_AUTH_ERROR, errMsgId, 0, errString) .sendToTarget(); } @Override public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { mHandler.obtainMessage(MSG_FINGER_AUTH_HELP, helpMsgId, 0, helpString) .sendToTarget(); } };
这个回调接口中主要注册了四种指纹认证的情况,认证成功,认证失败,认证错误和认证帮助,在这里我们只关注认证成功和失败的情况,先看认证成功:
@Override public void onAuthenticationSucceeded(AuthenticationResult result) { int fingerId = result.getFingerprint().getFingerId(); mHandler.obtainMessage(MSG_FINGER_AUTH_SUCCESS, fingerId, 0).sendToTarget(); }
认证成功发送了消息MSG_FINGER_AUTH_SUCCESS,同时将指纹ID传了过去,看看消息处理的地方:
case MSG_FINGER_AUTH_SUCCESS: mFingerprintCancel = null; highlightFingerprintItem(msg.arg1); retryFingerprint(); break;
这里对指纹认证成功做了处理,看看到底做了什么处理?下面看看这个方法:
private void highlightFingerprintItem(int fpId) { String prefName = genKey(fpId); FingerprintPreference fpref = (FingerprintPreference) findPreference(prefName); final Drawable highlight = getHighlightDrawable(); if (highlight != null) { final View view = fpref.getView(); final int centerX = view.getWidth() / 2; final int centerY = view.getHeight() / 2; highlight.setHotspot(centerX, centerY); view.setBackground(highlight); view.setPressed(true); view.setPressed(false); mHandler.postDelayed(new Runnable() { @Override public void run() { view.setBackground(null); } }, RESET_HIGHLIGHT_DELAY_MS); } }
其实这个处理主要是对对应的指纹选项做了高亮显示处理,延时500ms之后又将背景设置为空,也就是原生的颜色,这样就可以直观的看到哪个指纹对应哪个指纹选项,识别是否能够成功。
注意:在这里我们思考这么一个问题?当出现对应的指纹选项已经删除了,但是还是要通过该指纹去识别这个选项,会出现什么情况? 这里当然会出现空指针的报错,因为指纹的识别是通过指纹ID,找到对应的指纹选项,但是指纹已经被删除了,指纹选项也就为空了,这时候如果去识别这个指纹:
FingerprintPreference fpref =(FingerprintPreference) findPreference(prefName);
这个时候就fpref就为空,所以在finalView view = fpref.getView();这一行代码就会出现空指针的报错,导致整个设置奔溃。下面看看指纹认证失败的情况,从应用层代码里边可以看到并没有对指纹认证失败的情况进行处理。但是我们在实际测试中可以发现,指纹认证失败最多能够执行5次,超过5次之后再进行指纹认证的时候就没有反应了。至于这个限制目前上层没有找到,应该是在底层进行验证的,有兴趣的同学可以进一步追一下代码,研究一下。
三, 总结:
到此我们梳理了整个设置下边指纹模块相关的一些逻辑,包括指纹的注册,指纹的重命名,指纹的删除已经界面的等,总体来说还是比较简单的,其实最难的应该是底层关于指纹的注册,读取,存储等。后边有时间在仔细研究一下。本次研究主要是针对上层关于指纹的处理作了一个比较深入的梳理。
-
pil 加载像素_python使用PIL模块获取图片像素点的方法 如何python pil开发图像识别...
2021-01-14 00:34:21使用python PIL处理图片。...比如: 用image模块更直接,可以用getpixel获得像素值,给你个例子吧。 01.#。/usr/bin/env python 02.import Image 03.import sys 04.im = Image.open(sys.argv[1]) 05.width =...使用python PIL处理图片。怎么获取图片的像素数据?
用python处理图像,想找到一种方法,能将图片的像素数据读出来。比如: 用image模块更直接,可以用getpixel获得像素值,给你个例子吧。 01.#。/usr/bin/env python 02.import Image 03.import sys 04.im = Image.open(sys.argv[1]) 05.width = im.size[0] 06.height = im.size[1] 07.print "/* width:%d */"%(width) 0
为什么用Python的openCV读取图片与PIL读取的图片像我首先尝试用PIL读取同一张图片, img1 = Image.open('000008.jpg') pri经测试,同一张图片,使用 PIL 和 OpenCv 库读取的数据是一样的(经过BGR转成RGB): 执行结果: 建议:可以尝试更新 PIL 或是 OpenCv 库。 本机测试环境: Python 3.7+Pillow 6.2 +opencv-python 4.1
如何使用Python如何获取某像素点处颜色
方法一: # -*- coding: cp936 -*- from ctypes import * #引入winapi gdi32 = windll.gdi32 user32 = windll.user32 #获取句柄 hdc = user32.GetDC(None) #获取指定像素的颜色 c = gdi32.GetPixel(hdc,100,50) #打印十进制转化为十六进制的颜色
Python如何获取图片长宽等信息
python怎么用PIL模块处理BMP图像 二值化我不是话少,也不是冷漠,只是我没必要对每个人都有说有笑。
Pillow 提供了一个 .load() 方法,用来处理像素。图片嘛,当然是二维的,有宽和高的。 pixels = image.load() for x in ramge(image.width): for y in range(image.height): pixsels[x, y] = 255 if pixsels[x, y] > 125 else 0 当然了。
用Python的PIL模块的image模块打开的图片位于哪个你所问的问题,其实是属于: 1.先参考 【教程】Python中的内置的模块 和第三方的模块 搞懂PIL是属于第三方Python模块 2.再参考: 【待完善】【总结】Python安装第三方的库、package的方法 去安装PIL模块。 3.关于PIL的一些使用。
python用PIL如何获得一张图片的亮度值
python的pil模块怎么判断图片是否相同你的身影是帆,我的目光是河流,多少次想挽留你,终不能够,我知道人间最难得的是友情,更宝贵的却是自由。
以上就是四十五资源网为大家整理的python使用PIL模块获取图片像素点的方法 如何python pil开发图像识别内容,如果觉得本站更新的资源对您有帮助 不要忘记分享给您身边的朋友哦!
-
Python 重新加载模块 reload
2019-07-09 19:51:56当对该模块进行更改后,即使重新导入,其中的任何改变都不会被识别,这使得模块调试变得非常困难。 那么,该如何解决这个问题? 模块仅被导入一次 出于效率原因(导入必须找到文件,将其编译成字节码,...简述
在进行模块化编程时,经常会遇到这样一种场景:
编写了一个 Python 模块,并用
import my_module
的形式进行导入。当对该模块进行更改后,即使重新导入,其中的任何改变都不会被识别,这使得模块调试变得非常困难。那么,该如何解决这个问题?
模块仅被导入一次
出于效率原因(导入必须找到文件,将其编译成字节码,并且运行代码),Python shell 在每次会话中,只对每个模块导入一次。
例如,有一个名为
hello.py
的模块,包含以下代码:print('Hello, Python!')
如果多次导入,会出现什么效果?
>>> import hello Hello, Python! >>> >>> import hello >>> import hello
可以看到,代码只执行了一次。也就是说,模块仅被导入了一次。
重新加载模块
倘若,更改了已经在 Python shell 中导入的模块,然后重新导入该模块,Python 会认为“我已经导入了该模块,不需要再次读取该文件”,所以更改将无效。
要解决这个问题,有以下几种方式:
- 最简单、最有效的方法:重新启动 Python shell。但是,这也有缺点,特别是丢失了 Python shell 名称空间中存在的数据以及其他导入模块中的数据。
- 对于简单的情况,可以使用 Python 的
reload()
函数。在许多情况下,在编辑一个模块之后就足够了。 - 对于更复杂的情况,重新加载被编辑的模块也需要重新加载其依赖/导入的模块(因为它们必须作为被编辑模块初始化的一部分进行初始化),所以 IPython 的 autoreload 扩展很有用。
PS: 下面主要介绍第 2 种方式 -
reload()
,其他方式自行尝试。reload()
是 Python 提供的一种简洁的方式,在不同的 Python 版本中有不同的表现形式:- 在 Python 2.x 中,reload() 是内置函数。
- 在 Python 3.0 - 3.3 中,可以使用 imp.reload(module)。
- 在 Python 3.4 中,imp 已经被废弃,取而代之的是 importlib。
>>> import importlib >>> import hello Hello, Python! # 修改前的内容 >>> >>> importlib.reload(hello) I am coming... # 修改后的内容 <module 'hello' from '/home/wang/Projects/hello.py'>
-
webpack是如何实现前端模块化的
2019-02-20 05:08:50前言es6 module是js语言原生的模块化方案,但是由于浏览器的兼容问题,需要webpack对我们写好的模块代码进行处理,可以让浏览器识别我们写的模块代码。因为浏览器端是没有commonJS规范相关的module,exports,require... -
pytest介绍、安装及如何自动识别测试用例
2019-09-29 23:14:191、自动识别测试用例和测试方法(unittest当中,需要引入TestSuite,主动加载测试用例)2、简单的断言表达:assert 表达式即可。(unittest当中,self.assert*)3、可以设置会话级(从运行所有用例开始到用例结束)、模块... -
如何识别一个进程是否为托管进程
2008-03-12 18:18:00如何识别一个进程是否是托管进程呢?我的方法是,获得进程对象,枚举进程加载的模块.如果进程加载的模块中包含mscoree.dll则认为此进程是托管的.mscoree.dll是.NET程序必需加载的DLL.不过.使用C++写的程序也可以加载它... -
vue如何加载html字符串_VUE渲染后端返回含有script标签的html字符串示例
2021-02-11 15:12:25在接入支付宝支付模块的时候,支支返回的是一个form串,细看一下还有一个script标签,如何将其渲染出来给大家分享一下经验。注意点:不能在当前页面追加任何元素例如原生js:innerHtml、appendChiled等等;Vue原生v-... -
如何使用 Opencv 实现人脸检测和人脸识别?
2017-10-08 01:47:00如何使用 Opencv 实现人脸检测和人脸识别? Note: 使用人脸识别需要自行编译 Opencv 第三方模块,地址如下: https://github.com/opencv/opencv_contrib 1.人脸检测 CascadeClassifier 加载 Opencv 自带的人脸检测... -
redhat Linux 5.0 如何识别网卡和安装驱动
2014-08-12 14:46:00如何查看网卡是否安装 1 ifconfig -a如果没有ethX 就很可能是网卡没有安装,至少可以断定网卡没有自动加载。 如果这时输入 ifconfig eth0 xxxx.xxxx.xxxx.xxxx 系统会提示没有eth0 该设备。 2 可以用 dmesg | grep ... -
Revit插件加载,addin文件的设置
2012-12-17 15:24:11问题描述:Revit二次开发使用addin加载时,出现如下...可根据供应商ID节点识别附加模块应用程序的供应商。如要Revit运行附加模块,必须注册清单“helloworld.addin”文件中定义的节点” 请问这个要如何解决,谢谢 ad -
ubuntu16.04 加载seeta_fr_v1.0.bin出错
2021-01-11 00:36:57但是在识别模块确认是net_ = CommonNet::Load(file)加载模型时候并不成功。 具体到注册网络: std::shared_ptr net = NetRegistry::CreateNet(“Eltwise”);失败 我的系统: Distributor ID: ... -
Nginx 编写模块遇到的问题
2019-04-06 22:59:48Content-Type:用于定义用户的浏览器或相关设备如何显示将要加载的数据,或者如何处理将要加载的数据 MIME:MIME类型就是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,... -
TensorFlow模型参数的保存和加载(含演示代码)
2017-11-22 08:51:15当我们通过TensorFlow构建了一个训练模型,譬如人脸识别...这就涉及到一个如何保存和加载TensorFlow训练参数的问题。 为方便使用者保存训练结果,TensorFlow提供了tf.train.Saver模块用于保存当前会话中所有的变量值(V -
Qt 之 自定义插件或控件无法识别显示
2019-03-20 15:02:42如何查看自定义控件是否加载出来? 进入Designer标签,tools -> Form Editor -> About QT Designer Plugin里是搜索到的控件,错误的控件有提示,比如Debug和Release选的不对。 dll 找不到指定的模块,这个是... -
用深度学习做命名实体识别(五)-模型使用
2019-09-24 03:46:37通过本文,你将了解如何基于训练好的模型,来编写一个rest风格的命名实体提取接口,传入一个句子,接口会提取...# 加载实体识别模型 def person_model_init(): ... # 预测句子中的实体 def predict(sentence, la... -
iOS【webView 加载微信文章注入JS实现交互 浏览图片及保存】
2017-09-11 00:20:50最近项目某个模块中要求可以实现对网页中图片的查看,并要求在多张图片的情况...在网页加载完成时,通过js获取图片和添加点击的识别方式 - (void)webViewDidFinishLoad:(UIWebView *)webView { [IDProgressHUD IDPlac -
tensorflow-image-recognition-chrome-extension:用于在网页上使用TensorFlow图像识别的Chrome浏览器扩展-...
2021-01-30 10:08:54有时,当页面上使用了一些漂亮的延迟加载模块(或其他js操纵)或嵌入了图像(data:image / png; base64,...)时,有时无法更新标题。 您可以检查背景页面视图(在chrome扩展页面上),以了解有关幕后事件的更多... -
opencv轻松入门面向pythonpdf下载_python使用opencv基于GoogLeNet 模型识别图片!
2020-11-27 20:55:27该API可C ++可在Python中调用,很容易磁盘加载模型;预处理输入图像;通过网络传递图像并获取输出分类。本文演示如何在ImageNet数据集上使用预先训练的深度学习网络并将其应用于输入图像。使用OpenCV进... -
带你玩转属于自己的spring-boot-starter系列(三)
2020-09-22 14:40:41在带你玩转属于自己的spring-boot-starter系列(一)的时候与大家分享了如何编写自己的第一个starter,接着在带你玩转属于自己的spring-boot-starter系列(二)的时候与大家分享了如何加载默认属性到我们的starter中... -
如何理解OC是一门动态语言
2018-03-14 12:06:55OC的动态特性可从三方面描述动态类型识别(Dynamic typing):最终判定该类的实例类型是在运行期间动态绑定(Dynamic binding):在运行时确定调用的方法动态加载(Dynamic loading):在运行期间可添加模块(类、... -
iOS WebView 如何通过js获取网页中所有图片并加入点击事件,实现浏览图片的功能
2016-01-07 21:45:07最近项目某个模块中要求可以实现对网页中图片的查看,并要求在多张图片的情况下可以...在网页加载完成时,通过js获取图片和添加点击的识别方式 - (void)webViewDidFinishLoad:(UIWebView *)webView { [I -
进击的KFC:iOS WebView 如何通过js获取网页中所有图片并加入点击事件,实现浏览图片的功能
2016-03-21 16:45:49最近项目某个模块中要求可以实现对网页中图片的查看,并要求在多张...在网页加载完成时,通过js获取图片和添加点击的识别方式- (void)webViewDidFinishLoad:(UIWebView *)webView { [IDProgressHUD IDPlaceViewHideD -
OpenCV4 深度神经网络(DNN)实战教程
2019-11-09 14:56:07理解卷积神经网络基本原理,熟练掌握OpenCV深度神经...学会如何把正常的tensorflow对象检测模型转化为OpenCV可以接受的模型,实时人脸检测与识别案例。学会使用OpenCV DNN模块解决实际问题。部分课程代码演示效果如下: -
揭秘webpack loader
2020-01-29 14:35:44Loader(加载器) 是 webpack 的核心之一。它用于将不同类型的文件转换为 webpack 可识别的模块。本文将尝试深入探索 webpack 中的 loader,揭秘它的工作原理,以及如何开发一个 loader。 -
学习笔记(01):OpenCV4 深度神经网络(DNN)实战教程-导入tensorflow对象检测框架模型支持...
2020-05-18 14:38:50理解卷积神经网络基本原理,熟练...学会如何把正常的tensorflow对象检测模型转化为OpenCV可以接受的模型,实时人脸检测与识别案例。学会使用OpenCV DNN模块解决实际问题。部分课程代码演示效果如下: ... -
JZ2440插入usbhub无法使用
2017-06-17 23:17:05感觉JZ2440的usb口太少了,只有一个usb host,个人感觉这是一个弊端,插了鼠标就不能...今天通过usb-hub接了个3G手机模块到设备板上,无论如何不能识别到模块,在usb相应驱动加载后有一行提示:ignoring external hu
-
linux基础入门和项目实战部署系列课程
-
筛子谜题(蓝桥)
-
【爱码农】C#制作MDI文本编辑器
-
数字逻辑课件.zip
-
Mysql数据库面试直通车
-
数据分析师八大能力培养 Part5 定义标准能力.pdf
-
【PAT B1001】害死人不偿命的3n+1猜想
-
零基础一小时极简以太坊智能合约开发环境搭建并开发部署
-
MHA 高可用 MySQL 架构与 Altas 读写分离
-
用微服务spring cloud架构打造物联网云平台
-
matplotlib中figure、subplot和axes的用法
-
入门前端-《JavaScript 语言入门教程-函数和数组》
-
PHP 含换行符的字符串复制给js变量的方法
-
数据分析师八大能力培养 Part8.总结汇报能力.pdf
-
app软件测试全栈系列精品课程
-
C/C++反汇编解密
-
【JavaScript】键盘按键+组合键
-
access应用的3个开发实例
-
mysql系列:innodb日志管理,带你高效快速理解
-
Amoeba 实现 MySQL 高可用、负载均衡和读写分离