Coder Social home page Coder Social logo

嵌套 PreferenceFragmentCompat 导致 java.lang.ClassCastException: cannot be cast to com.tencent.shadow.core.runtime.ShadowActivity about shadow HOT 4 CLOSED

LeonWu6 avatar LeonWu6 commented on June 15, 2024
嵌套 PreferenceFragmentCompat 导致 java.lang.ClassCastException: cannot be cast to com.tencent.shadow.core.runtime.ShadowActivity

from shadow.

Comments (4)

shifujun avatar shifujun commented on June 15, 2024

大致浏览之后,我是比较相信这里是遇到bug了的。因为PreferenceFragmentCompat应该只是个androidx的fragment,怎么都不应该被实例化成Activity(ShadowActivity)的。所以问题可能出在ShadowAppComponentFactory上。

androidx不需要特别支持,所以我们应该找出它依赖的系统api有什么需要支持的。

如果你不能自己解决这个问题,最好fork项目后在sample或test工程里用最少代码复现一下这个问题。

androidx相关的例子可以在这个插件工程里添加代码:
https://github.com/Tencent/Shadow/tree/master/projects/test/plugin/androidx-cases/test-plugin-androidx-cases

from shadow.

LeonWu6 avatar LeonWu6 commented on June 15, 2024

Hi @shifujun
由于我们公司网络限制,无法 push code changes 到 github 上,请辛苦浏览复制以下复现问题的测试代码。
我在 Sample 里面加了一个 testcase,可复现此 Issue 所说的问题。
请看下面的 patch

  1. git patch, (打补丁)
    1.1 请在您的 PC上创建 Issue#1194_Change.patch 文件,在 NotePad++ 打开 Issue#1194_Change.patch;
    1.2 请将此 patch 内容复制到您的 Issue#1194_Change.patch 文件中,将 Issue#1194_Change.patch 文件拷贝到 Shadow 仓库的根目录;
    1.3 在 Shadow 仓库中使用 git apply Issue#1194_Change.patch 打入补丁。

以下是补丁的内容:(请使用补丁内容)

diff --git a/projects/sample/source/sample-plugin/sample-app/build.gradle b/projects/sample/source/sample-plugin/sample-app/build.gradle
index 5bb93f01..85546e31 100644
--- a/projects/sample/source/sample-plugin/sample-app/build.gradle
+++ b/projects/sample/source/sample-plugin/sample-app/build.gradle
@@ -18,6 +18,7 @@ buildscript {
 
 apply plugin: 'com.android.application'
 apply plugin: 'com.tencent.shadow.plugin'
+apply plugin: 'kotlin-android'
 
 android {
     compileSdkVersion project.COMPILE_SDK_VERSION
@@ -68,6 +69,7 @@ dependencies {
     //Shadow Transform后业务代码会有一部分实际引用runtime中的类
     //如果不以compileOnly方式依赖,会导致其他Transform或者Proguard找不到这些类
     pluginCompileOnly 'com.tencent.shadow.core:runtime'
+    implementation 'androidx.preference:preference:1.2.0'
 }
 
 preBuild.dependsOn(":sample-host-lib:jarDebugPackage")
diff --git a/projects/sample/source/sample-plugin/sample-app/src/main/AndroidManifest.xml b/projects/sample/source/sample-plugin/sample-app/src/main/AndroidManifest.xml
index abac57e8..83fbc3c7 100644
--- a/projects/sample/source/sample-plugin/sample-app/src/main/AndroidManifest.xml
+++ b/projects/sample/source/sample-plugin/sample-app/src/main/AndroidManifest.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
     package="com.tencent.shadow.sample.plugin.app.lib">
 
     <uses-feature android:glEsVersion="0x00020000" />
@@ -62,6 +63,8 @@
         <activity android:name=".usecases.host_communication.PluginUseHostClassActivity" />
         <activity android:name=".usecases.webview.WebViewActivity" />
         <activity android:name=".usecases.fragment.TestDialogFragmentActivity" />
+        <activity android:name=".usecases.preferencefragmentcompatcase.RfFragment"
+            tools:ignore="Instantiatable" />
 
         <provider
             android:authorities="${applicationId}.provider.test"
diff --git a/projects/sample/source/sample-plugin/sample-app/src/main/java/com/tencent/shadow/sample/plugin/app/lib/UseCaseApplication.java b/projects/sample/source/sample-plugin/sample-app/src/main/java/com/tencent/shadow/sample/plugin/app/lib/UseCaseApplication.java
index 93c05284..3f43f005 100644
--- a/projects/sample/source/sample-plugin/sample-app/src/main/java/com/tencent/shadow/sample/plugin/app/lib/UseCaseApplication.java
+++ b/projects/sample/source/sample-plugin/sample-app/src/main/java/com/tencent/shadow/sample/plugin/app/lib/UseCaseApplication.java
@@ -22,6 +22,7 @@ import com.tencent.shadow.sample.plugin.app.lib.usecases.fragment.TestDynamicFra
 import com.tencent.shadow.sample.plugin.app.lib.usecases.fragment.TestXmlFragmentActivity;
 import com.tencent.shadow.sample.plugin.app.lib.usecases.host_communication.PluginUseHostClassActivity;
 import com.tencent.shadow.sample.plugin.app.lib.usecases.packagemanager.TestPackageManagerActivity;
+import com.tencent.shadow.sample.plugin.app.lib.usecases.preferencefragmentcompatcase.RfFragment;
 import com.tencent.shadow.sample.plugin.app.lib.usecases.provider.TestDBContentProviderActivity;
 import com.tencent.shadow.sample.plugin.app.lib.usecases.provider.TestFileProviderActivity;
 import com.tencent.shadow.sample.plugin.app.lib.usecases.receiver.TestDynamicReceiverActivity;
@@ -51,7 +52,8 @@ public class UseCaseApplication extends Application {
                 new TestActivityWindowSoftMode.Case(),
                 new TestActivitySetTheme.Case(),
                 new TestActivityOptionMenu.Case(),
-                new WebViewActivity.Case()
+                new WebViewActivity.Case(),
+                new RfFragment.Case()
         });
         useCases.add(activityCategory);
 
@@ -97,5 +99,8 @@ public class UseCaseApplication extends Application {
                 new PluginUseHostClassActivity.Case(),
         });
         useCases.add(communicationCategory);
