目录
- 前言
- 正文
- 1. Caused by: java.lang.IllegalStateException: Not allowed to start service Intent app is in background
- 2. Context.startForegroundService() did not then call Service.startForeground()
- 3. Permission Denial: startForeground requires android.permission.FOREGROUND_SERVICE
- 4. BottomSheetDialog 无法显示透明背景
- 5. WheelPicker 的 setSelectedItemPosition 方法不生效
- 6. EventBus 发送事件不应该使用 code 来区分事件
- 7. Git 错误地把一个目录提交到了远程
- 8. 项目中使用 File.getPath(),File.getAbsolutePath(),File.getCanonicalPath() 混乱
- 9. Trying to instantiate a class xxx that is not a Fragment
- 10. Caused by: java.lang.IllegalStateException: Expected Android API level 21+ but was 19
- 最后
前言
记录开发中遇到的 bug,不再让自己重复地被同样的 bug 折磨。
正文
1. Caused by: java.lang.IllegalStateException: Not allowed to start service Intent app is in background
时间:2019年12月4日21:49:41
问题描述:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.iekie.free.clean/com.iekie.free.clean.ui.activity.MainActivity}: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.iekie.free.clean/.ui.service.NotificationUpdateService }: app is in background uid UidRecord{c5e652f u0a118 TRNB idle procs:1 seq(0,0,0)}
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3139)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3282)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1970)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7156)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)
Caused by: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.iekie.free.clean/.ui.service.NotificationUpdateService }: app is in background uid UidRecord{c5e652f u0a118 TRNB idle procs:1 seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1666)
at android.app.ContextImpl.startService(ContextImpl.java:1611)
at android.content.ContextWrapper.startService(ContextWrapper.java:677)
at com.iekie.free.clean.ui.service.NotificationUpdateService.a(NotificationUpdateService.java:7)
at com.iekie.free.clean.ui.util.NotificationUtils.b(NotificationUtils.java:17)
at com.iekie.free.clean.ui.activity.MainActivity.t(MainActivity.java:4)
at com.iekie.free.clean.ui.activity.MainActivity.onCreate(MainActivity.java:24)
at android.app.Activity.performCreate(Activity.java:7335)
at android.app.Activity.performCreate(Activity.java:7326)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1275)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3119)
... 11 more
java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.iekie.free.clean/.ui.service.NotificationUpdateService }: app is in background uid UidRecord{c5e652f u0a118 TRNB idle procs:1 seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1666)
at android.app.ContextImpl.startService(ContextImpl.java:1611)
at android.content.ContextWrapper.startService(ContextWrapper.java:677)
at com.iekie.free.clean.ui.service.NotificationUpdateService.a(NotificationUpdateService.java:7)
at com.iekie.free.clean.ui.util.NotificationUtils.b(NotificationUtils.java:17)
at com.iekie.free.clean.ui.activity.MainActivity.t(MainActivity.java:4)
at com.iekie.free.clean.ui.activity.MainActivity.onCreate(MainActivity.java:24)
at android.app.Activity.performCreate(Activity.java:7335)
at android.app.Activity.performCreate(Activity.java:7326)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1275)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3119)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3282)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1970)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7156)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)
解决办法:
在 API 26 以上,需要使用 startForegroundService 方式启动
public static void start(Context context) {
Intent starter = new Intent(context, NotificationUpdateService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(starter);
} else {
context.startService(starter);
}
}
2. Context.startForegroundService() did not then call Service.startForeground()
时间:2019年12月15日11:52:11
问题描述:
12-15 11:51:36.892 E/AndroidRuntime(30893): FATAL EXCEPTION: main
12-15 11:51:36.892 E/AndroidRuntime(30893): Process: com.iekie.free.clean, PID: 30893
12-15 11:51:36.892 E/AndroidRuntime(30893): android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
12-15 11:51:36.892 E/AndroidRuntime(30893): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1848)
12-15 11:51:36.892 E/AndroidRuntime(30893): at android.os.Handler.dispatchMessage(Handler.java:105)
12-15 11:51:36.892 E/AndroidRuntime(30893): at android.os.Looper.loop(Looper.java:164)
12-15 11:51:36.892 E/AndroidRuntime(30893): at android.app.ActivityThread.main(ActivityThread.java:6695)
12-15 11:51:36.892 E/AndroidRuntime(30893): at java.lang.reflect.Method.invoke(Native Method)
12-15 11:51:36.892 E/AndroidRuntime(30893): at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
12-15 11:51:36.892 E/AndroidRuntime(30893): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:772)
解决办法:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
showNotify();
}
return super.onStartCommand(intent, flags, startId);
}
@RequiresApi(api = Build.VERSION_CODES.O)
private void showNotify() {
startForeground(NotificationUtils.NOTIFICATION_ID_PERMANENT, NotificationUtils.getInstance().createNotification(null));
}
3. Permission Denial: startForeground requires android.permission.FOREGROUND_SERVICE
时间:2019年12月15日12:06:17
问题描述:在9.0机子上出现这个问题,
java.lang.SecurityException: Permission Denial: startForeground from pid=1824, uid=10479 requires android.permission.FOREGROUND_SERVICE
at android.os.Parcel.createException(Parcel.java:1942)
at android.os.Parcel.readException(Parcel.java:1910)
at android.os.Parcel.readException(Parcel.java:1860)
at android.app.IActivityManager$Stub$Proxy.setServiceForeground(IActivityManager.java:5198)
at android.app.Service.startForeground(Service.java:695)
at com.example.app.services.AudioService.setUpMediaNotification(AudioService.java:372)
at com.example.app.services.AudioService.setUpAndStartAudioFeed(AudioService.java:328)
at com.example.app.services.AudioService.onStartCommand(AudioService.java:228)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3667)
at android.app.ActivityThread.access$1600(ActivityThread.java:199)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1681)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
解决办法:
查看 Test your Android 9 app,在清单中添加权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
4. BottomSheetDialog 无法显示透明背景
时间:2019年12月15日09:44:20
问题描述: 应用中有一个底部弹窗,需要背景带有圆角,但实际上却看不到设置的圆角。
问题分析: 开始以为是背景圆角的背景被忽略了,于是把带圆角的背景设置为红色,查看一下效果:
发现自己设置的圆角背景是有的,但是 BottomSheetDialog 自己是带有白色背景的,这样才造成我原来设置的白色圆角背景看不见。所以,需要去掉 BottomSheetDialog 自带的白色背景,改为透明背景。
查看一下 BottomSheetDialog 的代码,关键的地方是下边的方法:
private View wrapInBottomSheet(int layoutResId, View view, LayoutParams params) {
// 填充 design_bottom_sheet_dialog.xml
FrameLayout container = (FrameLayout)View.inflate(this.getContext(), layout.design_bottom_sheet_dialog, (ViewGroup)null);
CoordinatorLayout coordinator = (CoordinatorLayout)container.findViewById(id.coordinator);
if (layoutResId != 0 && view == null) {
view = this.getLayoutInflater().inflate(layoutResId, coordinator, false);
}
// 找到 design_bottom_sheet 这个 id 对应的控件 bottomSheet
FrameLayout bottomSheet = (FrameLayout)coordinator.findViewById(id.design_bottom_sheet);
this.behavior = BottomSheetBehavior.from(bottomSheet);
this.behavior.setBottomSheetCallback(this.bottomSheetCallback);
this.behavior.setHideable(this.cancelable);
// 把我们的 view 添加进去
if (params == null) {
bottomSheet.addView(view);
} else {
bottomSheet.addView(view, params);
}
coordinator.findViewById(id.touch_outside).setOnClickListener(new OnClickListener() {
public void onClick(View view) {
if (BottomSheetDialog.this.cancelable && BottomSheetDialog.this.isShowing() && BottomSheetDialog.this.shouldWindowCloseOnTouchOutside()) {
BottomSheetDialog.this.cancel();
}
}
});
ViewCompat.setAccessibilityDelegate(bottomSheet, new AccessibilityDelegateCompat() {
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
super.onInitializeAccessibilityNodeInfo(host, info);
if (BottomSheetDialog.this.cancelable) {
info.addAction(1048576);
info.setDismissable(true);
} else {
info.setDismissable(false);
}
}
public boolean performAccessibilityAction(View host, int action, Bundle args) {
if (action == 1048576 && BottomSheetDialog.this.cancelable) {
BottomSheetDialog.this.cancel();
return true;
} else {
return super.performAccessibilityAction(host, action, args);
}
}
});
bottomSheet.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View view, MotionEvent event) {
return true;
}
});
return container;
}
再去查看一下 design_bottom_sheet_dialog.xml:
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2015 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<View
android:id="@+id/touch_outside"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:importantForAccessibility="no"
android:soundEffectsEnabled="false"
tools:ignore="UnusedAttribute"/>
<FrameLayout
android:id="@+id/design_bottom_sheet"
style="?attr/bottomSheetStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|top"
app:layout_behavior="@string/bottom_sheet_behavior"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</FrameLayout>
可以看到 design_bottom_sheet 这个 id 下设置了一个 style="?attr/bottomSheetStyle"
这里面应该负责设置了颜色。通过查找,重新定义主题:
<style name="CustomBottomSheetDialogTheme" parent="Theme.Design.Light.BottomSheetDialog">
<item name="bottomSheetStyle">@style/CustomBottomSheetStyle</item>
</style>
<style name="CustomBottomSheetStyle" parent="Widget.Design.BottomSheet.Modal">
<item name="android:background">@android:color/transparent</item>
</style>
并通过构造设置主题:
new BottomSheetDialog(this, R.style.CustomBottomSheetDialogTheme);
运行后解决了问题。
还可以通过下面的方法解决:
BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(this);
bottomSheetDialog.setContentView(R.layout.bottome_sheet);
// 设置背景透明
bottomSheetDialog.getWindow().findViewById(R.id.design_bottom_sheet)
.setBackgroundResource(android.R.color.transparent);
参考:https://stackoverflow.com/questions/37104960/bottomsheetdialog-with-transparent-background
5. WheelPicker 的 setSelectedItemPosition 方法不生效
时间:2019年12月15日10:35:54
问题描述: WheelPicker 设置了选中的位置,但是在显示出来之后,实际的位置与预期的位置不一致。
weightBottomSheet = new BottomSheetDialog(this);
weightBottomSheet.setContentView(R.layout.bottome_sheet);
weightBottomSheet.getWindow().findViewById(R.id.design_bottom_sheet)
.setBackgroundResource(android.R.color.transparent);
weightWheelPicker = weightBottomSheet.findViewById(R.id.wheel_picker);
ImageView ivBack = weightBottomSheet.findViewById(R.id.ivBack);
ivBack.setOnClickListener(v -> weightBottomSheet.dismiss());
TextView tvFinish = weightBottomSheet.findViewById(R.id.tvFinish);
tvFinish.setOnClickListener(v -> {
currentWeightIndex = weightWheelPicker.getCurrentItemPosition();
binding.csivWeight.setValue(weightList.get(currentWeightIndex));
weightBottomSheet.dismiss();
setupCurrentWater();
});
// 在这里设置选中的位置
weightWheelPicker.setSelectedItemPosition(currentWeightIndex,false);
weightWheelPicker.setData(weightList);
在点击事件里,显示出来:
public void onClick(View v) {
if (v == binding.csivWeight) {
weightBottomSheet.show();
}
}
解决办法:
把选中位置的代码放到显示的点击事件里:
public void onClick(View v) {
if (v == binding.csivWeight) {
weightWheelPicker.setSelectedItemPosition(currentWeightIndex,false);
weightBottomSheet.show();
}
}
解决了这个问题。
6. EventBus 发送事件不应该使用 code 来区分事件
时间:2019年12月15日10:46:43
问题描述:项目中使用 EventBus 发送事件,有的页面可能需要注册多个时间,同学们会想到使用同一个事件类,接收到以后,再通过携带过来的 code 区分具体该做什么处理。
问题分析:以现实生活中的快递为例来说明,三位买家分别在北京,上海,深圳居住,分别向郑州的卖家购买了苹果,香蕉,橘子。那么按照上面按 code 来区分的写法,郑州的卖家会把苹果群发给三位买家,北京的买家会接收,上海,深圳的买家一看不是它们的货物,会怎么办呢?
再回到我们的代码里面,三个页面需要监听不同的事件,如果通过 code 来区分事件的话,在 EventBus 发送事件时,三个页面都会收到事件而只有一个页面会真正需要这个事件,这会造成什么?白发了 2 个事件。
解决办法:还是看一下快递的例子,卖家是怎样给买家发货的?填上明确的地址信息,收货人,再发出去。代码中也应该这样操作,就是创建明确的事件,不通过 code 来区分。
7. Git 错误地把一个目录提交到了远程
时间:2019年12月16日09:20:22
问题描述:AndroidStudio 开发,有一个 .idea 目录,刚开始只是把 .idea 目录下的几个文件添加进了 .gitignore 文件中,但是后来 .idea 目录下又生成了新的文件,错误地把它们也提交到了远程。
解决办法:
在 .ignore 文件中添加一行,表示忽略掉 .idea/ 整个目录:
/.idea
打开 git bash 窗口:
git rm -r -n --cached ".idea/" //-n:加上这个参数,执行命令时,是不会删除任何文件,而是展示此命令要删除的文件列表预览。
git rm -r --cached ".idea/" //最终执行命令.
git commit -m "remove .idea folder all file out of control" //提交
git push origin master //提交到远程服务器
8. 项目中使用 File.getPath(),File.getAbsolutePath(),File.getCanonicalPath() 混乱
时间:2019年12月16日09:30:53
问题描述:项目中使用了上述三种获取路径的方法,但是并没有区分清楚它们的不同之处。
解决办法:
package com.test;
import java.io.File;
/**
* @author wangzhichao
* @since 2019/12/16
*/
public class Test {
public static void main(String[] args) throws Exception {
String pathname = "..\\demo.txt";
System.out.println(pathname+":");
File file = new File(pathname);
System.out.println("file.getPath()=" + file.getPath());
System.out.println("file.getAbsolutePath()=" + file.getAbsolutePath());
System.out.println("file.getCanonicalPath()=" + file.getCanonicalPath());
System.out.println();
pathname = ".\\demo.txt";
System.out.println(pathname+":");
file = new File(pathname);
System.out.println("file.getPath()=" + file.getPath());
System.out.println("file.getAbsolutePath()=" + file.getAbsolutePath());
System.out.println("file.getCanonicalPath()=" + file.getCanonicalPath());
System.out.println();
pathname = "G:\\AndroidWorkspaces\\Think4JavaExamples\\app\\src\\main\\java\\com\\test\\demo.txt";
System.out.println(pathname+":");
file = new File(pathname);
System.out.println("file.getPath()=" + file.getPath());
System.out.println("file.getAbsolutePath()=" + file.getAbsolutePath());
System.out.println("file.getCanonicalPath()=" + file.getCanonicalPath());
}
}
运行一下:
..\demo.txt:
file.getPath()=..\demo.txt
file.getAbsolutePath()=G:\AndroidWorkspaces\Think4JavaExamples\..\demo.txt
file.getCanonicalPath()=G:\AndroidWorkspaces\demo.txt
.\demo.txt:
file.getPath()=.\demo.txt
file.getAbsolutePath()=G:\AndroidWorkspaces\Think4JavaExamples\.\demo.txt
file.getCanonicalPath()=G:\AndroidWorkspaces\Think4JavaExamples\demo.txt
G:\AndroidWorkspaces\Think4JavaExamples\app\src\main\java\com\test\demo.txt:
file.getPath()=G:\AndroidWorkspaces\Think4JavaExamples\app\src\main\java\com\test\demo.txt
file.getAbsolutePath()=G:\AndroidWorkspaces\Think4JavaExamples\app\src\main\java\com\test\demo.txt
file.getCanonicalPath()=G:\AndroidWorkspaces\Think4JavaExamples\app\src\main\java\com\test\demo.txt
它们的区别如下:
File.getPath()
获取的是传入 File 构造的那个路径。
File.getAbsolutePath()
获取的是定义时的路径对应的相对路径,但不会处理. 和 … 的情况。
File.getCanonicalPath()
获取的是规范化的绝对路径,会处理 . 和 … 的情况。但是,它是会抛出异常的,需要处理一下。
9. Trying to instantiate a class xxx that is not a Fragment
时间:2019年12月17日22:19:45
问题描述:
错误日志:
2019-12-17 22:20:54.118 11934-11934/com.example.startactivityforresultdemo E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.startactivityforresultdemo, PID: 11934
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.startactivityforresultdemo/com.example.startactivityforresultdemo.FirstActivity}: android.view.InflateException: Binary XML file line #25: Binary XML file line #25: Error inflating class fragment
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2724)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2789)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1527)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6251)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
Caused by: android.view.InflateException: Binary XML file line #25: Binary XML file line #25: Error inflating class fragment
Caused by: android.view.InflateException: Binary XML file line #25: Error inflating class fragment
Caused by: android.app.Fragment$InstantiationException: Trying to instantiate a class com.example.startactivityforresultdemo.FirstFragmentFragment that is not a Fragment
at android.app.Fragment.instantiate(Fragment.java:617)
at android.app.Fragment.instantiate(Fragment.java:593)
at android.app.FragmentManagerImpl.onCreateView(FragmentManager.java:2302)
at android.app.FragmentController.onCreateView(FragmentController.java:98)
at android.app.Activity.onCreateView(Activity.java:5886)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:777)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:727)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:858)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:821)
at android.view.LayoutInflater.inflate(LayoutInflater.java:518)
at android.view.LayoutInflater.inflate(LayoutInflater.java:426)
at android.view.LayoutInflater.inflate(LayoutInflater.java:377)
at com.android.internal.policy.PhoneWindow.setContentView(PhoneWindow.java:424)
at android.app.Activity.setContentView(Activity.java:2416)
at androidx.databinding.DataBindingUtil.setContentView(DataBindingUtil.java:303)
at androidx.databinding.DataBindingUtil.setContentView(DataBindingUtil.java:284)
at com.example.startactivityforresultdemo.FirstActivity.onCreate(FirstActivity.java:31)
at android.app.Activity.performCreate(Activity.java:6666)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2677)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2789)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1527)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6251)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
Caused by: java.lang.ClassCastException
at android.app.Fragment.instantiate(Fragment.java:618)
at android.app.Fragment.instantiate(Fragment.java:593)
at android.app.FragmentManagerImpl.onCreateView(FragmentManager.java:2302)
at android.app.FragmentController.onCreateView(FragmentController.java:98)
at android.app.Activity.onCreateView(Activity.java:5886)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:777)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:727)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:858)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:821)
at android.view.LayoutInflater.inflate(LayoutInflater.java:518)
at android.view.LayoutInflater.inflate(LayoutInflater.java:426)
at android.view.LayoutInflater.inflate(LayoutInflater.java:377)
at com.android.internal.policy.PhoneWindow.setContentView(PhoneWindow.java:424)
at android.app.Activity.setContentView(Activity.java:2416)
at androidx.databinding.DataBindingUtil.setContentView(DataBindingUtil.java:303)
at androidx.databinding.DataBindingUtil.setContentView(DataBindingUtil.java:284)
at com.example.startactivityforresultdemo.FirstActivity.onCreate(FirstActivity.java:31)
at android.app.Activity.performCreate(Activity.java:6666)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2677)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2789)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1527)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6251)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
在一个继承于 Activity 的页面,通过 fragment 标签加载了一个继承于 androidx.fragment.app.Fragment
的 Fragment 后,报出了这个错误。
问题分析:
查看日志,定位报错的地方在 android.app.Fragment.instantiate() 这个方法里。看一下源码:
Class<?> clazz = sClassMap.get(fname);
if (clazz == null) {
// Class not found in the cache, see if it's real, and try to add it
clazz = context.getClassLoader().loadClass(fname);
if (!Fragment.class.isAssignableFrom(clazz)) {
throw new InstantiationException("Trying to instantiate a class " + fname
+ " that is not a Fragment", new ClassCastException());
}
sClassMap.put(fname, clazz);
}
clazz
对象是通过传入的参数 fname
,加载出来的,它是一个 androidx.fragment.app.Fragment
的一个子类。
Fragment.class
它所在的包是 package android.app;
再来看一下 Class.isAssignableFrom(Class clazz)
,是Class
类的方法,主要用于判断此Class
对象表示的类或接口是否与指定的Class
参数表示的类或接口相同,或者是它们的超类或超接口。很明显,结果是 false
,所以抛出了异常。
解决办法:使用继承于 android.app.Fragment
加载。
10. Caused by: java.lang.IllegalStateException: Expected Android API level 21+ but was 19
时间:2019年12月19日21:40:00
问题描述:
java.lang.ExceptionInInitializerError
at okhttp3.internal.platform.Platform$Companion.findPlatform(Platform.kt:211)
at okhttp3.internal.platform.Platform$Companion.access$findPlatform(Platform.kt:179)
at okhttp3.internal.platform.Platform.<clinit>(Platform.kt:180)
at okhttp3.OkHttpClient.<init>(OkHttpClient.kt:219)
at okhttp3.OkHttpClient.<init>(OkHttpClient.kt:211)
at com.didichuxing.doraemonkit.util.DoraemonStatisticsUtil.uploadUserInfo(DoraemonStatisticsUtil.java:51)
at com.didichuxing.doraemonkit.DoraemonKit.install(DoraemonKit.java:392)
at com.didichuxing.doraemonkit.DoraemonKit.install(DoraemonKit.java:127)
at com.prdsff.veryclean.MainApplication.onCreate(MainApplication.java:43)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1009)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4611)
at android.app.ActivityThread.access$1500(ActivityThread.java:153)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5373)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:829)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:645)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalStateException: Expected Android API level 21+ but was 19
at okhttp3.internal.platform.AndroidPlatform.<clinit>(AndroidPlatform.kt:232)
at okhttp3.internal.platform.Platform$Companion.findPlatform(Platform.kt:211)
at okhttp3.internal.platform.Platform$Companion.access$findPlatform(Platform.kt:179)
at okhttp3.internal.platform.Platform.<clinit>(Platform.kt:180)
at okhttp3.OkHttpClient.<init>(OkHttpClient.kt:219)
at okhttp3.OkHttpClient.<init>(OkHttpClient.kt:211)
at com.didichuxing.doraemonkit.util.DoraemonStatisticsUtil.uploadUserInfo(DoraemonStatisticsUtil.java:51)
at com.didichuxing.doraemonkit.DoraemonKit.install(DoraemonKit.java:392)
at com.didichuxing.doraemonkit.DoraemonKit.install(DoraemonKit.java:127)
at com.prdsff.veryclean.MainApplication.onCreate(MainApplication.java:43)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1009)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4611)
at android.app.ActivityThread.access$1500(ActivityThread.java:153)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5373)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:829)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:645)
at dalvik.system.NativeStart.main(Native Method)
使用 Doraemonkit 在 API 19 的手机上报出这个错误。
问题分析:定位一下,是 okhttp 抛出的异常。我使用的 okhttp 版本是 4.2.1,定位到代码:
val isSupported: Boolean = when {
!isAndroid -> false
else -> {
// Fail Fast
check(
Build.VERSION.SDK_INT >= 21) { "Expected Android API level 21+ but was ${Build.VERSION.SDK_INT}" }
true
}
}
官方确实毫不犹豫抛出了异常。查看 okhttp 的 Requirements:
OkHttp works on Android 5.0+ (API level 21+) and on Java 8+.
The OkHttp 3.12.x branch supports Android 2.3+ (API level 9+) and Java 7+.
从这里看出应该使用 3.12.x 版本才对。
使用开源库,有大版本号升级时,一定要去查看一下版本更新。大版本号,意味着有大的更新。
最后
代码出错了,关键是要仔细查看日志。能够仔细地查看日志,就离解决问题很近了。