密码可见性在升级依赖性为27.1.0

时间:2018-04-04 06:41:23

标签: android

我收到许多与密码可见性相关的崩溃。 更奇怪的是它在某些设备上崩溃并非全部。

我在诺基亚5,三星音符4和s7,Honor 5C和9,Redmi Note 4和4,Moto E和G play和moto M都进行了测试。

JavaCode

    EditText loEtPassword = (EditText) findViewById(R.id.etPassword);
    loEtPassword.setTransformationMethod(new PasswordTransformationMethod()); // Java internal class.
    loEtPassword.setOnEditorActionListener(new DoneOnEditorActionListener(loBtnLogin)); // custom class.

验证

    public static class LoginUser {
          public String lsEmail, lsPassword, lsIMEINumber, lsJsonParameter;
    }

    LoginUser loLoginUser = new LoginUser();
    loLoginUser.lsEmail = loEtEmail.getText().toString().trim();
    loLoginUser.lsPassword = loEtPassword.getText().toString();

    if (validate(loLoginUser)) {
          //cont...
    }

    private boolean validate(LoginUser foLoginUser) {

          final EditText loEtPassword = (EditText) findViewById(R.id.etPassword);

          boolean lbIsValid = true;

          if (foLoginUser.lsPassword.length() <= 0) {
              loEtPassword.setError("Please enter Password");
              loEtPassword.requestFocus();
              lbIsValid = false;
          }
          return lbIsValid;
      }

XML文件

 <android.support.design.widget.TextInputLayout
            android:id="@+id/ilPassword"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColorHint="@color/textColorGray"
            app:hintEnabled="false"
            app:passwordToggleEnabled="true"
            app:passwordToggleTint="@color/textColorGray">

            <EditText
                android:id="@+id/etPassword"
                style="@style/editTextStyle"
                android:layout_marginBottom="@dimen/MarginBetweenView"
                android:backgroundTint="@color/textColorGray"
                android:drawableLeft="@drawable/ic_password"
                android:drawableStart="@drawable/ic_password"
                android:drawablePadding="@dimen/MarginBetweenInnerView"
                android:hint="@string/HINT_PASSWORD"
                android:imeOptions="actionDone"
                android:inputType="textEmailAddress" />
 </android.support.design.widget.TextInputLayout>

设计

enter image description here

摇篮

apply plugin: 'com.android.application'
apply plugin: 'io.fabric'

android {
    compileSdkVersion 27
    buildToolsVersion "27.0.3"
    defaultConfig {
        applicationId "com.packageName"
        minSdkVersion 14
        targetSdkVersion 25
        multiDexEnabled true
        versionName '7.2'
        versionCode 96
    }
dexOptions {
    javaMaxHeapSize "4g"
    preDexLibraries = false
}
buildTypes {
    release {
        minifyEnabled true
        shrinkResources true
        proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
        }
    }
    productFlavors {
    }
}

dependencies {
    compile files('libs/gcm.jar')
    compile 'com.android.support:support-v4:27.1.0'
    compile 'com.android.support:appcompat-v7:27.1.0'
    compile 'com.android.support:design:27.1.0'
    compile 'com.google.android.gms:play-services-analytics:11.8.0'
    compile('com.crashlytics.sdk.android:crashlytics:2.9.1@aar') {
        transitive = true
    }
    compile 'com.google.firebase:firebase-core:11.8.0'
}

apply plugin: 'com.google.gms.google-services'

参考快照 - 过去24小时内发生了21次崩溃。

enter image description here

崩溃日志

Caused by java.lang.NullPointerException
Attempt to invoke virtual method 'void android.support.design.widget.CheckableImageButton.setChecked(boolean)' on a null object reference arrow_right
android.support.design.widget.TextInputLayout.passwordVisibilityToggleRequested (Unknown Source:1339)
android.support.design.widget.TextInputLayout.onRestoreInstanceState (Unknown Source:1033)
android.view.View.dispatchRestoreInstanceState (View.java:15777)
android.view.ViewGroup.dispatchRestoreInstanceState (ViewGroup.java:3233)
android.support.design.widget.TextInputLayout.dispatchRestoreInstanceState (Unknown Source:1041)
android.view.ViewGroup.dispatchRestoreInstanceState (ViewGroup.java:3239)
android.view.ViewGroup.dispatchRestoreInstanceState (ViewGroup.java:3239)
android.view.ViewGroup.dispatchRestoreInstanceState (ViewGroup.java:3239)
android.view.ViewGroup.dispatchRestoreInstanceState (ViewGroup.java:3239)
android.view.View.restoreHierarchyState (View.java:15755)
com.android.internal.policy.PhoneWindow.restoreHierarchyState (PhoneWindow.java:2106)
android.app.Activity.onRestoreInstanceState (Activity.java:1098)
android.app.Activity.performRestoreInstanceState (Activity.java:1053)
android.app.Instrumentation.callActivityOnRestoreInstanceState (Instrumentation.java:1175)
android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2714)
android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2802)
android.app.ActivityThread.-wrap12 (ActivityThread.java)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:1549)
android.os.Handler.dispatchMessage (Handler.java:102)
android.os.Looper.loop (Looper.java:163)
android.app.ActivityThread.main (ActivityThread.java:6361)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:904)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:794)

