使用来自另一个 APK 的布局加载片段
Load fragment with layout from another APK
我有两个 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_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>
MainFragment.java(第二个 APK):
@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;
}
fragment_main.xml(第二个 APK):
<?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>
不明白,为什么在行里
View view = inflater.inflate(R.layout.fragment_main, viewGroup, false);
view
始终为 NULL。我是否需要像 mainFragment
一样将 R.layout.fragment_main
加载到内存中?
@CommonsWare 已经回答了你:你正在加载 classes,而不是资源。
在 Android 的包中,您同时拥有 classes(如 R)和资源(预处理的 XML 文件,例如布局)。 ClassLoader 能够读取和加载第一个,因此加载另一个 APK R class 是可能的。但是 R 的索引只是指向资源文件,它们不包含所述资源的实际值。因此,您旁加载的 R class 不提供指向有效资源的路由。如果 R 可以做到这一点,那么 APK/AAR/APKLib 格式就不会存在;常规 JAR 文件就足够了。但他们没有,因为 android 资源文件不同于 class 文件,因此,需要 "link" 的种类才能使它们对您的 classes 可见: Rclass.
如果你想让你当前的代码工作,你需要用编码的视图组实例替换fragment_main.xml。创建一个 class/method 提供一个包含按钮的 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 之间创建 Intent 过滤器,以使 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 的那个按钮。
我有两个 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_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>
MainFragment.java(第二个 APK):
@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;
}
fragment_main.xml(第二个 APK):
<?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>
不明白,为什么在行里
View view = inflater.inflate(R.layout.fragment_main, viewGroup, false);
view
始终为 NULL。我是否需要像 mainFragment
一样将 R.layout.fragment_main
加载到内存中?
@CommonsWare 已经回答了你:你正在加载 classes,而不是资源。
在 Android 的包中,您同时拥有 classes(如 R)和资源(预处理的 XML 文件,例如布局)。 ClassLoader 能够读取和加载第一个,因此加载另一个 APK R class 是可能的。但是 R 的索引只是指向资源文件,它们不包含所述资源的实际值。因此,您旁加载的 R class 不提供指向有效资源的路由。如果 R 可以做到这一点,那么 APK/AAR/APKLib 格式就不会存在;常规 JAR 文件就足够了。但他们没有,因为 android 资源文件不同于 class 文件,因此,需要 "link" 的种类才能使它们对您的 classes 可见: Rclass.
如果你想让你当前的代码工作,你需要用编码的视图组实例替换fragment_main.xml。创建一个 class/method 提供一个包含按钮的 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 之间创建 Intent 过滤器,以使 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 的那个按钮。