如何使用dexclassloader扩展包括自定义视图在内的片段(InflateException,ClassNotFoundException)

时间:2018-06-21 13:15:00

标签: android android-inflate dexclassloader

我有Main apk和Sub apk

Sub apk是一种库

主APK在资产文件夹中有子APK

Sub apk只有两个类

一个是片段类,另一个是自定义视图类

并且片段xml文件包含自定义视图

------------------------主应用程序MainActivity.java ----------------

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    try {
        InputStream inputStream = getAssets().open("sub.apk");
        FileOutputStream fileOutputStream = new FileOutputStream(new File(getExternalFilesDir(null) + "/sub.apk"));
        int length = inputStream.available();
        byte[] buffer = new byte[length];
        inputStream.read(buffer, 0, length);
        fileOutputStream.write(buffer, 0, length);
        inputStream.close();
        fileOutputStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }

    try {
        DexClassLoader dexClassLoader = new DexClassLoader((getExternalFilesDir(null) + "/sub.apk"), "", null, getClass().getClassLoader());
        Class<?> _class;
        Object object = null;
        try {
            _class = dexClassLoader.loadClass("com.test.tnojc.sub.MyFragment");
            object = _class.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        getFragmentManager().beginTransaction().add(R.id.linear_layout, (android.app.Fragment) object, null).commit();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

------------------子应用MyFragment.java --------------

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
    Resources resources = null;
    try {
        resources = getActivity().getPackageManager().getResourcesForApplication("com.test.tnojc.sub");
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }
    return inflater.inflate(resources.getLayout(R.layout.fragment_my), container, false);
}

--------------------------子应用程序MyView.java ---------------- -

公共类MyView扩展了视图{

public MyView(Context context) {
    super(context);
}

public MyView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
}

public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

}

------------------------子应用fragment_my.xml ------------------ -

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linear_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<com.test.tnojc.sub.MyView
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:background="#ffff00" />

</LinearLayout>

当片段被Main apk放大时,总是存在inflateException和ClassNotFoundException

06-21 17:47:22.211 8448-8448/com.test.tnojc.main E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.test.tnojc.main, PID: 8448
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.test.tnojc.main/com.test.tnojc.main.MainActivity}: android.view.InflateException: Binary XML file line #8: Binary XML file line #8: Error inflating class com.test.tnojc.sub.MyView
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2955)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3030)
    at android.app.ActivityThread.-wrap11(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
    at android.os.Handler.dispatchMessage(Handler.java:105)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6938)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
 Caused by: android.view.InflateException: Binary XML file line #8: Binary XML file line #8: Error inflating class com.test.tnojc.sub.MyView
 Caused by: android.view.InflateException: Binary XML file line #8: Error inflating class com.test.tnojc.sub.MyView
 Caused by: java.lang.ClassNotFoundException: Didn't find class "com.test.tnojc.sub.MyView" on path: DexPathList[[zip file "/data/app/com.test.tnojc.main-frRAX-uSidnbPYWOpcDLTg==/base.apk"],nativeLibraryDirectories=[/data/app/com.test.tnojc.main-frRAX-uSidnbPYWOpcDLTg==/lib/arm64, /system/lib64, /vendor/lib64]]
    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:93)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
    at android.view.LayoutInflater.createView(LayoutInflater.java:606)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:790)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
    at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
    at com.test.tnojc.sub.MyFragment.onCreateView(MyFragment.java:23)
    at android.app.Fragment.performCreateView(Fragment.java:2611)
    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1276)
    at android.app.FragmentManagerImpl.addAddedFragments(FragmentManager.java:2421)
    at android.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2200)
    at android.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2154)
    at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2055)
    at android.app.FragmentManagerImpl.dispatchMoveToState(FragmentManager.java:3050)
    at android.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:2997)
    at android.app.FragmentController.dispatchActivityCreated(FragmentController.java:179)
    at android.app.Activity.performCreateCommon(Activity.java:7168)
    at android.app.Activity.performCreate(Activity.java:7176)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2908)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3030)
    at android.app.ActivityThread.-wrap11(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
    at android.os.Handler.dispatchMessage(Handler.java:105)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6938)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

如果我在onCraeteView上动态添加自定义视图,或者如果Main和sub具有自定义视图作为公共库,则可以正常工作 但这不是必需的。

这种方式不可能吗?如果没有,我该怎么充气?

这是示例apk

https://github.com/woosuk0410/main

https://github.com/woosuk0410/sub

谢谢

0 个答案:

没有答案