为啥有时这不起作用?

Posted

技术标签:

【中文标题】为啥有时这不起作用?【英文标题】:Why is this not working sometimes?为什么有时这不起作用? 【发布时间】:2016-04-10 02:34:16 【问题描述】:

TL;DR 我有很多按钮,我正在交换它们的图像。出于某种原因,我的代码只能在某些手机上运行,​​而不能在其他手机上运行。

我的应用使用以下代码来比较图像按钮上的图像:

onCreate:

redsquare = getResources().getDrawable(R.drawable.redsquare);
bitred = ((BitmapDrawable) redsquare).getBitmap();

onClickv 是点击的按钮)

ClickGround = v.getBackground(); //Get the background of button clicked
//the bitmap background of the button clicked
BitClick = ((BitmapDrawable) ClickGround).getBitmap(); 

然后,稍后在 onClick 中,我通过执行以下操作检查用户是否点击了 redSquare:

if (BitClick == bitred)  //Make sure it is the red square that user clicked

我已经在模拟器和华为手机上测试过,效果很好。当我在我的另一部手机(lg g3)上测试它时,if 语句没有通过。为什么结果不一样? 我的手机中的图像是否被弄乱了?

【问题讨论】:

为什么要将点击次数与背景而不是视图的 id 进行比较? Why is this not working sometimes 不是一个好的问题标题。 【参考方案1】:

首先,Resources.getDrawable(int) 是deprecated。它可能与您的问题无关,但您应该解决它。

如果您使用== 比较位图,您就是在比较对象身份。如果== 测试给你false,那意味着你在比较不同的对象。这是毫无疑问的。

您的 sn-ps 没有提供足够的上下文来确定,但这里有一些可能性:

    代码中的某些内容导致将不同的值分配给 bitred

    两个sn-ps代码中的bitred标识符不表示同一个Java变量。

    您认为用作红色背景的“红色”位图始终是相同对象的假设是无效的。

假设您已经消除了上面的 1. 和 2.,并专注于 3. 这怎么会发生?好吧,我们看不到相关代码(您可以在其中随机交换按钮图像),但我可以想到几种可能性:

您可能会反复从Resources 获取位图。 您调用切换位图的方法可能是创建/设置副本。 您为获取单击按钮的位图而调用的方法可能会返回一个副本。

由于上述每个操作都可能依赖于行为不同的 API 实现(因为 javadoc 允许这样做),因此您的应用程序的行为可能取决于平台。


那么解决办法是什么?

假设,如果您可以找出导致使用不同位图对象的原因,您可能会解决它。然而,虽然您的代码仍然依赖于未指定行为,但它有可能会在其他手机上中断...

更好的解决方案是更改您的应用程序,以便不依赖使用 == 来比较 Bitmap 对象。例如:

为每个按钮关联一个标签。

 button1.setTag("one");
 button2.setTag("two");

创建一个HashMap,将按钮标签映射到该按钮的当前颜色。 HashMap 是应用“模型”状态的一部分。

Map colors = new HashMap();
...
colors.put("one", "red");
colors.put("two", "blue");

当您更改按钮的图像位图时,对地图进行相应的更新。

// After swap the images of button1 and button2 ...
String c1 = colors.get("one");
String c2 = colors.get("two");
colors.put("one", c2);
colors.put("two", c1);

在 onClick 方法中,使用地图查找按钮的当前颜色,而不是尝试通过比较 Bitmap 对象来找出它。

if (colors.get(v.getTag()).equals("red")) 
    // it is red!

(请注意,这与 Biju Parvathy 的建议很接近,但他没有明确说明如何处理按钮颜色/图像的变化。)

【讨论】:

