Java 从另一个APK加载带有布局的片段

Java 从另一个APK加载带有布局的片段,java,android,android-fragments,layout,dynamic-loading,Java,Android,Android Fragments,Layout,Dynamic Loading,我有两个APK。第一个APK是加载第二个APK的主APK MainActivity.java(第一个APK):对象mainFragment是由DexClassLoader提前加载的 setContentView(R.layout.activity_main); LinearLayout fragContainer = findViewById(R.id.main_fragment); LinearLayout ll = new LinearLayout(context); ll.setOri

我有两个APK。第一个APK是加载第二个APK的主APK

MainActivity.java(第一个APK):对象
mainFragment
是由DexClassLoader提前加载的

setContentView(R.layout.activity_main);

LinearLayout fragContainer = findViewById(R.id.main_fragment);

LinearLayout ll = new LinearLayout(context);
ll.setOrientation(LinearLayout.HORIZONTAL);
ll.setId(View.generateViewId());

getSupportFragmentManager().beginTransaction().add(ll.getId(), mainFragment, "mainFragment").commit();

fragContainer.addView(ll);
activity\u main.xml(第一个APK):

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

</LinearLayout>
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_main, viewGroup, false);

    view.findViewById(R.id.emailSignInButton).setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {

        }
    });

    return view;
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
        android:layout_height="match_parent">
    <Button
            android:text="@string/sign_in"
            android:layout_width="88dp"
            android:layout_height="wrap_content"
            android:id="@+id/emailSignInButton"

            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="32dp"
            android:layout_marginEnd="32dp" android:layout_marginTop="8dp"
            tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
fragment\u main.xml(第二个APK):

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

</LinearLayout>
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_main, viewGroup, false);

    view.findViewById(R.id.emailSignInButton).setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {

        }
    });

    return view;
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
        android:layout_height="match_parent">
    <Button
            android:text="@string/sign_in"
            android:layout_width="88dp"
            android:layout_height="wrap_content"
            android:id="@+id/emailSignInButton"

            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="32dp"
            android:layout_marginEnd="32dp" android:layout_marginTop="8dp"
            tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>

视图
始终为空。我是否需要像
mainFragment
那样将
R.layout.fragment\u main
加载到内存中?

@commonware已经回答了您:您正在加载类,而不是资源

在Android的软件包中,您既有类(比如R),也有资源(比如预处理的XML文件,比如布局)。类加载器能够读取和加载第一个类,因此,加载另一个的APKR类是可能的。但是R的索引只是指向资源文件,它们不包含所述资源的实际值。因此,您附带加载的R类不提供到有效资源的路由。如果R可以做到这一点,那么APK/AAR/APKLib格式将不存在;常规JAR文件就足够了。但它们不是,因为android资源文件不同于类文件,因此,需要一个“链接”使它们对类可见:R类

如果要使当前代码正常工作,需要将fragment_main.xml替换为编码的viewgroup实例。创建一个类/方法,提供包含按钮的constraintLayout实例(例如MyViewFactory.createConstraintLayoutWithButton),通过代码设置属性,然后替换

    @Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_main, viewGroup, false);

    view.findViewById(R.id.emailSignInButton).setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {

        }
    });

    return view;
}
有点像

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
    View view = MyViewFactory.createConstraintLayoutWithButton(getContext)

    view.findViewById(R.id.emailSignInButton).setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {

        }
    });

    return view;
}
只要你不使用资源,你就会没事的。也就是说,这种方法非常脆弱,所以最好在APK之间创建意图过滤器,以使APK 2适用于APK 1

编辑: 您可以使用R常量作为代码生成视图的ID,只要您首先手动设置它们。例如:

public static ConstraintLayout createConstraintLayoutWithButton(Context context){

  Constraintlayout mylayout = new ConstraintLayout(context);
  //set up of the layout
  Button myButton = new Button(context);
  //set up of the button
  button.setId(R.id.emailSignInButton);
  myLayout.addView(button);
  return mylayout;
}

然后您可以找到id为的按钮。

资源不存在
DexClassLoader
加载类,而不是资源。尝试使用应用程序上下文,而不是视图组上下文,例如View.inflate(getApplicationContext(),R.layout.fragment\u main,viewGroup)或LayoutInflater.from(getApplicationContext()).inflate(R.layout.fragment\u main,viewGroup,false)@VytautasBerankis它无助于感谢您的解决方案。1.我不认为Commonware回答了我的问题,所以我不能求助于他的评论作为解决方案。2.我尝试了你的解决方案,它对我有效(我将它标记为正确答案)。3.我的目的是从主APK创建动态加载代码/资源,我需要它来无声地更新我的应用程序(由于某些原因,我不能使用GooglePlay)。所以在您的解决方案中,所有资源都必须硬编码?例如,R.id.emailSignInButton它将在MyViewFactory.emailSignInButton之类的东西上更改?我明白了吗?嗨!在这种情况下,您必须将所有内容作为一个类公开,XML将无法从类加载器中看到。因此,XML布局是不可能的。但对于像图像这样的物理资产,您可以在APK 2中提供一个服务,将这些文件复制到共享目录中,APK 1可以从中读取它们。您仍然可以使用R常量作为ID,但必须在代码生成视图中手动设置它们。