首页
网站首页
公司简介
资讯中心
推荐内容
返回顶部
【www.64222.com】图片加载框架的简单设计,在Android中使用Realm作本地存储
发布时间:2020-03-02 02:42
浏览次数:

Android平台有很多的orm框架可以对数据作本地存储,比如ormlite、greenDao、SugarORM等等,这些orm框架基本都是基于sqlite的。今天我要介绍的这个数据库Realm,是用来替代sqlite的一种解决方案,它有一套自己的数据库存储引擎,比sqlite更轻量级,拥有更快的速度,最重要的是跨平台,目前已有Java,Objective C,Swift,React-Native,Xamarin这五种实现。本文是Realm数据库在Android中使用的一个入门级的教程,这里不对Realm与其他的orm框架的优缺点作讨论(这些网上已是一搜一大把)。

标题起得屌了点,文章只能给大家带来理论知识,能不能上天还是得各位亲自实践。文中涉及到很多自己的理解,能力有限,有问题的地方还请指正,文中的参考资料都是精心筛选的,非常值得阅读。

目前Android 发展至今优秀的图片加载框架太多,例如: Volley ,Picasso,Imageloader,Glide等等。但是作为程序猿,懂得其中的实现原理还是相当重要的,只有懂得才能更好地使用。于是乎,今天我就简单设计一个网络加载图片框架。主要就是熟悉图片的网络加载机制。

下载和安装

  • 客户端SVN客户端(TortoiseSVN)下载地址TortoiseSVN安装教程

  • 服务器SVN服务器(VisualSVN Server)下载地址VisualSVN Server安装教程

本文学习目录一.环境配置二.创建实体三.CRUD四.进阶用法

很多人把自定义View想得复杂了,以为有多高深,主要还是没有实践过,没有足够的自信;但也有很多人把自定义View想得简单了,以为摸清View的几个关键回调、知道自定义属性和Android的消息分发机制就算是老司机了,其实对于自定义View来讲,设计、排版、效率都是很费脑筋的,我在github上到现在都没发现一个像样的图文混排自定义View。

一般来说,一个优秀的 图片加载框架(ImageLoader) 应该具备如下功能:

版本说明

  • Android Studio:2.1.3
  • TortoiseSVN:1.9.4
  • VisualSVN Server:3.5.4

一.环境配置

  1. 在项目的build文件加上
buildscript { repositories { jcenter() } dependencies { ... classpath "io.realm:realm-gradle-plugin:1.2.0" } 
  1. 在 app 的 build文件中加入
apply plugin: 'realm-android'

常见的Android自定义View主要有两种类型:

  • 图片压缩
  • 内存缓存
  • 磁盘缓存
  • 图片的同步加载
  • 图片的异步加载
  • 网络拉取

使用教程

www.64222.com 1关联SVN

二.创建实体

Realm 支持的字段类型,除了Java提供的基本类型之外,Realm还支持<code>继承了RealmObject 的对象</code>和<code>RealmList<? extends RealmObject></code>

这里为了方便直接使用了示例项目中的对象了。

创建一个User实体

public class User extends RealmObject { @PrimaryKey private String id; private String name; private int age; private RealmList<User> friends; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge { this.age = age; } public String getId() { return id; } public void setId(String id) { this.id = id; } public RealmList<User> getFriends() { return friends; } public void setFriends(RealmList<User> friends) { this.friends = friends; }}

细心的同学已经注意到了,我们上面创建的实体对象继承于RealmObject ,Realm 数据实体定义需要继承自 RealmObject类。

这里需要知道的几点:

  • <code>@PrimaryKey</code>用来标识主键
  • 默认的所有的字段都会被存储
  • 如果某个字段不需要被存储到本地,则需在在这个字段上面加上<code>@Ignore</code>注解
  • 组合控件:通过Android的基础控件(TextView、CheckBox、Button、ProgressBar等)组合而成,比如试题控件(TextView+VideoGroup)、下拉刷新、瀑布流控件、带左/右滑功能的控件、视频控件等,这种自定义View的难点在于程序的逻辑处理;

  • 完全自定义控件:继承自View、TextureView或SurfaceView,然后重写核心的回调方法,以View为例,按需复写其构造、onMeasure、onLayout、onTouchEvent、onDraw、onAttachedToWindow、onDetachedFromWindow等方法,这种自定义View的难点在于程序的设计、效率优化和排版,比如输入法中的手写控件、图文混排控件(现在很多都是通过webview加载网页实现了)、词典取词控件、图表控件、个性化进度条、弹幕显示控件、Markdown控件、IDE代码编辑控件等。

那我们就从以上几个方面进行介绍:

二、开启版本控制工具

www.64222.com 2开启SVNwww.64222.com 3添加忽略清单www.64222.com 4分享工程到服务器www.64222.com 5提交代码

三.CRUD

数据库的使用无非上就是增删改查这四种操作,其中查是重点,在写原生sql语句中这也是个难点。下面我们就来看看Realm的CRUD是怎样的

RealmConfiguration realmConfig = new RealmConfiguration .Builder .build();Realm realm = Realm.getInstance(realmConfig);

 public void testAdd() { initRealm(); realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { for (int i = 0; i < 10; i++) { User user = realm.createObject(User.class); user.setName("user" + i); user.setAge; user.setId(UUID.randomUUID().toString; } showInTextView("10条数据添加成功"); } }); }

