Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

魅族设备 TextInputLayout 崩溃 #11

Open
Qixingchen opened this issue Sep 14, 2018 · 10 comments
Open

魅族设备 TextInputLayout 崩溃 #11

Qixingchen opened this issue Sep 14, 2018 · 10 comments
Labels
API 不工作 API 完全无法工作。(如调用无效果、API 无条件抛出异常)

Comments

@Qixingchen
Copy link

  • 设备厂商:魅族
  • 设备型号: MEIZU E3 ,PRO 6s,MX6
  • 设备 ROM: flyme 7.0.1.0A(Pro 6s 7.1.1)
  • Android 版本: 6.0/7.1.1
  • 涉及的 Android API:(请尽可能全面的列举或描述涉及到的 API)
    TextInputLayout 内嵌 TextInputEditText 例如:
  <android.support.design.widget.TextInputLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:counterEnabled="true"
                    app:counterMaxLength="15"
                    app:hintEnabled="false">

                    <android.support.design.widget.TextInputEditText
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"/>


                </android.support.design.widget.TextInputLayout>
  • 预期表现:
    正常展示页面
  • 实际表现:
    应用崩溃
  • 相关 logcat 日志:
    MEIZU E3 7.1.1
Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.text.Layout.getLineForOffset(int)' on a null object reference
       at android.widget.Editor.updateCursorPositionMz(Editor.java:7837)
       at android.widget.Editor.updateCursorsPositions(Editor.java:1963)
       at android.widget.TextView.getUpdatedHighlightPath(TextView.java:5777)
       at android.widget.TextView.onDraw(TextView.java:5963)
       at android.view.View.draw(View.java:17312)
       at android.view.View.updateDisplayListIfDirty(View.java:16290)
       at android.view.View.draw(View.java:17074)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
       at android.view.View.updateDisplayListIfDirty(View.java:16285)
       at android.view.View.draw(View.java:17074)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
       at android.view.View.draw(View.java:17315)
       at android.support.design.widget.TextInputLayout.draw(SourceFile:1577)
       at android.view.View.updateDisplayListIfDirty(View.java:16290)
       at android.view.View.draw(View.java:17074)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
       at android.view.View.updateDisplayListIfDirty(View.java:16285)
       at android.view.View.draw(View.java:17074)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
       at android.view.View.updateDisplayListIfDirty(View.java:16285)
       at android.view.View.draw(View.java:17074)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
       at android.view.View.updateDisplayListIfDirty(View.java:16285)
       at android.view.View.draw(View.java:17074)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
       at android.view.View.updateDisplayListIfDirty(View.java:16285)
       at android.view.View.draw(View.java:17074)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
       at android.view.View.updateDisplayListIfDirty(View.java:16285)
       at android.view.View.draw(View.java:17074)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
       at android.view.View.updateDisplayListIfDirty(View.java:16285)
       at android.view.View.draw(View.java:17074)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
       at android.view.View.updateDisplayListIfDirty(View.java:16285)
       at android.view.View.draw(View.java:17074)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
       at android.view.View.draw(View.java:17315)
       at com.android.internal.policy.DecorView.draw(DecorView.java:785)
       at android.view.View.updateDisplayListIfDirty(View.java:16290)
       at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:661)
       at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:667)
       at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:775)
       at android.view.ViewRootImpl.draw(ViewRootImpl.java:2857)
       at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2656)
       at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2257)
       at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1292)
       at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6498)
       at android.view.Choreographer$CallbackRecord.run(Choreographer.java:888)
       at android.view.Choreographer.doCallbacks(Choreographer.java:700)
       at android.view.Choreographer.doFrame(Choreographer.java:635)
       at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:874)
       at android.os.Handler.handleCallback(Handler.java:751)
       at android.os.Handler.dispatchMessage(Handler.java:95)
       at android.os.Looper.loop(Looper.java:154)
       at android.app.ActivityThread.main(ActivityThread.java:6371)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:936)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:826)

