【问题标题】:Android screen density calculationAndroid屏幕密度计算
【发布时间】:2012-01-29 14:08:04
【问题描述】:

谁能告诉我Android是如何计算屏幕密度的?

我的问题是我的设备(ODYS Space)分辨率为 480x800,屏幕对角线为 7 英寸。 如果我计算它的密度,我会得到一个 133 DPI 的值,但 Android(2.2 和 2.3 也一样)将它报告为“中等”密度设备(160 DPI)。

我正在与多屏支持作斗争,所以我认为 133 DPI 会被报告为“低”而不是“中”,所以现在我的屏幕布局在这个中等报告的设备上看起来很愚蠢。

我用这样的代码检查设备:

DisplayMetrics dMetrics = new DisplayMetrics(); 
getWindowManager().getDefaultDisplay().getMetrics(dMetrics);  
int d=dMetrics.densityDpi;

如果我在配置的虚拟设备(480x800/7" 和 133 DPI)上运行该代码,那么我得到的密度=120。

为什么在真机上显示的是 160?

【问题讨论】:

  • 如果您正在寻找赏金,请参阅 Peter O. 的回答和我在其下方的评论。这里的重点是 Android 如何实际计算密度,而不是如何检索设置。例如,LDPI 和 MDPI、MDPI 和 HDPI 之间的分界线在哪里……为什么给定的数字会舍入到较高的密度而不是较低的相邻密度,等等。同样,在 AVD 设备编辑器中可以看到答案的提示,但到目前为止,我还没有找到确定性、确定性、正确的答案。
  • DPI - 设备独立像素 您不能有自定义值,因为有标准 0.75 - ldpi - 120 dpi 1.0 - mdpi - 160 dpi 1.5 - hdpi - 240 dpi 2.0 - xhdpi - 320 dpi 3.0 - xxhdpi - 480 dpi 4.0 - xxxhdpi - 640 dpi

标签: android screen


【解决方案1】:

这里有两种不同的东西。

  1. 模拟器中的行为是 AVD 管理器配置 AVD 本身和可能使用设备定义的组合。仿真器系统映像已包含值,因此我们可以为所有设备配置提供相同的映像。这个烘焙值是密度的 mdpi。 当您创建具有不同密度的 AVD 时,我们会在启动时间之前注入新值。注入的值根据基本规则转换为密度桶值(ldpi,mdpi,hdpi,...)(如果超过桶值之间的一半,则进入下一个值)。

所以 120 和 160 之间的半点是 140,因此是 133dpi -> ldpi。

  1. 设备随心所欲。任何 OEM 都需要手动决定其设备的存储桶值是多少,并在属性中进行设置。它不是根据设备的实际硬件屏幕大小动态计算的。您可以制作一个真实屏幕密度为 133 的设备,但如果您愿意,可以将其放入 xxdpi 存储桶中。

最终结果是您需要创建一个新的设备定义,在其中手动说您的 7" 480x800 设备实际上是一个中等密度的设备,它应该可以工作。如果没有,这是我们这边的错误,当我们为特定的基于设备的 AVD 配置模拟器。这在 Android 平台本身上不是问题,它不计算任何东西。

【讨论】:

  • 当然,我知道 OEM 定义了自己的价值(我猜类似于改装社区的做法)。关于 AVD 编辑器,我不知道确切对话框是如何计算密度的(没有看到代码)。也就是说,感谢您通过实验证实了我的怀疑:即选择最接近计算密度的桶。有了这些信息,我找到了它的确切位置,并在 DeviceCreationDialog(在 sdkuilib 中)中找到了 SizeListener 类,这给了我在这种情况下使用的确切算法。谢谢。
【解决方案2】:

我已经更新了 2014 年的其他解决方案之一。

在您的一项活动中调用此方法:

private void tellMeDensity() {
        DisplayMetrics dm = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        int dpiClassification = dm.densityDpi;

        float xDpi = dm.xdpi;
        float yDpi = dm.ydpi;

        Toast.makeText(this, "xdpi=" + xDpi, Toast.LENGTH_SHORT).show();
        Toast.makeText(this, "ydpi=" + yDpi, Toast.LENGTH_SHORT).show();

        switch(dpiClassification) {
           case DisplayMetrics.DENSITY_LOW:
               Toast.makeText(this, "low density", Toast.LENGTH_SHORT).show();
               break;    
           case DisplayMetrics.DENSITY_MEDIUM:
               Toast.makeText(this, "medium density", Toast.LENGTH_SHORT).show();
               break;                
           case DisplayMetrics.DENSITY_HIGH:
               Toast.makeText(this, "high density", Toast.LENGTH_SHORT).show();
               break;    
           case DisplayMetrics.DENSITY_XHIGH:
               Toast.makeText(this, "xhigh density", Toast.LENGTH_SHORT).show();
               break;                  
           case DisplayMetrics.DENSITY_XXHIGH:
               Toast.makeText(this, "xxhigh density", Toast.LENGTH_SHORT).show();
               break;                  
           case DisplayMetrics.DENSITY_XXXHIGH:
               Toast.makeText(this, "xxxhigh density", Toast.LENGTH_SHORT).show();
               break;      
        }
    }

【讨论】:

    【解决方案3】:

    实际上,如果您想要 真正的显示 dpi,答案介于两者之间 如果您查询显示指标:

    DisplayMetrics dm = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(dm);
    int dpiClassification = dm.densityDpi;
    float xDpi = dm.xdpi;
    float yDpi = dm.ydpi;
    

    densityDpi 会给你值/建议你应该使用哪个密度

    0.75 - ldpi - 120 dpi
    1.0 - mdpi - 160 dpi
    1.5 - hdpi - 240 dpi
    2.0 - xhdpi - 320 dpi
    3.0 - xxhdpi - 480 dpi
    4.0 - xxxhdpi - 640 dpi
    

    如前文所述

    dm.xdpi 不会总是为您提供给定显示器的 REAL dpi,因此显示器的真实 dpi 可能应该是 Density*xdpi

    【讨论】:

      【解决方案4】:

      如果您查看docs(查找“使用配置限定符”部分),则设备被视为“低 DPI”,直到您达到/低于 120 DPI。

      【讨论】:

      • 是的。 androis 说 120 = 低; 160 = 中等; 240 = 高。没关系(我也知道在计算这些标准值时会使用任何舍入)
      • 但是为什么 android 将 133 DPI 舍入到 160 与我预期的 120 相反?
      • 我确信他们有充分的理由这样做,但我不认识他们。
      【解决方案5】:

      我使用相同的代码,我只看到了 160、240、320 的密度 Dpi 值。我认为这是对 android 操作系统的标准化。这是我的建议,只是我不知道详细的技术信息。

      【讨论】:

        【解决方案6】:
        **dpi calculation programitically:**
        
        public class SampleActivity extends Activity
        {
        
           @Override
           public void onCreate(Bundle savedInstanceState)
            {
              super.onCreate(savedInstanceState);
               setContentView(R.layout.main);
               DisplayMetrics dm = new DisplayMetrics();
               getWindowManager().getDefaultDisplay().getMetrics(dm);
               int dpiClassification = dm.densityDpi;
        
            float xDpi = dm.xdpi;
            float yDpi = dm.ydpi;
        
            Toast.makeText(SampleActivity.this, "xdpi="+xDpi, Toast.LENGTH_SHORT).show();
            Toast.makeText(SampleActivity.this, "ydpi="+yDpi, Toast.LENGTH_SHORT).show();
        
        
            switch(dpiClassification)
            {
               case DisplayMetrics.DENSITY_LOW:
                   Toast.makeText(SampleActivity.this, "low density",    
                           Toast.LENGTH_SHORT).show();
        
                         break;
        
               case DisplayMetrics.DENSITY_MEDIUM:
                   Toast.makeText(SampleActivity.this, "low medium", 
                          Toast.LENGTH_SHORT).show();
        
                         break;
               case DisplayMetrics.DENSITY_HIGH:
                   Toast.makeText(SampleActivity.this, "low high", 
                             Toast.LENGTH_SHORT).show();
        
                          break;
        
        
        
               case DisplayMetrics.DENSITY_XHIGH:
                   Toast.makeText(SampleActivity.this, "low xhigh", 
                          Toast.LENGTH_SHORT).show();
        
                         break;
               }
        
            }
         }
        

        【讨论】:

          【解决方案7】:
          DisplayMetrics metrics = new DisplayMetrics();
          getWindowManager().getDefaultDisplay().getMetrics(metrics);
          switch(metrics.densityDpi){
           case DisplayMetrics.DENSITY_LOW:
                      break;
           case DisplayMetrics.DENSITY_MEDIUM:
                       break;
           case DisplayMetrics.DENSITY_HIGH:
                       break;
          

          }

          这适用于 API lavel 4 或更高版本。

          【讨论】:

            【解决方案8】:

            制造商在为您的设备制作 ROM 映像时选择密度。它不是在运行时计算的。

            如果你看一下源码:https://github.com/android/platform_frameworks_base/blob/master/core/java/android/util/DisplayMetrics.java#L294你会看到getDeviceDensity()函数试图使用两个系统属性一个是qemu模拟器值qemu.sf.lcd_density,另一个是制造商设置值@987654324 @,最后如果制造商忘记设置一个,系统会退回到默认值。 DENSITY_DEFAULT 设置为 DENSITY_MEDIUM 设置为 160

            您可以通过插入设备并运行以下命令来验证设备属性:

            adb shell getprop ro.sf.lcd_density
            

            属性存储在/system/build.prop 并在启动时加载。您可以使用以下命令查看文件的内容:

            adb shell cat /system/build.prop
            

            【讨论】:

              猜你喜欢
              • 2015-04-01
              • 1970-01-01
              • 1970-01-01
              • 2011-10-05
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多