我仍然对为什么我们不能依赖 Bitmap object 比较感到困惑。另外,我只交换图像,而不是实际的按钮,那么如何将HashMapTag 附加到可绘制对象?非常感谢斯蒂芬! 您还没有向我们展示相关代码。但是,很明显,您没有向我们展示的代码中的某些内容是在假设它不应该这样做。例如,javadoc 是否保证当您设置按钮图像然后获取它时,您将获得相同的Bitmap 对象? 好的,所以如果我们假设Bitmap 对象在某种程度上不准确,我如何为每个图像创建一个Hashmap 或为每个按钮创建一个tag。我喜欢你给我的最后一个选项来查看按钮颜色的地图。我怎么做?我实际上并没有切换按钮... “那么如何将 HashMap 或标签附加到可绘制对象上?” - 你没有。 Hashmap 是应用程序状态(模型)的一部分。标签与按钮相关联,而不是与 Drawable 相关联。 您不会为每个图像创建一个 HashMap。请再次阅读我的回答。【参考方案2】:

您可以,我正在对您的比较代码进行一些小改动,以使其适用于所有设备。

Bitmap BitRed = ((BitmapDrawable)getResources().getDrawable(R.drawable.redsquare)).getBitmap();

Bitmap BitClick = ((BitmapDrawable) v.getBackground()).getBitmap();

if (BitClick.sameAs(BitRed)) 
 
    //Your Button with Red Square Clicked

更多详情请参考SameAs函数。 希望对您有所帮助。

【讨论】:

这和我一直在做的有什么不同 == 运算符只检查参考,不会比较位图数据 所以你只是说把 == 改成 =? 我的建议是使用sameAs() 函数进行比较,而不是使用== :) 我们已经知道,SameAs 将比较数据,== 比较参考。我怀疑一些设备供应商可能已经在后台实现了位图缓存,所以当我们调用getBitmap() 时,它总是给我们相同的引用,因此== 对这些设备返回 true。感谢@RuchirBaronia,给了我一个有趣的研究课题。一旦我从官方/可信来源获得可靠信息,我将编辑和更新答案。【参考方案3】:

首先Resources.getDrawable(int) 已弃用,因此您肯定会在一些较新的设备中遇到此类问题。更好的方法是为您要用于该特定按钮的每个可绘制对象使用按钮标签。例如,假设您有 4 个按钮,即按钮 1、按钮 2、按钮 3 和按钮 4。现在假设他们都有一些默认的背景。

让我们说,

button1.setBackgroundResource(R.drawable.default1);
button1.setTag(R.drawable.default1); // set the tag for button same as the drawable id

对所有 4 个按钮执行相同操作

button4.setBackgroundResource(R.drawable.default4);
button4.setTag(R.drawable.default4); // set the tag for button same as the drawable id

现在每次更改按钮的背景/图像时,您也需要更新标签,类似这样

button1.setBackgroundResource(R.drawable.redimage);
button1.setTag(R.drawable.redimage); // set the tag for button same as the drawable id

在您的按钮onClick() 上,您必须简单地使用开关盒来区分不同的标签

@Override
public void onClick(View view) 
    switch (view.getId()) 
        case R.id.button1:
        switch(button1.getTag())
            case R.drawable.default1:
            // do whatever action you want to perform
            break;
            case R.drawable.redimage:
            // do whatever action you want to perform
            break;
        
        break;
        // similarly you can do the same for rest of the buttons.
    

希望这会有所帮助。

【讨论】:

但是按钮并没有移动它的图像 我理解,我没有在任何地方这么说,我只是说,每当您更改图像时,您需要将可绘制的图像设置为按钮的标签,并使用该标签作为区分的基础在 onClick() 中的不同图像之间 我想你还是不明白,标签不过是一些独特的价值,需要附加到每个图像的按钮上。就像在其他答案中一样,他们使用了“一个”和“两个”静态值,如果您为两个不同的图像提供相同的标签/值,这可能会导致错误,因为图像可绘制对于您要设置的每个图像来说都是唯一且不同的您的按钮,这就是为什么我使用该可绘制值作为每个要设置为按钮的图像的标签。如果您仍然不明白,请告诉我。

以上是关于为啥有时这不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 NSAnimationContext completionHandler 不起作用(有时)?

css 为啥有时MARGIN 不起作用,

(这里是极端菜鸟)为啥这个 C 代码不起作用?

为啥非贪心量词有时在 Oracle 正则表达式中不起作用?

如何做一个简单的缩放动画,为啥这不起作用?

为啥 NSPredicate 和 DateComponents 不起作用