在用Realm进行操作之前需要对Realm作相关的配置操作,Realm中所有的写操作都必须在事务中进行,不然就会报错,记得在Activity的onDestory中调用realm.close()释放资源。上面的代码片段就创建了10个User对象。

  • 查询全部
 public void testQuery() { List<User> users= realm.where(User.class).findAll(); for (User user: users) { showInTextView("id:" + user.getId() + " name:" + user.getName() + " age:" + user.getAge; } }
  • 条件查询,Realm 支持以下查询条件:
    • between()、greaterThan()、lessThan()、greaterThanOrEqualTo() 和 lessThanOrEqualTo()
    • equalTo() 和 notEqualTo()
    • contains()、beginsWith() 和 endsWith()
    • isNull() 和 isNotNull()
    • isEmpty() 和 isNotEmpty()

以下代码片段查询年龄小于15的User

 public void testQueryAgeLessThan15() { List<User> users= realm.where(User.class).lessThan("age", 15).findAll(); for (User user: users) { showInTextView("id:" + user.getId() + " name:" + user.getName() + " age:" + user.getAge; } }
  • 聚合查询,支持的聚合操作有sum,min,max,average以下代码片段得到所有人的平均年龄
public void testQueryAverageAge() { double age = realm.where(User.class).findAll().average; textView.setText("average age:" + age); }

 public void testUpdate() { realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { User user = realm.where(User.class).equalTo("name", "user9").findFirst(); if (user != null) { user.setAge; user.setName; } textView.setText; } }); }

以下代码片段展示了如何删除指定的对象

 public void testDelete() { realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { User user = realm.where(User.class).equalTo("name", "user0").findFirst(); if (user != null) user.deleteFromRealm(); textView.setText; } }); }

按照上面这种方式分只是便于理解,很多时候有些控件既有组合,又需要复写所继承类的回调方法。

1.图片压缩(有效的降低OOM的发生概率)

完成以上五个步骤之后,就可以成功的将AS项目提交到SVN服务器。

欢迎大家访问我的简书,博客和GitHub。

四.进阶用法

通过前面一节的学习,我们基本学会了Realm数据库基本的增删改查操作。本节来看看Realm还有什么其他用法

在实际开发中我们和json打交道的机会比较多,所以直接从json去创建对象是十分有用的,下面的代码片段展示了怎么去用。