+        UseCaseCategory PreferenceFragmentCompatCategory = new UseCaseCategory("PreferenceFragmentCompat嵌套用例",
+                new UseCase[]{new RfFragment.Case(),});
+        useCases.add(PreferenceFragmentCompatCategory);
     }
 }
diff --git a/projects/sample/source/sample-plugin/sample-app/src/main/res/values/strings.xml b/projects/sample/source/sample-plugin/sample-app/src/main/res/values/strings.xml
index 8cb0af94..289eb0cb 100644
--- a/projects/sample/source/sample-plugin/sample-app/src/main/res/values/strings.xml
+++ b/projects/sample/source/sample-plugin/sample-app/src/main/res/values/strings.xml
@@ -20,5 +20,9 @@
     <!-- Simple strings. -->
     <string name="app_name">Shadow主测试用例集合</string>
     <string name="host_add_plugin_view">这是插件中的string资源</string>
+    <string name="nv_backup_title">NV Backup</string>
+    <string name="rf_items">RF Module</string>
+    <string name="qti_nv">NV parameters</string>
+    <string name="qti_adjust">Calibration status</string>
 </resources>

  1. 在 projects/sample/source/sample-plugin/sample-app/src/main/java/com/tencent/shadow/sample/plugin/app/lib/usecases 目录下新增一个 testcase,嵌套调用 PreferenceFragmentCompat

$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   projects/sample/source/sample-plugin/sample-app/build.gradle
        modified:   projects/sample/source/sample-plugin/sample-app/src/main/AndroidManifest.xml
        modified:   projects/sample/source/sample-plugin/sample-app/src/main/java/com/tencent/shadow/sample/plugin/app/lib/UseCaseApplication.java
        modified:   projects/sample/source/sample-plugin/sample-app/src/main/res/values/strings.xml

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        projects/sample/source/sample-plugin/sample-app/src/main/java/com/tencent/shadow/sample/plugin/app/lib/usecases/preferencefragmentcompatcase/
        projects/sample/source/sample-plugin/sample-app/src/main/res/xml/

2.1 com/tencent/shadow/sample/plugin/app/lib/usecases/preferencefragmentcompatcase/RfFragment.kt

package com.tencent.shadow.sample.plugin.app.lib.usecases.preferencefragmentcompatcase

