我的应用程序(游戏)的主菜单使用标准的Android按钮.它在我的所有设备上运行良好,除了使用Android 4.4.2的Nexus 7.问题如下:
在以下任何一种情况下,按钮的文本突然消失:
setEnabled(boolean)
在按钮上调用例如,如果我按下"加载游戏",则在按下事件期间按钮会正确突出显示,但"加载游戏"会完全消失(该按钮具有空文本).
如果我删除所有自定义样式和行为,并仅使用默认字体等默认Android按钮,则问题仍然存在.
如果我将targetSdkVersion减少到18(从19),即使在Nexus 7上一切正常.
知道KitKat在这方面有什么变化吗?我没有发现任何可疑的东西.
我的revalant XML代码:
<TableLayout
android:id="@+id/layoutGameMainmenu"
android:layout_width="wrap_content"
android:layout_height="83dip"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:orientation="vertical"
android:gravity="center_vertical"
android:visibility="gone" >
<TableRow>
<Button
android:id="@+id/buttonLoadGame"
android:layout_width="174dip"
android:layout_height="40dip"
android:layout_marginBottom="2dip"
android:layout_marginRight="30dip"
android:background="@drawable/button_gamemainmenu"
android:text="buttonLoadGame"
android:textColor="@color/button_gamemainmenu_text"
android:textScaleX="0.9"
android:textSize="16dp" />
<Button
android:id="@+id/buttonSettings"
android:layout_width="174dip"
android:layout_height="40dip"
android:layout_marginBottom="2dip"
android:layout_marginLeft="30dip"
android:background="@drawable/button_gamemainmenu"
android:text="buttonSettings"
android:textColor="@color/button_gamemainmenu_text"
android:textScaleX="0.9"
android:textSize="16dp" />
</TableRow>
<TableRow>
<Button
android:id="@+id/buttonStartGame"
android:layout_width="174dip"
android:layout_height="40dip"
android:layout_marginBottom="1dip"
android:layout_marginRight="30dip"
android:background="@drawable/button_gamemainmenu"
android:text="buttonStartGame"
android:textColor="@color/button_gamemainmenu_text"
android:textScaleX="0.9"
android:textSize="16dp" />
<Button
android:id="@+id/buttonQuit"
android:layout_width="174dip"
android:layout_height="40dip"
android:layout_marginBottom="1dip"
android:layout_marginLeft="30dip"
android:background="@drawable/button_gamemainmenu"
android:text="buttonQuit"
android:textColor="@color/button_gamemainmenu_text"
android:textScaleX="0.9"
android:textSize="16dp" />
</TableRow>
</TableLayout>
Run Code Online (Sandbox Code Playgroud)
关于上述代码的重要说明: …
Java虚拟机也可以int
对short
字段使用-sized width (这取决于它们的内部实现).只有数组(short[]
)是例外,它总是保证它们占用的空间比int[]
内部空间少.Dalvik怎么样?
例如,我有一个包含50个字段的类short
.有时在我的应用程序中,存在10000个这样的类.这意味着short
字段应该使用1MB的内存,但如果 Dalvik在short
内部使用4个字节的值,那么这将是2MB的内存使用量.
我应该期待Dalvik使用多少内存?(这是指它的内部内存使用,我知道它可能不会被系统内存使用所反映,例如因为Dalvik已经从系统中预留了更多的内存.)
我使用CountDownLatch来等待来自另一个组件的某个事件(在不同的线程中运行).以下方法适合我的软件的语义,但我不确定它是否像我期望的那样工作:
mCountDownLatch.await(3000, TimeUnit.MILLISECONDS)
otherComponent.aStaticVolatileVariable = true;
mCountDownLatch.await(3500, TimeUnit.MILLISECONDS);
... <proceed with other stuff>
Run Code Online (Sandbox Code Playgroud)
方案应该如下:我等待3秒钟,如果锁存器没有倒计数到0,我用该变量通知另一个组件,然后我等待最多3.5秒.如果再次出现超时,那么我不在乎并将继续进行其他操作.
注意:我知道它看起来不像那样,但上面的场景在我的软件中是完全合理且有效的.
我确实阅读了await(int,TimeUnit)和CountDownLatch的文档,但我不是Java/Android专家,所以我需要确认.对我来说,所有场景看起来都有效:
我正确使用等待(...)吗?即使先前await(...)在同一个对象上超时,也能以上述方式使用第二个等待(...)吗?
如果我读完一篇关于多线程的完整章节/书,我就能找到答案,但我想要一个更快的答案.(我知道这个 stackoverflow问题类似,但还不够.)
假设有这个类:
public class TestClass {
private int someValue;
public int getSomeValue() { return someValue; }
public void setSomeValue(int value) { someValue = value; }
}
Run Code Online (Sandbox Code Playgroud)
有两个线程(A和B)访问此类的实例.请考虑以下顺序:
如果我是对的,someValue必须是volatile,否则第3步可能不会返回最新值(因为A可能有缓存值).它是否正确?
第二种情况:
在这种情况下,A将始终获得正确的值,因为这是它的第一次访问,因此他还没有缓存值.这是正确的吗?
如果只以第二种方式访问类,则不需要volatile/synchronization,或者是它?
请注意,此示例已简化,实际上我想知道复杂类中的特定成员变量和方法,而不是整个类(即哪些变量应该是volatile或具有同步访问权限).重点是:如果更多线程访问某些数据,是否需要通过所有方式进行同步访问,还是取决于它们访问它的方式(例如顺序)?
阅读评论后,我尝试用另一个例子来说明我的困惑的来源:
threadA.start()
getSomeValue()
,并通知UI线程threadB.start()
setSomeValue()
,并通知UI线程getSomeValue()
这是一个完全同步的结构,但为什么这意味着threadA将在步骤6中获得最新的值?(如果someValue
不是易失性的,或者从任何地方访问时都不会放入监视器)
如果我预加载某些图像,在我的应用程序中是有利的.我这样做是正确的,在的AsyncTask,因为它是书面的正式文档.但是我有一个关于何时应该设置的问题/疑问.
我将展示代码片段.需要注意的是它简化了(他们的互操作性是我真正的代码更好,它会检查空值,等等).
让我们先看看原始(非预装)版本:
<ImageView
android:id="@+id/imageViewMyGraphicalImageElement"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="centerCrop"
android:src="@drawable/my_graphical_element" >
</ImageView>
Run Code Online (Sandbox Code Playgroud)
预加载版本具有以下XML(请注意缺少src属性):
<ImageView
android:id="@+id/imageViewMyGraphicalImageElement"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="centerCrop">
</ImageView>
Run Code Online (Sandbox Code Playgroud)
以及预装代码的片段:
sBitmap = bitmapBitmapFactory.decodeResource(context.getResources(), R.drawable.my_graphical_element, options);
// 'sBitmap' is a Bitmap reference, while 'options' is BitmapFactory.Options
Run Code Online (Sandbox Code Playgroud)
最后,我设置它的地方:
setContentView(R.layout.main);
...
ImageView imageViewMyGraphicalImageElement= (ImageView) findViewById(R.id.imageViewMyGraphicalImageElement);
imageViewMyGraphicalImageElement.setImageBitmap(sBitmap);
Run Code Online (Sandbox Code Playgroud)
问题:显然,基于xml的解决方案在调用setContentView(...)之前知道图像.预加载版本在该调用之后设置图像.有什么区别吗?由于这个原因,是否可以跳过某些自动缩放或系统完成的其他事情?
有时我需要醒来或发送一个单独的线程,我想知道什么是最好和最有效的方法.
第一个解决方案是信号结合wait-notify
(我知道如何正确实现这种模式,这不是问题).
我在某处读到了使用java.concurrent库和CountDownLatch
信令的效率更高.我也检查了concurrent.locks.Condition,但是这个主题声明它只是一个(程序员方面的)更安全和通用的结构,与之相比没有性能优势notify/notifyAll
.彼得Lawrey建议使用并发库,而不是notify-notifyAll
在这个意见,所以现在我感到困惑的是要使用的最佳实践.
一个相关的问题:哪个性能更好,notify
或者notifyAll
在我的情况下(即如果我有一个线程)?我知道有很多类似的线索,但没有一个给出明确的答案.在我的情况下,功能上,我使用哪个并不重要,但我想知道哪个更快.
我知道有很多这方面的主题和资源,但我想知道一个非常具体的问题(可能需要很长时间才能检查所有来源以获得明确答案).
我知道JVM/Dalvik保证当你访问类的静态字段时(final static
原始值除外),类的静态字段已经初始化.反之亦然吗?如果我从来没有在所有访问类(例如,因为switch-case
在另一个静态方法的代码永远不会达到一定的分支),是它保证了虚拟机并没有初始化这个类的静态?
假设我有一个这样的类:
public class Boo {
public static int[] anything = new int[] { 2,3,4 };
private static int[] something = new int[] { 5,6,7 }; // this may be much bigger as well
public static final int[] getAndClear() {
int[] st = something;
something = null;
return st;
}
}
Run Code Online (Sandbox Code Playgroud)
我的应用程序是一个非常特殊的应用程序(在某些方面不典型),并且它可能包含数百个类,例如Boo
(由代码生成器生成),其中something
可能是不同元素计数的数组(因此它可能包含很多元素,如好吧有时候).
根据应用程序输入,许多这些预生成的类可能永远不会被访问.我不希望很多int[]
对象被不必要地初始化,占用大量内存.
我知道 UI 元素(视图层次结构)只能从 UI 线程进行操作。对于后台操作,可以使用 AsyncTask,它提供事件处理程序以到达 UI 线程。
简而言之,是否允许getApplicationContext()
在非 UI 线程中实例化 View(绑定到)?这个自定义 View 后代 - 一旦实例化 - 从UI 线程添加到视图层次结构。所以只有构造函数调用是在Asynctask.doInBackground()
; 中完成的。它将 ( addView(...)
)附加到 Activity 的根布局层次结构仍然在 UI 线程中完成。
详细说明:
public MyView extends View {
public MyView(Context context) {
...
}
...
}
Run Code Online (Sandbox Code Playgroud)
我做了一个自定义视图,覆盖onDraw(...)
等。
当用户在我的主 Activity 中单击某个 MenuItem 时,会创建另一个 Activity (MyOtherActivity) 并显示哪个屏幕正是 MyView
由于必须立即显示 MyOtherActivity 的屏幕,因此我在 AsyncTask 中预先实例化 MyView,而用户在主 Activity 中的其他位置(即他还没有单击该 MenuItem)。MyView 引用存储在静态数据成员中。
当MyOtherActivity.onCreate()
被调用时,它的构造函数代码从静态中获取 MyView,并通过addView(...)
.
(我知道静态变量可能会导致内存泄漏,因此我将其设置为null
不需要时。)
MyView …
我被分配了扩展软件的某个组件(由其他人编写).它是用Android编写的,完全用Java编写(没有我知道的本机/ c ++组件).
熟悉代码时,我遇到了一个方法(渲染类的绘图方法).该方法涉及一个更新对象的大循环(然后另一个方法将在以后呈现它们).该方法的创建者似乎在循环之前将所有/大多数成员变量和数组以及其他对象的字段缓存到局部变量中.代码看起来像这样:
float[] coordArr = mCoordArr;
float[] texCoordArr = mTexCoordArr;
float[] cArray = mColArray;
// ... there are further locals too, I didn't copy all here
float[] color = mColor;
float r = color[0];
float g = color[1];
float b = color[2];
float a = color[3];
int texw = mTexW;
int texH = mTexH;
Font font = mFont;
float[] ccords = font.ccords;
float cf = font.cf;
float cu = font.cu;
int len = mCurLength;
// Update …
Run Code Online (Sandbox Code Playgroud) 我反编译了 Java(实际上是 Dalvik)字节码。在方法的开头,我直接访问实例成员的字段(即不通过 getter)。
似乎 Java 调用Object.getClass()
了访问的实例成员 ( mOther
),但没有在任何地方使用结果。这是某种检查吗?为什么需要这个电话?我怀疑这是因为我直接访问了一个字段(在该类中定义),但我没有看到连接。
Java代码和反编译后的字节码如下。
(请注意,最后一条指令lifeTime
作为常量加载,0x0001
因为 in MyOtherClass
,我有lifeTime
一个public final
字段,并且当前是从代码初始化的。)
MyOtherClass other = mOther;
if (mAge >= other.lifeTime) { // lifeTime is initialized to 0x0001
end();
return;
}
.line 53
move-object/from16 v0, p0
iget-object v0, v0, Lcom/example/engine/MyClass1;->mOther:Lcom/example/engine/MyOtherClass;
move-object/from16 v16, v0
.line 54
.local v16, other:Lcom/example/engine/MyOtherClass;
move-object/from16 v0, p0
iget v0, v0, Lcom/example/engine/MyClass1;->mAge:I
move/from16 v18, v0
// Why is Object->getClass() called?
invoke-virtual/range {v16 .. v16}, …
Run Code Online (Sandbox Code Playgroud) android ×10
java ×10
dalvik ×4
performance ×2
android-ui ×1
android-view ×1
button ×1
bytecode ×1
drawable ×1
volatile ×1