目錄
- 前言
- 正文
- 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 版本纔對。
使用開源庫,有大版本號升級時,一定要去查看一下版本更新。大版本號,意味着有大的更新。
最後
代碼出錯了,關鍵是要仔細查看日誌。能夠仔細地查看日誌,就離解決問題很近了。