任何人都可以帮助如何防止这个错误吗?

我需要升级targetSdkVersion吗?

如果有任何替代解决方案,请建议,因为如果我更改目标sdk版本,那么我必须在我的应用程序中更新大量代码。

3 个答案:

答案 0 :(得分:1)

我通过简单地将EditText的inputType(或我的案例中的TextInputEditText)更改为textPassword来解决这个问题。所以你应该试试这个:

<EditText
    android:id="@+id/etPassword"
    ...
    android:inputType="textPassword" />

我认为您并不是要将其设置为textEmailAddress

答案 1 :(得分:1)

由于以上答案均无济于事,所以我自己花了一些时间解决此问题。我发现方向改变时可能会发生崩溃(也许还有更多情况)。

最初,使用反射解决方案很难看。提取指示密码可见性的布尔值,并在方向更改后切换可见性。但是后来我注意到,即使不再出现崩溃,我的解决方案也不是解决此崩溃的原因。因此,我开始逐步地对代码进行注释,以查找所谓的 solution 解决方案。

解决方案(已在SDK 26,三星Galaxy Tab S3上测试)

解决方案是修改AndroidManifest。意想不到的。

我注意到添加android:configChanges属性可以解决此问题。可悲的是,我无法确切解释它如何解决该问题。解决方案是偶然发现的。如果orientation的值不能解决问题,请尝试different values

<activity
        android:configChanges="orientation"
        android:name="com.example.activity.LoginActivity"
        android:screenOrientation="sensor" />

较旧设备的解决方案(已在仿真器设备上进行测试,SDK 22)

对于较旧版本的SDK,我必须扩展TextInputLayout才能解决此问题。使用configChanges修复无法在此处解决问题。

此解决方案适用于新旧设备,因此我建议坚持使用它。

import com.google.android.material.textfield.TextInputLayout;

public class PasswordTextInputLayout extends TextInputLayout {
    public PasswordTextInputLayout(Context context) {
        super(context);
    }

    public PasswordTextInputLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public PasswordTextInputLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * We have to change "password visibility toggle enabled"
     * state twice in order to recreate private {@link TextInputLayout#passwordToggleView}.
     * Calling {@link TextInputLayout#setPasswordVisibilityToggleEnabled(boolean)}
     * we also invoke {@link TextInputLayout#updatePasswordToggleView}.
     * Which recreates passwordToggleView if it is equals to null.
     * UI performance is not affected.
     *
     * @param state saved when screen configuration has changed (e.g. orientation change).
     */
    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        setPasswordVisibilityToggleEnabled(false);
        setPasswordVisibilityToggleEnabled(true);
        super.onRestoreInstanceState(state);
    }
}

如何使用最后一种解决方案

简单。代替标签<com.google.android.material.textfield.TextInputLayout>,请使用<com.example.view.PasswordTextInputLayout>

<com.example.view.PasswordTextInputLayout
    ... >

    <com.google.android.material.textfield.TextInputEditText
        ...
        />

</com.example.view.PasswordTextInputLayout>

这次崩溃的原因是什么?

好像是活动或片段将其状态保存到Bundle后(即您在savedInstanceState中看到的Activity#onCreate),后来又用它来还原状态TextInputLayout失败了正确地做。 passwordToggleView未正确还原。一种解决方案是在可见性切换之前,添加TextInputLayout#onRestoreInstanceState方法调用updatePasswordToggleView或进行适当的更改以重新创建passwordToggleView

答案 2 :(得分:0)

使用以下代码:

if(loEtPassword.getText().toString().trim().equalsIgnoreCase("")){
    loEtPassword.setError("Please enter Password");
    loEtPassword.requestFocus();
    lbIsValid = false;
}