起源
targetSdkVersion为30时运行在Android 11的小米10手机上,调用ToastUtil时闪退报错:
null不能转换为非null类型Android . widget . linear layout
看看已知的条件:
targetSdkVersion 30Android 11小米10
文末附上一份Android 11适配手册。
定位问题
好的,如果遇到问题,快速定位。我重新包装了原来的祝酒词,ToastUtil。
所以我很快找到了问题所在。
私趣create toast(msg:String){ if(toast = = null){ toast = toast . make text(yutils . getapp()。applicationContext,msg,Toast。LENGTH_SHORT) } else { toast!!。setText(msg)} val linear layout = toast!!。view as linear layout val message TextView = linear layout . get child at(0)as TextView message TextView . textsize = 15f toast!!。show() }
没错,就是这句话被改造了:
val linearLayout = toast!!。以线性布局方式查看
代码也比较简单。获得视图后,我只需设置字体大小。
为什么要写这个?看下面的源代码分析(很简单)。
源码解析
我们一般的称呼是这样写的:
Toast.makeText(上下文,味精,吐司。LENGTH_SHORT)。show()
一行代码,也很容易找到重点——make text,没错,接下来的分析就是从这里开始的。
compileSdkVersion 30之前
以compileSdkVersion 28为例,makeText源代码:
public static Toast make text(@ NonNull Context Context,@Nullable Looper looper,@NonNull CharSequence text,@ Duration int Duration){ Toast result = new Toast(Context,Looper);layoutinflate inflate =(layoutinflate)Context . getsystem service(Context。LAYOUT _ INFLATER _ SERVICE);view v = inflate . inflate(com . Android . internal . r . layout . transient _ notification,null);TextView TV =(TextView)v . findviewbyid(com . Android . internal . r . id . message);tv.setText(文本);result . mnext view = v;result.mDuration =持续时间;返回结果;}
这几行代码的关键点是什么?这是:
view v = inflate . inflate(com . Android . internal . r . layout . transient _ notification,null);
参考布局来显示信息。
这种布局也很简单:
& ltlinear layout xmlns:Android = & # 34;http://schemas.android.com/apk/res/android"安卓:layout _ width = & # 34match _ parent & # 34Android:layout _ height = & # 34;match _ parent & # 34Android:orientation = & # 34;垂直& # 34;安卓:背景= & # 34;?Android:attr/toast frame background & # 34;& gt& ltTextView Android:id = & # 34;@ Android:id/message & # 34;Android:layout _ width = & # 34;wrap _ content & # 34Android:layout _ height = & # 34;wrap _ content & # 34Android:layout _ weight = & # 34;1"Android:layout _ marginHorizontal = & # 34;24dp & # 34Android:layout _ margin vertical = & # 34;15dp & # 34Android:layout _ grity = & # 34;居中_水平& # 34;Android:text appearance = & # 34;@style/TextAppearance。敬酒& # 34;Android:text color = & # 34;@ color/primary _ text _ default _ material _ light & # 34;/& gt;& lt/linear layout & gt;
根布局LinearLayout和TextView显示文本。
这就是为什么我们得到了之前报告错误的这行代码:
val linearLayout = toast!!。以线性布局方式查看
现在看来,并没有什么不妥。其实在Android11下运行真的没问题。
SetView和getView也没问题。
/** *设置要显示的视图。* @ see # getView */public void set View(View View){ mnext View = View;} /** *返回视图。* @ see # set View */public View getView(){ return mnext View;}
作者:yechaoa
compileSdkVersion 30之后
重点是,源代码在compileSdkVersion 30之后有变化。
或者直接看关键makeText:
public static Toast make TEXT(@ NonNull Context Context,@Nullable Looper looper,@NonNull CharSequence text,@ Duration int Duration){ if(compatibility . is CHANGE enabled(CHANGE _ TEXT _ TOASTS _ IN _ THE _ SYSTEM)){ Toast result = new Toast(Context,Looper);result.mText = textresult.mDuration =持续时间;返回结果;} else { Toast result = new Toast(上下文,looper);view v = toast presenter . gettexttoastview(context,text);result . mnext view = v;result.mDuration =持续时间;返回结果;} }
嗯?获取视图的方式发生了变化。这曾经是膨胀的方式,但现在是了
view v = toast presenter . gettexttoastview(context,text);
好了,继续看toastpresenter。gettexttoastview
公共类ToastPresenter {…@ visible for testing public static final int TEXT _ TOAST _ LAYOUT = r . LAYOUT . transient _ notification;/** *返回消息{@code text}的默认文本提示视图。*/公共静态视图getTextToastView(Context Context,char sequence text){ View View View = layoutinflater . from(Context)。inflate(TEXT_TOAST_LAYOUT,null);TextView TextView = view . findviewbyid(com . Android . internal . r . id . message);textView.setText(文本);返回视图;} }
这里是不是有点眼熟?没错,和compileSdkVersion 28中的源代码差不多,但是布局变成了常量,有了注解@VisibleForTesting,但是xml代码还是一样的。
而setView和getView也是弃用的。
/** *设置要显示的视图。* * @ see # getView * @已弃用的自定义toast视图已弃用。应用程序可以使用* {@link #makeText(Context,CharSequence,int)}方法创建标准文本toast,或者使用* & lta href = & # 34{ @ docRoot } reference/com/Google/Android/material/snack bar/snack bar & # 34;& gtSnackbar & lt/a & gt;*在前台时。从Android {@link Build开始。VERSION_CODES#R},针对API级别的应用程序{ @ link Build。后台*中的VERSION_CODES#R}或更高版本将不会显示自定义toast视图。*/@已弃用的public void set View(View View){ mnext View = View;} /** *返回视图。* * & ltp & gt用{@link #Toast(Context)}构造的祝酒词没有& # 39;用非{@code null}视图调用的{@link #setView(View)} *将在此返回{@code null}。* * & ltp & gt从Android {@link Build开始。VERSION_CODES#R},在针对API级别{ @ link * Build }的应用中。VERSION_CODES#R}或更高版本,用{@link #makeText(Context,* CharSequence,int)}或其变体构造的toasts也将在此返回{@code null},除非它们用非{@code null}视图调用了* {@link #setView(View)}。如果您想在显示或隐藏* toast时得到通知,请使用{@link #addCallback(Callback)}。* * @ see # setView * @已弃用的自定义toast视图已弃用。应用程序可以使用* {@link #makeText(Context,CharSequence,int)}方法创建标准文本toast,或者使用* & lta href = & # 34{ @ docRoot } reference/com/Google/Android/material/snack bar/snack bar & # 34;& gtSnackbar & lt/a & gt;*在前台时。从Android {@link Build开始。VERSION_CODES#R},针对API级别的应用程序{ @ link Build。后台*中的VERSION_CODES#R}或更高版本将不会显示自定义toast视图。*/@ Deprecated @ Nullable public View getView(){ return mnex View;}
直接看笔记的要点:
@已弃用的自定义toast视图已弃用。应用程序可以使用{@link #makeText(Context,CharSequence,int)}方法创建标准文本toast,或者使用& lta href = & # 34{ @ docRoot } reference/com/Google/Android/material/snack bar/snack bar & # 34;& gtSnackbar & lt/a & gt;当在前景中时。从Android {@link Build开始。VERSION_CODES#R},appstargeting API级别{@link Build。后台中的VERSION_CODES#R}或更高版本将不显示自定义toast视图。
自定义toast视图toast已被否决。您可以创建标准的ToastView或使用Snackbar。从Android R开始,不再显示自定位吐司视图。
Android R也是Android11。具体版本的对应关系见。
在座的一些同学可能有一些想法。既然getView已经被放弃了,我能通过ToastPresenter得到它吗?GetTextToastView像一个系统?可惜行不通。ToastPresenter是@hide。。
适配方案
综上所述,适应计划也是明确的。
方案一
使用标准吐司
吐司。maketext(上下文、消息、吐司。length _ short)。Show () Scheme 2使用Snackbar。
Snackbar类似于吐司。了解更多相关信息。
Snackbar.make(查看,& # 34;行程已添加& # 34;,Snackbar。LENGTH_SHORT)。show()方案3没有使用系统的toast,但是可以借鉴来写自定义视图。
总体思路:
初始化引用自定义布局编写一些公开的set、get属性加上进入进出动画开始/结束显示倒计时
等空再补这个。。
Android 11开发手册
Android 11开发者手册
最后
写作不容易。如果对你有用,请给我点个赞。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。