gpt4 book ai didi

android - 在应用程序内使用外部应用程序 fragment/Activity

转载 作者:塔克拉玛干 更新时间:2023-11-02 21:47:42 26 4
gpt4 key购买 nike

是否可以使用来自外部应用程序的 fragment/Activity 并在嵌入时使用?

例如:嵌入来自 PDF 阅读器应用程序的 PDF 阅读器 fragment 。

最佳答案

可能有点晚了,但还是觉得可以加,可能对别人有帮助。

对于 Activity ,嵌入它真的没有意义,有一种方便的方式来使用其他应用程序 Activity - 用 Intent 启动它。对于在应用程序内实现某种“插件”功能的情况下的 fragment 可能有意义。

Android Blog 'Custom Class Loading in Dalvik' 中有一个官方方法可以使用来自其他应用程序的代码(或从网络加载代码) .请注意,android 与其他平台/环境没有太大区别,因此两个部分(您的应用程序和您想要加载到您的应用程序中的 fragment )都应该支持某种契约(Contract)。这意味着您不能从任何应用程序中加载任何组件,这很常见,并且有很多原因会导致这种情况。

所以,这里有一些实现的小例子。它由3部分组成:

  • 接口(interface)项目 - 该项目包含接口(interface)的定义,应由主应用程序加载以使用外部类:
    package com.example.test_interfaces;

    import android.app.Fragment;

    /**
    * Interface of Fragment holder to be obtained from external application
    */
    public interface FragmentHolder {
    Fragment getFragment();
    }

    对于这个例子,我们只需要一个接口(interface)来演示如何加载 fragment 。
  • 插件应用程序,其中包含您需要加载的代码——在我们的例子中,它是一个 fragment 。请注意,您的 IDE 中的这个项目应该依赖于使用“提供”类型且不导出的接口(interface)一,因为它将由主应用程序导入。

    fragment ,我们要加载 插件 fragment :
    package com.sandrstar.plugin;

    import com.example.test_interfaces.FragmentHolder;

    public class PlugInFragment extends Fragment implements FragmentHolder {

    @Override
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {

    // Note that loading of resources is not the same as usual, because it loaded actually from another apk
    final XmlResourceParser parser = container.getContext().getPackageManager().getXml("com.sandrstar.plugin", R.layout.fragment_layout, null);

    return inflater.inflate(parser, container, false);
    }

    @Override
    public Fragment getFragment() {
    return this;
    }
    }

    它的布局 fragment 布局.xml :
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@android:color/black">

    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="This is from fragment"
    android:textColor="@android:color/white"/>
    </LinearLayout>
  • 想要从另一个应用程序加载 fragment 的主应用程序。它应该导入接口(interface)项目:

    Activity 本身 我的 Activity :
    public class MyActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    try {
    Class<?> requiredClass = null;
    final String apkPath = getPackageManager().getApplicationInfo("com.sandrstar.plugin",0).sourceDir;
    final File dexTemp = getDir("temp_folder", 0);
    final String fullName = "com.sandrstar.plugin.PlugInFragment";
    boolean isLoaded = true;

    // Check if class loaded
    try {
    requiredClass = Class.forName(fullName);
    } catch(ClassNotFoundException e) {
    isLoaded = false;
    }

    if (!isLoaded) {
    final DexClassLoader classLoader = new DexClassLoader(apkPath,
    dexTemp.getAbsolutePath(),
    null,
    getApplicationContext().getClassLoader());

    requiredClass = classLoader.loadClass(fullName);
    }

    if (null != requiredClass) {
    // Try to cast to required interface to ensure that it's can be cast
    final FragmentHolder holder = FragmentHolder.class.cast(requiredClass.newInstance());

    if (null != holder) {
    final Fragment fragment = holder.getFragment();

    if (null != fragment) {
    final FragmentTransaction trans = getFragmentManager().beginTransaction();

    trans.add(R.id.fragmentPlace, fragment, "MyFragment").commit();
    }
    }
    }
    } catch (PackageManager.NameNotFoundException e) {
    e.printStackTrace();
    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    } catch (InstantiationException e) {
    e.printStackTrace();
    } catch (IllegalAccessException e) {
    e.printStackTrace();
    }
    }
    }

    它的布局 main.xml :
    <RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:clipChildren="false"
    android:id="@+id/root">

    <ImageView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/down_image" />

    <FrameLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/fragmentPlace"
    android:layout_centerInParent="true" />
    </RelativeLayout>

  • 最后我们能够在真实设备上观察到以下内容:

    enter image description here

    可能的问题处理 (感谢 @MikeMiller 的更新):
  • 如果您在调用 classLoader.loadClass 时遇到以下错误:
  • java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
    确保 fragment 模块包含在主应用程序中(作为“已编译”)
  • 如果您收到 NameNotFoundException在调用 context.getPackageManager().getApplicationInfo(packageName,0).sourceDir ,然后确保该 fragment 位于已安装的 APPLICATION 中(而不仅仅是库依赖项)。请按照以下步骤确保是这种情况:

    1) 在主应用程序的 build.gradle 中,更改 apply plugin: 'android-library'apply plugin: 'android'并确保有一个虚拟 Activity java 文件。在主应用中,移除对fragment模块的依赖(步骤3中没有指定,但是我必须在主应用中添加对fragment模块的依赖。但是fragment模块现在是一个 Activity 应用程序,你可以'不依赖这些),否则你会得到:Error:Dependency unspecified on project resolves to an APK archive which is not supported as a compilation dependency.
    2)运行 fragment 模块(你现在可以这样做,因为它是一个 Activity 应用程序)。这以 getApplicationInfo 调用可以找到它的方式安装它 Revert build.gradle 并将依赖项添加回主应用程序(作为“编译”依赖项)现在一切都应该工作了。当您对 fragment 代码进行更新时,您无需再次执行此过程。但是,如果您想在新设备上运行或添加新的 fragment 模块,您将会这样做。我希望这能够节省我试图解决上述错误的时间。

  • 安卓L

    看来,基于正常 multidex support使用 Android L,则不需要上述步骤,因为类加载不同。可以使用 multidex 支持中描述的方法来代替 Android Blog 'Custom Class Loading in Dalvik' ,因为它明确指出:

    Note: The guidance provided in this document supersedes the guidance given in the Android Developers blog post Custom Class Loading in Dalvik.



    可能, android.support.multidex 的变化可能需要重用该方法。

    关于android - 在应用程序内使用外部应用程序 fragment/Activity ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7726702/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com