import android.os.Bundle
import com.tencent.shadow.sample.plugin.app.lib.R
import com.tencent.shadow.sample.plugin.app.lib.gallery.cases.entity.UseCase

class RfFragment : EngineerFragmentCompat() {

    class Case : UseCase() {
        override fun getName(): String {
            return "PreferenceFragmentCompat 嵌套测试"
        }

        override fun getSummary(): String {
            return "测试PreferenceFragmentCompat嵌套"
        }

        override fun getPageClass(): Class<*> {
            return RfFragment::class.java
        }
    }

    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        addPreferencesFromResource(R.xml.fragment_rf_container)
    }
}

2.2 com/tencent/shadow/sample/plugin/app/lib/usecases/preferencefragmentcompatcase/NVBackupUI.kt

package com.tencent.shadow.sample.plugin.app.lib.usecases.preferencefragmentcompatcase
import android.os.Bundle
import android.util.Log
import androidx.preference.PreferenceFragmentCompat
import com.tencent.shadow.sample.plugin.app.lib.R

class NVBackupUI : PreferenceFragmentCompat() {

    private val TAG = "NVBackupUI"
    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        Log.d(TAG, "onCreatePreferences")
        addPreferencesFromResource(R.xml.qti_nv_options)
    }
}

2.3 com/tencent/shadow/sample/plugin/app/lib/usecases/preferencefragmentcompatcase/EngineerFragmentCompat.kt

package com.tencent.shadow.sample.plugin.app.lib.usecases.preferencefragmentcompatcase

import android.content.Context
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceScreen
import android.util.Log
import androidx.annotation.RequiresApi
import com.tencent.shadow.sample.plugin.app.lib.R

open class EngineerFragmentCompat : PreferenceFragmentCompat() {

    private val TAG = "EngineerFragmentCompat"
    private var mContext: Context? = null

    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        Log.d(TAG, "onCreatePreferences")
    }

    override fun onAttach(p0: Context) {
        super.onAttach(p0)
        mContext = p0
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val preferenceScreen: PreferenceScreen = preferenceManager.preferenceScreen
        for (i in 0 until preferenceScreen.preferenceCount) {
            val preference = preferenceScreen.getPreference(i)
            val intent = preference.intent
            if (intent != null) {
                preference.isEnabled = true
            } else {
                Log.w(TAG, "onViewCreated preference is not available for i: $i")
                preference.isEnabled = false
            }
        }
    }

    /**
     * 实例化 Fragment 来显示视图,这将在 onCreate 和 onViewCreated 之间调用。
     * */
    @RequiresApi(Build.VERSION_CODES.M)
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        val view: View = super.onCreateView(inflater, container, savedInstanceState)
        view.setBackgroundColor(
            resources.getColor(R.color.material_grey_850, mContext?.theme)
        )
        return view
    }

    override fun getCallbackFragment(): Fragment {
        return this
    }
}

2.4 xml/fragment_rf_container.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
    android:key="rf_container"
    android:title="@string/rf_items">

    <androidx.preference.Preference
        android:key="nv_backup"
        android:title="@string/nv_backup_title">
        <intent
            android:action="android.intent.action.MAIN"
            android:targetClass="com.tencent.shadow.sample.plugin.app.lib.usecases.preferencefragmentcompatcase.NVBackupUI"
            android:targetPackage="com.tencent.shadow.sample.host" />
    </androidx.preference.Preference>
</PreferenceScreen>

2.5 xml/qti_nv_options.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <Preference
        android:key="nv_function_new"
        android:title="@string/qti_nv">
        <intent
            android:action="android.intent.action.MAIN"
            android:targetClass="com.tencent.shadow.sample.plugin.app.lib.usecases.preferencefragmentcompatcase.NVBackupUIActivity"
            android:targetPackage="com.tencent.shadow.sample.host" />
    </Preference>