MX6 6.0

Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.text.Layout.getLineForOffset(int)' on a null object reference
       at android.widget.Editor.updateCursorPositionMz(Editor.java:6968)
       at android.widget.Editor.updateCursorsPositions(Editor.java:1759)
       at android.widget.TextView.getUpdatedHighlightPath(TextView.java:5703)
       at android.widget.TextView.onDraw(TextView.java:5896)
       at android.view.View.draw(View.java:16532)
       at android.view.View.updateDisplayListIfDirty(View.java:15485)
       at android.view.View.draw(View.java:16286)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
       at android.view.View.updateDisplayListIfDirty(View.java:15477)
       at android.view.View.draw(View.java:16286)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
       at android.view.View.draw(View.java:16544)
       at android.support.design.widget.TextInputLayout.draw(SourceFile:1577)
       at android.view.View.updateDisplayListIfDirty(View.java:15485)
       at android.view.View.draw(View.java:16286)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
       at android.view.View.updateDisplayListIfDirty(View.java:15477)
       at android.view.View.draw(View.java:16286)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
       at android.view.View.updateDisplayListIfDirty(View.java:15477)
       at android.view.View.draw(View.java:16286)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
       at android.view.View.updateDisplayListIfDirty(View.java:15477)
       at android.view.View.draw(View.java:16286)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
       at android.view.View.updateDisplayListIfDirty(View.java:15477)
       at android.view.View.draw(View.java:16286)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
       at android.view.View.updateDisplayListIfDirty(View.java:15477)
       at android.view.View.draw(View.java:16286)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
       at android.view.View.updateDisplayListIfDirty(View.java:15477)
       at android.view.View.draw(View.java:16286)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
       at android.view.View.updateDisplayListIfDirty(View.java:15477)
       at android.view.View.draw(View.java:16286)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
       at com.android.internal.policy.PhoneWindow$DecorView.dispatchDraw(PhoneWindow.java:2829)
       at android.view.View.draw(View.java:16544)
       at com.android.internal.policy.PhoneWindow$DecorView.draw(PhoneWindow.java:2810)
       at android.view.View.updateDisplayListIfDirty(View.java:15485)
       at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:286)
       at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:292)
       at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:327)
       at android.view.ViewRootImpl.draw(ViewRootImpl.java:3041)
       at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2845)
       at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2454)
       at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1340)
       at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6809)
       at android.view.Choreographer$CallbackRecord.run(Choreographer.java:894)
       at android.view.Choreographer.doCallbacks(Choreographer.java:696)
       at android.view.Choreographer.doFrame(Choreographer.java:631)
       at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:880)
       at android.os.Handler.handleCallback(Handler.java:815)
       at android.os.Handler.dispatchMessage(Handler.java:104)
       at android.os.Looper.loop(Looper.java:207)
       at android.app.ActivityThread.main(ActivityThread.java:5985)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:939)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:800)
  • 补充说明:

android.support.design.widget.TextInputEditText 更换为 android.support.v7.widget.AppCompatEditText 不再闪退
相关 so 链接: https://stackoverflow.com/questions/51891415/nullpointerexception-on-meizu-devices-in-editor-updatecursorpositionmz/52001305

@drakeet
Copy link

drakeet commented Sep 15, 2018

同样遇到这个问题。

Context

image
这些 TextInputLayout 的第一层崩溃都在一个魅族自己添加的以 Mz 后缀的方法上。

这个事情最终确定为:只要使用 TextInputLayout 包裹 TextInputEditText (谷歌推荐的组合,能够更好地适配 extra UI),在魅族部分系统上就会闪退。据说 TextInputLayout + AppCompatEditText。

我这边遇到更多魅族设备存在这个问题,包括 M5s。

魅族员工答复

大意就是说,魅族已经修复这个问题了,但由于固件下沉很慢,实际上效果很不尽人意。

image

按照现在的状况,大概率最终 28.0.0 正式版也会有这个问题,因为这事根本没法和谷歌反馈,总不能说:你们去买台魅族旧设备来试试,它们不兼容你们最新的 support 库 😥。

如果魅族的开发同学能够一起来写一个 workaround 提交给谷歌 support library,或许可以避免这个问题之后更大范围的影响。因为大家都是升级后遇到线上崩溃才后知后觉,而且还要探究折腾一番才知道是源于魅族系统的修改所致。

@mariotaku
Copy link

mariotaku commented Sep 30, 2018

我这里有一个(可能的)解决方案,同时不会有log警告和功能不全:
问题是出在getHint()这里。魅族可能如果mHintgetHint()不一致就会引起错误,所以我们在旧版本上面用反射获取mHint的值。

package android.support.design.widget

import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.widget.TextView

class FixedTextInputEditText(context: Context, attrs: AttributeSet?) : TextInputEditText(context, attrs) {

    override fun getHint(): CharSequence? {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            return super.getHint()
        }
        return try {
            getSuperHintHack()
        } catch (e: Exception) {
            super.getHint()
        }
    }

    private fun getSuperHintHack(): CharSequence? {
        val f = TextView::class.java.getDeclaredField("mHint")
        f.isAccessible = true
        return f.get(this) as? CharSequence
    }

}

@GreyLabsDev
Copy link

我这里有一个(可能的)解决方案,同时不会有log警告和功能不全:
问题是出在getHint()这里。魅族可能如果mHintgetHint()不一致就会引起错误,所以我们在旧版本上面用反射获取mHint的值。