private void testAddFromJson() { realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { String json = "{n" + " "id": "uuid1",n" + " "name": "solid",n" + " "age": 20n" + "}"; String jsons = "[n" + " {n" + " "id": "uuid1",n" + " "name": "solid",n" + " "age": 20n" + " },n" + " {n" + " "id": "uuid2",n" + " "name": "jhack",n" + " "age": 21n" + " },n" + " {n" + " "id": "uuid3",n" + " "name": "tom",n" + " "age": 22n" + " }n" + "]"; //realm.createObjectFromJson(User.class, json); realm.createAllFromJson(User.class, jsons); } }); }

开发中数据模型不可能从一开始创建了,就保证后面的开发过程中不会更改,对于Realm如果其中的某个实体类改变了,而我们没有做任何的处理,就会报错,如果还处于应用的开发的初期,这无所谓,直接清空数据即可,但是如果应用已经发布了,我们就需要去寻找一种解决方案了。

这里的解决方案如下:

public class MyMigration implements RealmMigration { @Override public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { Log.e(MainActivity.TAG, "oldVersion:" + oldVersion + " newVersion:" + newVersion); RealmSchema schema = realm.getSchema(); if (newVersion == 2) { schema.get .addField("desc", String.class); } } @Override public boolean equals(Object obj) { return obj instanceof MyMigration; } @Override public int hashCode() { return super.hashCode(); }}

 realmConfig = new RealmConfiguration .Builder .schemaVersion .migration(new MyMigration .build();

Realm原生是支持Rxjava的,由于RxJava 是可选依赖,所以在使用的时候需要在app的build文件中添加RxJava库的依赖,下面是使用的代码片段。

public void testRxJava() { realm.where(User.class).findAll() .asObservable() .flatMap(new Func1<RealmResults<User>, Observable<User>>() { @Override public Observable<User> call(RealmResults<User> users) { return Observable.from; } }) .subscribe(new Action1<User>() { @Override public void call(User user) { showInTextView("id:" + user.getId() + " name:" + user.getName() + " age:" + user.getAge() + " desc:" + user.getDesc; }

这篇文章接到这了,遗憾的是Realm在Windows中没有相关的查看器,只有Mac版的,所以不能直接在Windows中查看Realm数据库中的数据,希望官方后面会有支持吧。更多的资料请查看官方文档。参考文档:realm-java

  • 能够做到基础控件无法做到的效果,为应用的表现增色;

  • 在多个应用并行开发的团队,将公用的交互效果提取成自定义控件,方便复用,减少不必要的重复劳动;

  • 将控件的内部逻辑封装在自定义View中,便于应用内解耦;

图片压缩功能我在Bitmap 的高效加载中已经做了介绍这里不多说直接上代码。这里直接抽象一个类用于完成图片压缩功能。

View、SurfaceView、TextureView的区别

  • View:普通的View,与宿主窗口共享同一个绘图表面,UI在主线程中绘制,在有无硬件加速的情况下都能工作(没有硬件加速的情况下,canvas的有些方法会失效);

  • SurfaceView:继承自View,绘制和显示效率高,因为拥有独立的绘图表面,UI在一个独立的线程中进行绘制,不会占用主线程的资源。SurfaceView的使用和普通的View不一样,需要结合SurfaceHodler一起使用。因为和宿主窗口不是共享同一个绘图表面的原因,笔者在实际使用SurfaceView的过程中发现对其做动画操作会达不到想要的效果;

  • TextureView:继承自View,与SurfaceView相比,TextureView不会创建一个单独的绘图表面,这使得它可以像一般的View一样执行一些变换操作,比如移动、动画等等,但TextureView必须在硬件加速开启的窗口中才能正常工作;

public class ImageResizer { private static final String TAG = "ImageResizer"; public ImageResizer() { super(); // TODO Auto-generated constructor stub } public Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); } public Bitmap decodeSampledBitmapFromBitmapFileDescriptor(FileDescriptor fd, int reqWidth,int reqHeight){ final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFileDescriptor(fd, null, options); options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); options.inJustDecodeBounds = false; return BitmapFactory.decodeFileDescriptor(fd, null, options); } public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { final int width = options.outWidth; final int height = options.outHeight; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > halfWidth) { inSampleSize *= 2; } } return inSampleSize; }}

View的三大核心方法onMeasure、onLayout、onDraw

  • onMeasure:用于测量视图的大小;

  • onLayout:用于给视图进行布局;

  • onDraw:用于对视图进行绘制;

2.内存缓存和磁盘缓存

友情链接: 网站地图
Copyright © 2015-2019 http://www.nflfreepicks.net. 新葡萄京娱乐场网址有限公司 版权所有