2024年安卓最全Android Realm数据库使用(1),Android面试问题和答案技巧,安卓开发者成功指南

最后送福利了,现在关注我可以获取包含源码解析,自定义View,动画实现,架构分享等。
内容难度适中,篇幅精炼,每天只需花上十几分钟阅读即可。
大家可以跟我一起探讨,有flutter—底层开发—性能优化—移动架构—资深UI工程师 —NDK相关专业人员和视频教学资料,还有更多面试题等你来拿

录播视频图.png

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

之后用Realm.getDefaultInstance()取到的就是这个默认配置对应的实例.

数据库迁移


迁移的策略是通过config指定的:

RealmConfiguration config = new RealmConfiguration.Builder() .schemaVersion(2) // Must be bumped when the schema changes .migration(new MyMigration()) // Migration to run instead of throwing an exception .build()

其中MyMigration实现了RealmMigration接口, 在migrate()方法中根据新旧版本号进行一步一步地升级.

具体例子见Migration.

开发的时候为了方便我用的是.deleteRealmIfMigrationNeeded(), 这样在需要数据库迁移的时候直接就删了数据重新开始了.

关于Realm的close()


一个打开的Realm实例会持有一些资源, 有一些是Java不能自动管理的, 所以就需要打开实例的代码负责在不需要的时候将其关闭.

Realm的instance是引用计数的(reference counted cache), 在同一个线程中获取后续实例是免费的, 但是底层的资源只有当所有实例被释放了之后才能释放. 也即你调用了多少次getInstance(), 就需要调用相应次数的close()方法.

比较建议的方法是在Activity或Fragment的生命周期中处理Realm实例的开启和释放:

  • 在Activity的onCreate()getInstance()onDestroy()close().

  • 在Fragment的onCreateView()getInstance()onDestroyView()close().

如果多个Fragment相关的都是同一个数据库实例, 那么在Activity中处理更好一些.

写操作一般的流程是这样:

// Obtain a Realm instance Realm realm = Realm.getDefaultInstance(); realm.beginTransaction(); //… add or update objects here … realm.commitTransaction();

这里创建对象可以用createObject()方法或者copyToRealm()方法.

前者是先创建再set值, 后者是先new对象再更新数据库.

如果不想自己处理beginTransaction()cancelTransaction()commitTransaction(), 可以直接调用realm.executeTransaction()方法:

realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { User user = realm.createObject(User.class); user.setName(“John”); user.setEmail(“john@corporation.com”); } });

异步

因为transactions之间是互相阻塞的.

异步执行可以用这个方法:

realm.executeTransactionAsync(new Realm.Transaction() { @Override public void execute(Realm bgRealm) { User user = bgRealm.createObject(User.class); user.setName(“John”); user.setEmail(“john@corporation.com”); } }, new Realm.Transaction.OnSuccess() { @Override public void onSuccess() { // Transaction was a success. } }, new Realm.Transaction.OnError() { @Override public void onError(Throwable error) { // Transaction failed and was automatically canceled. } });

这两个回调是Optional的, 它们只能在有Looper的线程调用.

注意: 这个方法的返回值对象可以用于在Activity/Fragment生命周期结束的时候取消未完的操作.

删除和更新

所有的写操作都要放在transaction中进行, 如上, 不同的操作只是其中具体方法不同.

删除操作:

final RealmResults users = getUsers(); // method 1: users.get(0).deleteFromRealm(); // method 2: users.deleteFromRealm(0); // delete all users.deleteAllFromRealm();

更新操作:

realm.copyToRealmOrUpdate(obj);

注意: 这个方法需要Model有主键, 会更新obj的主键对应的对象, 如果不存在则新建对象.

查询

查询可以流式地写:

// Or alternatively do the same all at once (the “Fluent interface”): RealmResults result2 = realm.where(User.class) .equalTo(“name”, “John”) .or() .equalTo(“name”, “Peter”) .findAll();

查询条件默认是and的关系, or则需要显式指定.

这个RealmResults是继承Java的AbstractList的, 是有序的集合, 可以通过索引访问.

RealmResults永远不会为null, 当查不到结果时, 它的size()返回0.

查询的线程

基本上所有的查询都是很快进行的, 足够在UI线程上同步进行.

所以绝大多数情况在UI线程上使用findAll()是没有问题的.

如果你要进行非常复杂的查询, 或者你的查询是在非常大的数据集上进行的, 你可以选择异步查询, 使用findAllAsync().

查询条件是一个集合 -> in()

如果想要查询的某一个字段的值是在一个集合中, 比如我有一个id的集合, 我现在想把id在这个集合中的项目全都查出来, 这就可以使用in操作符:

RealmResults toDeleteLists = realm.where(TodoList.class).in(“id”, ids).findAll();

链式查询

查询的时候可以利用link或关系来查询, 比如一个Person类中含有一个RealmList<Dog> dogs的字段.

查询的时候可以这样:

RealmResults persons = realm.where(Person.class) .equalTo(“dogs.color”, “Brown”) .findAll();

利用字段名dogs.来查询一个dog的属性, 再查出拥有这种特定属性dog的人.

但是反向地, 我们能不能查询主人是满足特定属性的人的所有dogs呢? 目前(2017.2.17)这种查询仍是不支持的. 这里有讨论: realm-java-issue-607.

所以两种解决办法: 一是做两次查询; 二是在Dog类的model里加入对Person的引用.

Notifications


可以添加一个listener, 在数据改变的时候收到更新.

public class MyActivity extends Activity { private Realm realm; private RealmChangeListener realmListener; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); realm = Realm.getDefaultInstance(); realmListener = new RealmChangeListener() { @Override public void onChange(Realm realm) { // … do something with the updates (UI, etc.) … }}; realm.addChangeListener(realmListener); } @Override protected void onDestroy() { super.onDestroy(); // Remove the listener. realm.removeChangeListener(realmListener); // Close the Realm instance. realm.close(); } }

注意listener需要在不用的时候删除掉.

可以用这样删除所有的listeners:

realm.removeAllChangeListeners();

Listener不一定要和Realm绑定, 也可以和具体的RealmObject或者RealmResults绑定.

当Listener被调用的时候, 它绑定的对象是自动更新的, 不需要手动刷新.

查看数据库的工具


用Stetho不能直接查看Realm的数据库, 看不到.

需要用这个工具配置一下: stetho-realm.

之后就可以在浏览器中查看Realm的数据库了.

(但是感觉这个工具不是很好用, 有时候不显示数据, 有时候显示的是旧数据.)

也可以用官方提供的Realm Browser来查看, 但是只有Mac版.

如何查看看这里: StackOverflow answer.

实际使用的感想和遇到的问题


优点

  • 建立Model之间的关系很方便也很直接, 查询的时候自动关联了其中的关系.

  • 自动更新(Auto-Updating)的特性很有用, 不用再关心数据的刷新, 只用关心UI的刷新.

比如一旦给Adapter绑定了数据, 之后的数据更新只需要在onChange()里面通知Adapter调用notifyDataSetChanged()即可.

当然我并没有用RealmBaseAdapterRealmRecyclerViewAdapter, 估计这两个更好用, 官方有例子, 这里不再赘述.

缺点

这里有的也不能说是缺点, 只是使用起来觉得不方便的地方.

  • 限制了创建对象和操作对象必须在同一个线程.

违反了这条会报错: java.lang.IllegalStateException: Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.比如我们在UI线程查询出来的对象, 想要异步地删除或者更新, 我们必须在新的线程重新查询.

  • 没有主键自增的功能, 见Issue #469, 需要自己控制主键自增.

  • 从List中删除了一项之后, 最后的一项会移动过来补到被删除的那一项原来的位置. 这是因为人家就是这么设计的stackoverflow. 默认情况下是没有排序的, 数据按照添加的顺序返回, 但是这并不是一种保证, 所以当删除了中间的元素, 后面的会补上这个位置, 以保证底层的数据是放在一起的. 解决办法就是指定一个排序规则.

  • 查询出来的对象不可以临时改变其数据, 否则会报错: java.lang.IllegalStateException: Changing Realm data can only be done from inside a transaction.

  • 不支持反向link的查询. (见前面链式查询部分的介绍).

  • 不支持级联删除. 即从数据库中删除一个对象的时候, 不会删除其中RealmObject子类或RealmList类型的字段在数据库中对应的数据. Issue #1104Issue #2717. 这点也可以理解, 因为model之间的关系可能是多对多的. 所以需要实现级联删除的地方需要手动处理.

  • 测试不方便: RealmResults对象即不能被mock也不能被new; 所有的Model对象也不能被mock. 因为Mockito can only mock non-private & non-final classes.

我的练习Demo:

其他资料:

https://github.com/realm/realm-java

http://www.cnblogs.com/RaphetS/p/5996265.html

最后

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。

最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司20年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

【算法合集】

【延伸Android必备知识点】

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

高级技术PDF文档,BAT大厂面试真题解析】**

[外链图片转存中…(img-tnE60Vm8-1715728596274)]

【算法合集】

[外链图片转存中…(img-V9cP3cF4-1715728596274)]

【延伸Android必备知识点】

[外链图片转存中…(img-OY2pFaOV-1715728596275)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

<think>嗯,用户问的是AD软件中换层的快捷键。首先,我需要确定AD指的是哪个软件。通常,AD可能指Altium Designer,这是一款常用的电子设计自动化软件,用于电路板设计。所以用户可能是在使用Altium Designer时想要快速切换层,提高工作效率。 接下来,我需要回忆或查找Altium Designer中关于层切换的快捷键。根据之前的知识,Altium Designer中确实有一些快捷键用于切换不同的层。比如,小键盘的数字键可能对应不同的层,例如1是Top Layer,2是Mid Layer 1,依此类推。不过,不同版本可能会有些差异,所以需要确认这一点是否正确。 另外,用户可能还不太清楚如何自定义这些快捷键,或者是否有其他方式快速换层。比如,使用快捷键L调出层设置面板,或者通过Preferences设置自定义快捷键。这可能是用户潜在的需求,想要更灵活地调整快捷键以适应自己的习惯。 还要考虑用户可能的操作环境,比如是否在使用英文版软件,或者是否有安装不同版本的Altium Designer,因为不同版本快捷键可能不同。此外,用户可能对层的概念不太熟悉,比如信号层、电源层、丝印层等,是否需要简要解释这些层的用途,以帮助用户更好地理解换层的意义。 另外,是否有其他相关功能,比如切换层的同时切换走线层,或者如何在多层板中快速跳转,这些也可能是用户需要的信息。比如在布线时按数字键切换层并自动添加过孔,这样的操作是否可行,需要确认正确性。 总结一下,回答需要包括: 1. 常用默认快捷键,如小键盘数字键对应各层。 2. 如何通过快捷键L打开层设置面板。 3. 自定义快捷键的方法。 4. 可能需要注意的版本差异或操作细节。 5. 简要说明层的类型用途,帮助用户理解为何需要换层。 需要确保信息准确,避免错误,比如Altium Designer是否真的使用小键盘数字键作为默认切换层的快捷键。可能需要查阅官方文档或可靠来源确认。此外,提醒用户如果快捷键不起作用,可能需要检查键盘设置或软件版本,确保兼容性。 最后,组织回答时要结构清晰,分点说明,便于用户理解。如果有不确定的地方,建议用户参考软件帮助文档或官方资源,以确保信息的正确性。</think>在 Altium Designer(AD)中,**换层快捷键**是提高 PCB 设计效率的重要工具。以下是常用操作说明: --- ### 一、默认快捷键 1. **小键盘数字键** - 按下数字键 **1~6** 可快速切换至对应信号层(例如:1=Top Layer,2=Mid Layer 1,依此类推)。 - **+/- 键**:切换至下一层/上一层(需开启小键盘的 Num Lock)。 2. **信号层与平面层切换** - **Shift+Ctrl+鼠标滚轮**:按住后滚动滚轮可快速切换层(需按住快捷键)。 3. **特殊层快捷键** - **L**:打开层设置面板(快速启用/禁用层显示)。 - **Ctrl+Shift+G**:切换到丝印层(Top Overlay)。 - **Ctrl+Shift+M**:切换到阻焊层(Top Solder Mask)。 --- ### 二、自定义快捷键 1. 通过 **Preferences > PCB Editor > Shortcuts** 修改快捷键。 2. 搜索功能关键词(如 `Layer Next`、`Layer Previous`)绑定自定义按键。 --- ### 三、实用技巧 1. **布线时自动换层**: 布线过程中按下对应层数字键,软件会自动添加过孔并切换至目标层。 2. **层高亮显示**: 按 **Shift+S** 进入单层模式,按层数字键可快速高亮特定层。 --- ### 四、注意事项 - 不同版本快捷键可能略有差异,建议通过 **Help > Shortcuts** 确认当前版本设置。 - 若快捷键失效,检查键盘输入法或软件冲突。 如果需要更详细的层管理(如创建/删除层),可通过 **Design > Layer Stack Manager** 操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值