package android.support.design.widget

import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.widget.TextView

class FixedTextInputEditText(context: Context, attrs: AttributeSet?) : TextInputEditText(context, attrs) {

    override fun getHint(): CharSequence? {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            return super.getHint()
        }
        return try {
            getSuperHintHack()
        } catch (e: Exception) {
            super.getHint()
        }
    }

    private fun getSuperHintHack(): CharSequence? {
        val f = TextView::class.java.getDeclaredField("mHint")
        f.isAccessible = true
        return f.get(this) as? CharSequence
    }

}

Greetings from Russian developers =) Thank you for this solution, it really works. I`am using MX6 as my main device and found that issue while testing new project. Only your type of workaround helped me.

@oasisfeng oasisfeng added the API 不工作 API 完全无法工作。(如调用无效果、API 无条件抛出异常) label Oct 9, 2018
@udenfox
Copy link

udenfox commented Oct 15, 2018

我这里有一个(可能的)解决方案,同时不会有log警告和功能不全:
问题是出在getHint()这里。魅族可能如果mHintgetHint()不一致就会引起错误,所以我们在旧版本上面用反射获取mHint的值。

package android.support.design.widget

import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.widget.TextView

class FixedTextInputEditText(context: Context, attrs: AttributeSet?) : TextInputEditText(context, attrs) {

    override fun getHint(): CharSequence? {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            return super.getHint()
        }
        return try {
            getSuperHintHack()
        } catch (e: Exception) {
            super.getHint()
        }
    }

    private fun getSuperHintHack(): CharSequence? {
        val f = TextView::class.java.getDeclaredField("mHint")
        f.isAccessible = true
        return f.get(this) as? CharSequence
    }

}

And another thanks from Ukrainian developers :)
Can confirm that it works.
Great workaround!

@gugact
Copy link

gugact commented Oct 15, 2018

package android.support.design.widget

import android.content.Context;
import android.os.Build;
import android.support.design.widget.TextInputEditText;
import android.util.AttributeSet;
import android.widget.TextView;

import java.lang.reflect.Field;

public class FixedTextInputEditText extends TextInputEditText {
    public FixedTextInputEditText(Context context) {
        super(context);
    }

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

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

    @Override
    public CharSequence getHint() {
        String manufacturer = Build.MANUFACTURER.toUpperCase();
        if (!manufacturer.contains("MEIZU") || Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            return super.getHint();
        }else{
            try {
                return getSuperHintHack();
            }catch (Exception e){
                return super.getHint();
            }
        }
    }

    private CharSequence getSuperHintHack() throws NoSuchFieldException, IllegalAccessException {
        Field hintField = TextView.class.getDeclaredField("mHint");
        hintField.setAccessible(true);
        return (CharSequence) hintField.get(this);
    }
}

Java version of the code from @mariotaku , code specific for Meizu devices only, I think it's safer this way, for the problems the java reflection can bring.

Good job @mariotaku

@calvarez-ov
Copy link

calvarez-ov commented Nov 27, 2018

Thanks for the explanations and workarounds!

In my own project, I've tried out a different workaround, which doesn't use reflection. It's still a bit hacky though 😄

  • Reset the hint on the edit text (so TextInputEditText.mHint will be the same as TextInputEditText.getHint())
  • Make the edit text's hint color transparent, to avoid seeing a double/blurry hint (due to both the edit text and its container having a hint).
private void hackFixHintsForMeizu(TextInputEditText... editTexts) {
    String manufacturer = Build.MANUFACTURER.toUpperCase(Locale.US);
    if (manufacturer.contains("MEIZU")) {
        for (TextInputEditText editText : editTexts) {
            editText.setHintTextColor(Color.TRANSPARENT);
            editText.setHint(editText.getHint());
        }
    }
}

@liudongmiao
Copy link

liudongmiao commented Dec 16, 2018

@linroid
Copy link

linroid commented Jan 11, 2019

TextInputEditTexts 换成 AppCompatEditText 可以避免这个问题

<android.support.design.widget.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="...">

    <android.support.v7.widget.AppCompatEditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</android.support.design.widget.TextInputLayout>

https://stackoverflow.com/questions/51891415/nullpointerexception-on-meizu-devices-in-editor-updatecursorpositionmz

@awenger
Copy link

awenger commented May 17, 2019

This was just fixed in the material components for Android lib, see: material-components/material-components-android#358

@huaxunhuang
Copy link

这个issue是不是已经被修复了?我在mx6上重现不出来

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API 不工作 API 完全无法工作。(如调用无效果、API 无条件抛出异常)
Projects
None yet
Development

No branches or pull requests