从另一个apk动态加载资源(布局)

5

我成功获取了布局,并将其添加到我的ViewFlipper中,但是它加载为空白。

代码如下:

Resources packageResources;
Context packageContext;
try
{   
    packageResources = pm.getResourcesForApplication(packageName);
    packageContext = this.createPackageContext(packageName,     Context.CONTEXT_INCLUDE_CODE + Context.CONTEXT_IGNORE_SECURITY);                
 }
 catch(NameNotFoundException excep)
 {
     // the package does not exist. move on to see if another exists.
 }

 Class layoutClass;
 try
 {
       // using reflection to get the layout class inside the R class of the package
       layoutClass = packageContext.getClassLoader().loadClass(packageName + ".R$layout");
 }
 catch (ClassNotFoundException excep1)
 {
     // Less chances that class won't be there.
 }

 for( Field layoutID : layoutClass.getFields() )
 {
    try
    {
        int id = layoutID.getInt(layoutClass);
        XmlResourceParser xmlResourceLayout = packageResources.getLayout(id);

        View v = new View(this, Xml.asAttributeSet(xmlResourceLayout));

        this.viewFlipper.addView(v);                 
    }
    catch (Exception excep)
   {
    continue;
   }
}

我没有收到任何错误信息,已经进行了调试和检查。布局ID是正确的。然而,在我的ViewFlipper中却什么都没有显示出来。我找不到任何警告或错误信息。


在视图层次结构中,它显示了视图的存在,但每个视图的子视图不存在。 - Siddharth Naik
3个回答

4

终于搞定了...实际上很简单!!!!

这是我做的...

  1. In the target apk, there is only resources and layouts with no application or activity code. I created a class,

    public final class ViewExtractor
    {
        private static final int NUMBER_OF_LAYOUTS = 5;
    
        public static View[] getAllViews(Context context)
        {
            View[] result = new View[ViewExtractor.NUMBER_OF_LAYOUTS];
    
            result[0] = View.inflate(context, R.layout.layout_0, null);
            result[1] = View.inflate(context, R.layout.layout_1, null);
            result[2] = View.inflate(context, R.layout.layout_2, null);
            result[3] = View.inflate(context, R.layout.layout_3, null);
            result[4] = View.inflate(context, R.layout.layout_4, null);
    
            return result;
        }
     }
    

在我的当前应用程序中,我修改了之前的代码。一旦验证包存在,就会进行修改。

        // If the package exists then get the resources within it.
        // Use the method in the class to get the views.
        Class<?> viewExtractor;
        try
        {
            viewExtractor = packageContext.getClassLoader().loadClass(packageName + ".ViewExtractor");
        }
        catch (ClassNotFoundException excep)
        {
            continue;
        }

        View[] resultViews;
        try
        {
            Method m = viewExtractor.getDeclaredMethod("getAllViews", Context.class);

            resultViews= (View[])m.invoke(null, new Object[]{packageContext});

            for( View v : resultViews)
            {
                this.viewFlipper.addView(v);
            }
        }
        catch (Exception excep)
        {
            excep.printStackTrace();
        }   

2
但是..如何使用这个类?您能否提供一个示例或链接到一个样本项目?谢谢。 - Lisitso

2
您并没有填充布局,而是创建了一个空的View并将其添加到了您的ViewFlipper中。

如何使用XmlResourceParser膨胀布局?如果不能(我已经搜索了大部分都说不可能),那么是否有其他方法可以使用另一个apk的布局并将其合并到您的应用程序中? - Siddharth Naik
1
“@SiddharthNaik:如何使用XmlResourceParser膨胀布局?”-- 我不知道这是可能的。“是否有其他方法可以使用另一个apk的布局并将其合并到您的应用程序中?”-- 我暂时想不到任何简单的方法来做到这一点。 - CommonsWare

1

我目前正在进行这项工作。只有在我知道应该提供布局层次结构的.apk文件中的活动或片段的packageName时才有效(我称之为外部上下文)。并且您需要知道要填充的布局的名称(例如R.layout.mylayout ->“mylayout”)。

Context c = createPackageContext(foreignPackageName,
    Context.CONTEXT_INCLUDE_CODE|Context.CONTEXT_IGNORE_SECURITY); //create foreign context
int resId = c.getResources.getIdentifier(mylayoutName,"layout",foreignPackageName); 
LayoutInflater myInflater = LayoutInflater.from(c); //Inflater for foreign context
View myLayout = myInflater.inflate(resId,null,false); //do not attach to a root view

非常感谢这个。它绝对有效 - 但有一个警告。我正在Android 6.0.1上进行测试,并通过调试可以看到布局确实被膨胀了 - 连同其所有子项,但是子项不会显示在屏幕上。这一定与使用外部上下文构建的那些视图有关。我编写了一些代码来粗略地克隆外部布局及其子项 - 使用我的当前上下文 - 并且显示该克隆布局是有效的。 - Code4aliving
也许你可以分享一下你写的代码,让它能够正常工作?我还不能确定为什么它没有起作用。 - FrankKrumnow
还有一件事要提到(尽管它似乎不是Code4aliving所描述的问题):ID冲突。正如您所知,像R.id.mytext这样的ID通过项目特定的R.java转换为简单的整数ID。因此,您可能会遇到与主应用程序资源的ID冲突。您可以通过不使用getActivtiy().findById而是在最内部的可能布局上使用layout.findById来减轻或完全避免这些问题。我认为这样发现过程也会更快。 - FrankKrumnow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接