我正在构建类似于Google Hangouts聊天界面的界面.新消息将添加到列表底部.向上滚动到列表顶部将触发先前消息历史记录的加载.当历史从网络进入时,这些消息将添加到列表的顶部,并且不应从触发负载时用户已停止的位置触发任何类型的滚动.换句话说,列表顶部显示"加载指示符":
然后将其替换为任何已加载的历史记录.
我完成了所有这些工作......除了一件我不得不诉诸于反思的事情.当向连接到ListView的适配器添加项目时,有很多问题和答案涉及仅保存和恢复滚动位置.我的问题是当我做类似以下的事情时(简化但应该是不言自明的):
public void addNewItems(List<Item> items) {
final int positionToSave = listView.getFirstVisiblePosition();
adapter.addAll(items);
listView.post(new Runnable() {
@Override
public void run() {
listView.setSelection(positionToSave);
}
});
}
Run Code Online (Sandbox Code Playgroud)
然后用户将看到的是快速闪烁到ListView的顶部,然后快速闪回到正确的位置.这个问题很明显,并且被很多人发现:setSelection()
直到之后notifyDataSetChanged()
重新开始并且不重要ListView
.所以我们必须要有post()
机会画画.但那看起来很糟糕.
我通过使用反射来"修复"它.我讨厌它.在其核心,就是我要完成的任务是重置的第一位置ListView
,而无需通过抽奖周期的rigamarole下去,直到后,我给自己定的位置.要做到这一点,ListView有一个有用的领域:mFirstPosition
.通过gawd,这正是我需要调整的!不幸的是,它是包私有的.还不幸的是,似乎没有任何方式以编程方式设置它或以任何不涉及无效循环的方式影响它...产生丑陋的行为.
因此,反映失败的后备:
try {
Field field = AdapterView.class.getDeclaredField("mFirstPosition");
field.setAccessible(true);
field.setInt(listView, positionToSave);
}
catch (Exception e) { // CATCH ALL THE EXCEPTIONS </meme>
e.printStackTrace();
listView.post(new Runnable() {
@Override
public void run() {
listView.setSelection(positionToSave);
}
}); …
Run Code Online (Sandbox Code Playgroud) 我正在尝试通过 Dagger 2 学习 DI 并将其应用到我们的产品中。注释的应用程序级别的东西@Singleton
非常简单(例如SharedPreferences
)。在考虑我们的架构时,有几个本质上是异步的依赖项,我想象它们的范围@ForSession
。
AccountManager
。在现有有效会话的情况下可以是同步的。如果没有现有会话,并且AccountManager
必须显示完整的登录流程,则可能是异步的。Endpoint
来满足依赖关系,以便我们的网络层知道在哪里可以找到 API。Service
。Service
仅当绑定完成 时才异步提供该组件。表示层应在收到这些项目的集合后进行门控。除了某种“正在加载”显示之外,如果没有上述任何一项,它就无能为力。
感觉这些依赖项适合 和 的用@ProducerModule
例@Produces
。我觉得我可以@Produces ListenableFuture<>
为每个依赖项提供方法,也许可以使用 aSettableFuture<>
作为实现。执行任何需要的工作,呼唤set()
未来,依赖性得到满足。
我感到不安的地方是《制作人指南》中的这句话。
正如上面的例子,生产者模块可以与普通模块无缝使用,但受到提供类型不能依赖于生产类型的限制。
对于“所有可用的东西的门演示”,我可以设想一个复合对象,可以@Inject
通过打开T
期货来获得。但这合法吗?
这是我最接近的,但它显式调用复合材料的构造函数,而不是注入它。有没有办法做到这一点清洁?
@ProducerModule
public class SessionModule {
@Produces
@ForSession
static ListenableFuture<User> produceSignedInUser(SessionManager sessionManager) {
return sessionManager.getSignedInUserFuture();
}
@Produces
@ForSession …
Run Code Online (Sandbox Code Playgroud)