</PreferenceScreen>
  1. 测试方法:
    基于本代码 commit chagnes
    安装 sample-host:installDebug
    进入 Shadow Dynamic测试宿主App
    点击 启动插件
    左边栏选择最后一项:PreferenceFragmentCompat嵌套用例,点击“启动”

  2. 异常出现:
    插件APP 闪退,UI界面回到宿主UI,com.tencent.shadow.sample.host:plugin Crashed
    AndroidRuntime: Shutting down VM
    --------- beginning of crash
    AndroidRuntime: FATAL EXCEPTION: main
    AndroidRuntime: Process: com.tencent.shadow.sample.host:plugin, PID: 27763
    AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tencent.shadow.sample.host/com.tencent.shadow.sample.plugin.runtime.PluginDefaultProxyActivity}: java.lang.RuntimeException: java.lang.ClassCastException: com.tencent.shadow.sample.plugin.app.lib.usecases.preferencefragmentcompatcase.RfFragment cannot be cast to com.tencent.shadow.core.runtime.ShadowActivity
    AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3876)
    AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4018)
    AndroidRuntime: at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:111)
    AndroidRuntime: at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
    AndroidRuntime: at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
    AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2474)
    AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:106)
    AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:240)
    AndroidRuntime: at android.os.Looper.loop(Looper.java:351)
    AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:8426)
    AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
    AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:584)
    AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1013)
    AndroidRuntime: Caused by: java.lang.RuntimeException: java.lang.ClassCastException: com.tencent.shadow.sample.plugin.app.lib.usecases.preferencefragmentcompatcase.RfFragment cannot be cast to com.tencent.shadow.core.runtime.ShadowActivity
    AndroidRuntime: at com.tencent.shadow.core.loader.delegates.ShadowActivityDelegate.onCreate(ShadowActivityDelegate.kt:159)
    AndroidRuntime: at com.tencent.shadow.core.runtime.container.PluginContainerActivity.onCreate(PluginContainerActivity.java:84)
    AndroidRuntime: at android.app.Activity.performCreate(Activity.java:8460)
    AndroidRuntime: at android.app.Activity.performCreate(Activity.java:8433)
    AndroidRuntime: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1403)
    AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3849)
    AndroidRuntime: ... 12 more
    AndroidRuntime: Caused by: java.lang.ClassCastException: com.tencent.shadow.sample.plugin.app.lib.usecases.preferencefragmentcompatcase.RfFragment cannot be cast to com.tencent.shadow.core.runtime.ShadowActivity
    AndroidRuntime: at com.tencent.shadow.core.runtime.ShadowAppComponentFactory.instantiateActivity(ShadowAppComponentFactory.java:18)
    AndroidRuntime: at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:45)
    AndroidRuntime: at com.tencent.shadow.core.loader.delegates.ShadowActivityDelegate.onCreate(ShadowActivityDelegate.kt:120)
    AndroidRuntime: ... 17 more

from shadow.

shifujun avatar shifujun commented on June 15, 2024

你前面这个patch我复制下来倒是能像你说的那样复现一个RfFragment cannot be cast to com.tencent.shadow.core.runtime.ShadowActivity的crash。但这个看起来是非常正常的,因为你写了:

override fun getPageClass(): Class<*> {
            return RfFragment::class.java
        }

这是把一个车fragment填到intent里去startActivity了。(

如果这就是你说的原本的问题,那肯定是你的业务代码哪写错了,把fragment当activity去start了。

另外你代码中也没有NVBackupUIActivity,看起来莫名其妙的。

特意指明让你在test-plugin-androidx-cases中复现问题就是避免sample-app中依赖的support包和你要添加的androidx冲突。否则你这个例子现在sample-app能单独运行吗?我这很正常的报Duplicate class found了。如果你能运行,我估计也会很正常的报类错误吧。改在test-plugin-androidx-cases中试试吧。test-plugin-androidx-cases和sample-app一样,test-dynamic-host和sample-host一样,只是这些test工程有自动化测试。

另外这样贴代码绝对不是正常的交流方式,你只是赶上我有空贴一下patch而已。你下次还是push上来吧。最不济也可以push到国内的其他公开git仓库上。

from shadow.

LeonWu6 avatar LeonWu6 commented on June 15, 2024

把fragment当activity去start了。

Hi @shifujun
确实,我是把 fragment 当作 activity 去start 了,导致了原来的问题。
感谢您的指导!

另外,回答您的 comment 中的问题:
1.

另外你代码中也没有NVBackupUIActivity,看起来莫名其妙的。
因为我贴代码时,认为只要调用到第二层嵌套的 PreferenceFragmentCompat UI 即可,不会再进到 NVBackupUIActivity,所以我没有把 NVBackupUIActivity 的代码贴出来。

谢谢!

from shadow.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.