Android中负责选择正确资源配置文件的部分是哪一部分?

8

我有一个奇怪的问题。

在你想要责备我的时候,请注意我正在开发一个定制版的Jelly Bean。因此,“通常的好方法”可能不起作用,必须采用一些不太正规的方法。

我有一个APK文件,其中包含以下内容:

layout
layout-mdpi
layout-land
layout-large-mdpi
layout-large-land-mdpi
layout-large-hdpi
layout-large-xhdpi

其他一些指标代码返回了以下结果:

D/AppDemo( 2091): measured width: 1920 PE width: 1920 scaleFactor = 1.0
D/AppDemo( 2091): [ANDROID] measured width: 1920 measured height: 1080
D/AppDemo( 2091): [ANDROID] scale for resources: 2.0 xdpi: 320.0 ydpi: 320.0
D/AppDemo( 2091): [ANDROID] screen density: xhdpi
D/AppDemo( 2091): [ANDROID] screen size: large
D/AppDemo( 2091): [ANDROID] using layout: layout-mdpi

看一下指标,为什么没有加载"layout-large-xhdpi"?请告诉我在哪里可以找到这个信息。我真的需要找到一种方法来强制Layout/Resource/AssetManager加载特定的布局。我知道这个问题上最流行的评论是"你不需要,为什么有'layout-xhdpi',应该有'drawable-xhdpi'和'layout-large'",但是请理解一下。希望能给出哪些地方需要查看以及查找什么内容的简单提示。到目前为止,看起来像是要从AssetManager入手进行挖掘/记录。当我省略'layout-mdpi'时,应用程序会崩溃并且资源丢失。错误似乎在于尽管代码返回了'xhdpi',但它在其他地方假设了'mdpi'。我需要找到这个问题,并修复它,让我的应用程序看起来像在ICS上那样漂亮。我正在想办法以简单的方式确定哪个布局被加载——所有根布局都有一个'android:tag'元素,当我使用'setContentView(R.layout.main_layout)'时,我抓取根元素上的标签并知道哪个文件夹被加载了。除了视觉反馈外,这最终还必须与我的设备配置相匹配。提前感谢。

2
虽然你不是在寻找“你不需要那个”的回复,但我相信对你最终目标的简要解释可能会帮助我们想出获取所需内容的方法,而无需走一条困难的路线。 - Phil
@Phil:好的,问题在于由于某处存在差异,所有应用程序只显示整个屏幕左上角的四分之一。它们不是更小(如果缩放正常工作),而是更大。无论如何,我已经被重新分配了,所以这就结束了。 - Shark
3个回答

3
有趣的问题。我看了一下,但是它变得有点复杂了。没有确切的答案,但也许我的分析会指引你朝着正确的方向前进。
我查看了从setContentView开始的内容。显然,在那一点上,你谈论的是一个密度无关的布局引用(例如R.layout.main_layout),然后稍后它将被转换为APK中特定文件的引用。何时和在哪里是你的问题。
我使用横向/纵向限定符,以便可以在运行时更改质量,并使用带有Android源代码附加的调试器。
以下是一个流程,从其中某个地方开始。
1. Resources.getLayout(int) 2. Resources.loadXmlResourceParser(int, String) 3. Resources.getValue(int, TypedValue, boolean) 4. AssetManager.getResourceValue(int, int, TypedValue, boolean) 5. StringBlock.get(int) 6. StringBlock.nativeGetString(int,int)
让我们倒过来看。
第6步是一个本地(C)方法,返回限定的引用,例如/res/layout-land/yourview.xml。它的参数是一个索引,但这取决于我们是否处于横向或纵向状态。
要查看它来自哪里,我们必须回到第4步。索引是TypedValue内的一个字段,但当将其传递给此方法时,它最初未正确设置。
第4步调用另一个本地方法AssetManager.loadResourceValue(),它更改传入的TypedValue并适当地设置索引。
也许你可以开始查看C语言代码,看看你能否搞定。

特别是你可能想从ResourceTypes.cpp开始,其中你可以看到与密度相关的配置项,但它很快变得太复杂了,不符合我的口味。 - Rob Pridham
ResourceTypes 看起来很有趣,似乎最贴近主题,恭喜赢得了奖金 :) - Shark
谢谢。您可以看到有一个名为“isBetterThan”的方法,它对候选配置进行比较,并可能包含您需要的逻辑。但我还没有弄清楚这些候选者来自哪里。 - Rob Pridham
让我们在聊天中继续这个讨论:http://chat.stackoverflow.com/rooms/25774/discussion-between-rob-pridham-and-shark - Rob Pridham
似乎NDK提供了访问isBetterThan逻辑的方式。有没有人知道我可以从哪里更接近Java领域来访问这个逻辑呢? - Sam
显示剩余2条评论

3

市场上有很多被黑客攻击的设备,比如 Micromax Funbook,虽然屏幕尺寸很大,但使用mdpi资源,相信我,我曾经和它们一起工作,非常令人沮丧。

正如你所提到的,你的应用程序在其他设备上运行良好,只是在这个特定的平板电脑上无法运行,你可能需要实现这里发布的类似解决方案。

http://android-developers.blogspot.in/2011/07/new-tools-for-managing-screen-sizes.html

请务必阅读本页的最后一段,它肯定会有所帮助。

总结一下,建议的方法是使用不同的资源创建一个单独的布局,并使用不同的名称。

在这里,你负责选择资源,而不是系统。虽然可能耗费时间,但肯定会有所帮助。

public class MyActivity extends Activity {
    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate();

        Configuration config = getResources().getConfiguration();
        if (config.smallestScreenWidthDp >= 600) {
            setContentView(R.layout.main_activity_tablet);
        } else {
            setContentView(R.layout.main_activity);
        }
    }
}  

问题在于我的布局文件夹是layout-sw600dp和layout-sw1000dp,但它们都没有被“触发”。似乎出了些问题,但这个问题似乎不在我能控制的范围内。但我看到这里使用的方法是拥有一个统一的布局文件夹并手动选择正确的文件夹。我明白了。 - Shark
但是这些“res/layout-xlarge/main_activity.xml # 适用于3.2之前的平板电脑”和“res/layout-sw600dp/main_activity.xml # 适用于3.2及以上版本的平板电脑”根本不起作用,也不会被选中。 - Shark

1
我不知道我是否理解正确,您正在构建自定义的Android操作系统,并希望该自定义Android操作系统始终加载相同的布局资源,在您的情况下为layout-large-xhdpi?如果是这样,我认为您需要自定义Configuration Class。如果您希望快速简单地完成,您可以在第72行及以下覆盖int常量。具体来说,请更改:
....
100     public static final int SCREENLAYOUT_SIZE_LARGE = 0x03;
108     public static final int SCREENLAYOUT_SIZE_XLARGE = 0x04;

至:

....
100     public static final int SCREENLAYOUT_SIZE_LARGE = 0x04;
108     public static final int SCREENLAYOUT_SIZE_XLARGE = 0x04;

另一种方法是覆盖构造函数和setToDefaults()方法,使其始终加载相同的屏幕布局。
我没有尝试过它,不知道它是否有效,并且我没有可靠和/或官方来源(除了官方Android代码),但我希望我能帮到你。

请查看收集的数据。这些数据是使用配置类收集的,并与我的设备匹配。它注册了一个良好的屏幕和正确的密度,但选择了错误的布局文件夹。我正在寻找快速脏修复布局选择器的方法。 - Shark

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