我正在研究用Kotlin编写的游戏,并正在研究改进GC流失.流失的主要来源之一是在主游戏/渲染循环中调用的for循环,导致迭代器的分配.
谈到文档,我发现了这一段:
数组上的for循环被编译为基于索引的循环,该循环不会创建迭代器对象.
如果要迭代数组或带索引的列表,可以这样做:
for (i in array.indices)
print(array[i])
Run Code Online (Sandbox Code Playgroud)
请注意,这种"通过范围的迭代"被编译为最佳实现,而不创建额外的对象.
https://kotlinlang.org/docs/reference/control-flow.html#for-loops
这是真的吗?为了验证,我采用了这个简单的Kotlin程序并检查了生成的字节代码:
fun main(args: Array<String>) {
val arr = arrayOf(1, 2, 3)
for (i in arr.indices) {
println(arr[i])
}
}
Run Code Online (Sandbox Code Playgroud)
根据上面的引用,这不应该导致分配任何对象,而是编译成一个很好的旧的Java-5前样式for循环.但是,我得到的是这样的:
41: aload_1
42: checkcast #23 // class "[Ljava/lang/Object;"
45: invokestatic #31 // Method kotlin/collections/ArraysKt.getIndices:([Ljava/lang/Object;)Lkotlin/ranges/IntRange;
48: dup
49: invokevirtual #37 // Method kotlin/ranges/IntRange.getFirst:()I
52: istore_2
53: invokevirtual #40 // Method kotlin/ranges/IntRange.getLast:()I
56: istore_3
57: iload_2
58: iload_3
59: if_icmpgt 93
Run Code Online (Sandbox Code Playgroud)
这看起来好像调用了一个调用的方法,该方法getIndices分配一个临时IntRange对象来备份此循环中的边界检查.这是一个"最佳实现","没有创建额外的对象",或者我错过了什么?
更新: 所以,经过多一点玩弄并查看答案之后,Kotlin 1.0.2似乎也是如此:
阵列:
for …我很好奇在Kotlin中定义成员函数的建议方法是什么.考虑这两个成员函数:
class A {
fun f(x: Int) = 42
val g = fun(x: Int) = 42
}
Run Code Online (Sandbox Code Playgroud)
这些似乎完成了同样的事情,但我发现了微妙的差异.
在val基础的定义,举例来说,似乎是在某些情况下更加灵活.也就是说,我无法通过直接的方式f与其他功能合作,但我可以g.为了玩弄这些定义,我使用了funKTionale库.我发现这不编译:
val z = g andThen A::f // f is a member function
Run Code Online (Sandbox Code Playgroud)
但如果f被定义为val指向同一个函数,它就会编译得很好.为了弄清楚发生了什么事情,我问的IntelliJ明确定义的类型::f和g对我来说,和它给了我这样的:
val fref: KFunction1<Int, Int> = ::f
val gref: (Int) -> Int = g
Run Code Online (Sandbox Code Playgroud)
所以一个是类型KFunction1<Int, Int>,另一个是类型(Int) -> Int.很容易看出它们都代表了类型的功能Int -> Int.
这两种类型有什么区别,哪些情况重要?我注意到对于顶级函数,我可以使用任何一个定义来编写它们,但是为了使前面的组合编译,我必须像这样编写它:
val z = g …Run Code Online (Sandbox Code Playgroud) 我有一个特定的问题,如何在Android中运行类加载/垃圾收集.我们现在偶然发现了几次这个问题,据我所知,Android在这里与普通的JVM不同.
问题在于:我们目前正在尝试减少应用程序中的单例类,以支持单个根工厂单例,其唯一目的是管理其他管理器类.如果你愿意的话,是一名顶级经理.这使我们可以轻松地替换测试中的实现,而无需选择完整的DI解决方案,因为所有活动和服务共享对该根工厂的相同引用.
这是它的样子:
public class RootFactory {
private static volatile RootFactory instance;
@SuppressWarnings("unused")
private Context context; // I'd like to keep this for now
private volatile LanguageSupport languageSupport;
private volatile Preferences preferences;
private volatile LoginManager loginManager;
private volatile TaskManager taskManager;
private volatile PositionProvider positionManager;
private volatile SimpleDataStorage simpleDataStorage;
public static RootFactory initialize(Context context) {
instance = new RootFactory(context);
return instance;
}
private RootFactory(Context context) {
this.context = context;
}
public static RootFactory getInstance() {
return instance;
}
public LanguageSupport getLanguageSupport() …Run Code Online (Sandbox Code Playgroud) 假设我有一个可序列化的Java Bean对象.我想它存储起来安全当活动经过的onDestroy()的目的(即的onSaveInstanceState()是不叫).
我正在寻找一种不涉及创建数据库并将对象写入其中的方法(主要是因为a)Android的DB API非常糟糕b)因为数据库使应用程序更新成为一场噩梦,因为没有适当的支持来应用迁移).
我想到将对象序列化为ByteArrayOutputStream,base64编码并将其作为字符串写入SharedPreferences文件.还是那太远了?
UPDATE
也许那个序列化到字符串的想法毕竟不是那么糟糕,似乎运作得很好.这就是我现在正在做的事情:
public static String objectToString(Serializable object) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
new ObjectOutputStream(out).writeObject(object);
byte[] data = out.toByteArray();
out.close();
out = new ByteArrayOutputStream();
Base64OutputStream b64 = new Base64OutputStream(out);
b64.write(data);
b64.close();
out.close();
return new String(out.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static Object stringToObject(String encodedObject) {
try {
return new ObjectInputStream(new Base64InputStream(
new ByteArrayInputStream(encodedObject.getBytes()))).readObject();
} catch (Exception e) {
e.printStackTrace();
}
return null;
} …Run Code Online (Sandbox Code Playgroud) 我浏览了他们的文档,一开始发现它有点压倒性.我知道您可以通过输入UPC(低于1D条形码的数字)来搜索项目,但我在API中找不到关于它的单词.
我想要做的是在扫描条形码后通过执行UPC搜索来执行产品查找.
直到最近,我们的应用程序在整个应用程序中使用ThreadSafeClientConnManager共享一个Apache HttpClient实例.http客户端实例由单例类保存.
由于我不喜欢单例模式存在的众多问题,我将我的API访问器重构为每线程对象,但现在对于每个线程(在我们的情况下主要是指每个Activity/Service),都会创建一个新的HttpClient实例.
这不是我对这种新方法有问题,但我已经读过Apache人员建议每个应用程序只有一个实例出于性能原因.
在视觉上,我们之前做的是:
HttpClient (thread safe)
|
|
/\
/ \
Activity1...ActivityN
Run Code Online (Sandbox Code Playgroud)
现在,我们这样做:
Activity1 ... ActivityN
| |
| |
HttpClient1 HttpClientN
Run Code Online (Sandbox Code Playgroud)
你们是如何在你的应用程序中做到这一点的?如果您在应用程序和可能有多个并发线程之间共享一个HttpClient,那么如何处理对它的访问?
我必须在这里遗漏一些东西.JavaDoc ActivityUnitTestCase建议此测试用例与系统隔离测试一个Activity:
此类提供单个活动的独立测试.将使用与系统基础结构的最小连接来创建测试中的活动,并且可以注入许多Activity的依赖项的模拟或包装版本.
我假设包括没有实际启动应用程序.此外,它暴露了setApplication一个可以用来注入模拟应用程序的助手.
但是,任何ActivityUnitTestCase我开始启动(实际)应用程序并调用其onCreate方法.更准确地说,InstrumentationTestRunner似乎是这样做,甚至在我有机会进入setApplication我的测试setUp方法之前就这样做了!我甚至没有注意到这一段时间,因为它似乎发生在测试套件启动期间甚至没有达到Eclipse断点的地方,但写入日志onCreate显示它实际上被调用.
这完全超出了我的范围.当Android的测试运行器实例化并执行实际应用程序时,为什么我要使用模拟应用程序对象?考虑到instrumentation runner在其自己的线程中运行,并且在执行此操作时生成主应用程序线程,这甚至更成问题.这意味着正在执行的测试和Application.onCreate被调用之间存在竞争条件.如果你在那里做任何可能影响测试的事情,例如写入共享偏好文件,那么你就完全搞砸了,因为你的测试会随机失败.
我是否遗漏了某些内容,或者这只是对测试框架的严重疏忽?
更新
这似乎ApplicationTestCase也会影响.在我的测试用例开始之前,我可以在我的应用程序类中找到一个断点onCreate.我们在那里启动了一个即发即弃的AsyncTask,它会随机失败,因为我没有机会嘲笑它(记住,之前setUp在我的测试用例中调用它).这是我在onCreate这个模糊的调用过程中看到的堆栈跟踪:
Thread [<1> main] (Suspended (breakpoint at line 86 in QypeRadar))
QypeRadar.onCreate() line: 86
InstrumentationTestRunner(Instrumentation).callApplicationOnCreate(Application) line: 969
ActivityThread.handleBindApplication(ActivityThread$AppBindData) line: 4244
ActivityThread.access$3000(ActivityThread, ActivityThread$AppBindData) line: 125
ActivityThread$H.handleMessage(Message) line: 2071
ActivityThread$H(Handler).dispatchMessage(Message) line: 99
Looper.loop() line: 123
ActivityThread.main(String[]) line: 4627
Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method] …Run Code Online (Sandbox Code Playgroud) 在ApiDemos中,有一个名为Gallery1的视图示例,它在attrs.xml中声明了一个自定义样式,如下所示:
<declare-styleable name="Gallery1">
<attr name="android:galleryItemBackground" />
</declare-styleable>
Run Code Online (Sandbox Code Playgroud)
现在,我想为我的小部件做同样的事情,但使用不同的命名空间.但是,只要我用其他东西替换android:名称空间,我就会收到此错误:
错误:在Gallery1中,无法找到属性myns:galleryItemBackground
无法找到属性?为什么它要查找我要声明的属性?这个文件的重点不是能够命名自己的自定义属性吗?
有趣的是,如果您不提供自定义命名空间,而只是提供属性名称,则它可以正常工作.
对于我们的应用程序的下一个版本,我想更改sharedUserId,因为我们现在使用内部控制仪表板应用程序,该应用程序必须写入其他应用程序的设置文件.
但由于该应用程序已安装在许多手机上,这是一个问题吗?我在模拟器上运行了一些测试,我在设备日志中看到了无法写入*.bak版本的首选项文件的例外情况.不确定是多么重要.奇怪的是,即使使用另一个Linux用户ID创建了shared_prefs文件夹,安全设置似乎仍然有效.
有没有人以前尝试过这个?
我经常遇到一个问题,我必须在一个活动的几次调用之间保持状态(即经历几个onCreate()/ onDelete()循环).不幸的是,Android对此的支持非常糟糕.
作为一种保存状态的简单方法,我认为由于类只被类加载器加载一次,因此在静态Bundle字段中存储在活动的多个实例之间共享的临时数据是安全的.
但是,偶尔,当实例A创建静态包并在其中存储数据,然后被销毁,而实例B尝试从中读取时,静态字段突然变为NULL.
这是否意味着当活动进行创建/销毁循环时,类已被类加载器删除并重新加载?在以前引用对象时,静态字段怎么会突然变为NULL?
android ×7
classloader ×2
java ×2
kotlin ×2
singleton ×2
barcode ×1
concurrency ×1
lifecycle ×1
static ×1
unit-testing ×1
userid ×1
widget ×1