Realm-基础使用(一)

版权声明:小哥哥小姐姐 欢迎关注csdn 小凡爱碧瑶 https://blog.csdn.net/Aiction/article/details/89887518

1. 依赖配置和初始化

  • project level build.gradle:
buildscript {
    
	...
    dependencies {
        ...
        classpath "io.realm:realm-gradle-plugin:5.9.0"
       
    }
}
...
  • app module level build.gradle:
apply plugin: 'realm-android'
...
dependencies {
       implementation 'io.realm:android-adapters:2.1.1'
   
   ...

}

android-adapters 这个包分装了一个RecycleView.Adpter,监听了数据的变化 处理了增删改的notifyChange事件,你可以自己分装一个.

2. 全局初始化

  • 在你的自定义application初始化:
private void initRealm() {
        Realm.init(libInterface.provideContext());
        RealmConfiguration.Builder builder = new RealmConfiguration.Builder()
                .name("app.realm")
                .schemaVersion(1)               // TODO: 数据库版本号
                .migration(new MyMigration());

        if (BuildConfig.DEBUG) {
            builder.deleteRealmIfMigrationNeeded();
        }
        Realm.setDefaultConfiguration(builder.build());
    }
    
    class MyMigration implements RealmMigration {
    @Override
    public void migrate(@NonNull DynamicRealm realm, long oldVersion, long newVersion) {

    }
}

MyMigration这个类是数据库升级的时候的迁移类用来改变数据库的schema ,通过**schemaVersion(1)**来改变数据库升级.

当你增加RealmObject或者增加 删减 所有和RealmObject相关的配置改变的时候都需要处理是迁移呢还是配置**builder.deleteRealmIfMigrationNeeded()**来直接删除全部数据库文件来重新创建.

一般情况,开发的时候配置 :

if (BuildConfig.DEBUG) {
    builder.deleteRealmIfMigrationNeeded();
}

直接删除数据库文件重新创建.

如果是升级app的时候,缓存的数据库数据是必须保留的,比如登录的用户信息userId ,token,那么你需要配置你的MyMigration类,来进行数据库升级.

3. 配置全局realm实例和全局数据库监听

  • 在application中:
mGlobalRealm = Realm.getDefaultInstance();

保留一份realm实例,为了ui线程的使用.(Realm实例只能在创建realm实例的本线程中使用,ui线程中就创建这一个全局使用就行了,没必要一直创建);

realm实例创建后,使用完毕必须关闭.

对于application中创建的实例:

    @Override
	public void onTerminate() {
        mGlobalRealm.close();
        super.onTerminate();
    }
  • 全局监听数据库,处理上传参数请求失败的重试和下载数据成功的监听

上传参数请求(如微信聊天记录):

//这是微信消息体,需要上传到服务器的一些数据参数,图片语音视频 涉及到文件的上传需求是先上传文件,把返回的md5或者Url路径放到消息的一个参数里面再上传消息体
//其中有重试次数和成功失败的一些标志位.

//当接收到微信消息的时候,直接realm.insert()进去 (realm的所有写操作都要开启事务哦).

public class WxMessageEntity extends RealmObject {
    // 收消息
    public static final int GET = 0;
    // 发消息
    public static final int POST = 1;

    public static final int NORMAL_TXT = 1;
    public static final int VISIBLE_SELF_ONLY = 10000;
    public static final int REVOKE_MESSAGE = 10002;
    public static final int READ_MESSAGE = -10002;
    public static final int PIC = 3;
    public static final int VOICE = 34;
    public static final int BUSINESS_CARD = 42;
    public static final int VIDEO = 43;
    public static final int FACE = 47;
    public static final int LOCATION = 48;
    public static final int FILE = 49;
    public static final int LINK = -49;
    public static final int TRANS_MONEY = 419430449;
    public static final int LUCKY_MONEY = 436207665;
    public static final int CHATROOM_SYSTEM_MESSAGE = 570425393;
    public static final int SHARE_LOCATION = -1879048186;

    private long msgId;
    private long msgSvrId;
    private String talker;
    private String userId;
    private String chatRoomTalker;
    private int isSend;
    private int type;
    private String content;
    private String imgPath;//0b01
    private String videoImgPath;//0b10
    private String imgPathMd5;
    private String videoImgPathMd5;
    private int fileNeedUpLoadFlag;//两个全部需要是 0b11 不需要是0
    private long createTime;


    private int retry;
    //0未进行 1进行中 2完成 3失败
    private int processStatus;
    private long timeStrap;


    private int retryFile;
    //0未进行 1进行中 2完成 3失败
    private int processStatusFile;
    private long timeStrapFile;
}

在application中全局监听WxMessageEntity:

//这是在监听微信消息中需要先上传文件的
RealmResults<WxMessageEntity> allWxMessageNeedUploadFile = mGlobalRealm
.where(WxMessageEntity.class)
.notEqualTo("fileNeedUpLoadFlag",0)
.notEqualTo("processStatusFile", ProcessStatus.STATUS_FAIL_LOCAL_FILR_NOT_EXIST.getCode())
.findAllAsync();
allWxMessageNeedUploadFile.addChangeListener(list -> WxFileUploadService.startSelf(this));
//这是 上传微信消息中的文件的service 同步上传
public class WxFileUploadService extends IntentService {

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     */
    public WxFileUploadService() {
        super("WxFileUploadService");
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        if (!NetUtil.isNetConnect()) {
            return;
        }
        Realm realm = Realm.getDefaultInstance();
        WxMessageEntity first = realm.where(WxMessageEntity.class)
                .notEqualTo("fileNeedUpLoadFlag", 0)
                .and()
                .notEqualTo("processStatusFile", ProcessStatus.STATUS_DOING.getCode())
                .and()
                .notEqualTo("processStatusFile", ProcessStatus.STATUS_DONE.getCode())
                .and()
                .notEqualTo("processStatusFile", ProcessStatus.STATUS_FAIL_LOCAL_FILR_NOT_EXIST.getCode())
                .and()
                .lessThan("retryFile", 1)
                .findFirst();
        if (first != null) {
            uploadFile(realm, first);
        }
        realm.close();
    }

    private void uploadFile(Realm realm, WxMessageEntity first) {
        realm.beginTransaction();
        first.setRetryFile(first.getRetryFile() + 1);
        first.setProcessStatusFile(ProcessStatus.STATUS_DOING.getCode());
        first.setTimeStrapFile(System.currentTimeMillis());
        realm.commitTransaction();

        String path = null;
        int flagCurrent = 0b00;
        int flag = first.getFileNeedUpLoadFlag();
        if ((flag & (flagCurrent = 0b01)) > 0) {
            path = first.getImgPath();
        } else if ((flag & (flagCurrent = 0b10)) > 0) {
            path = first.getVideoImgPath();
        }
        if (!TextUtils.isEmpty(path)) {
            File file = new File(path);
            if (!file.exists()) {
                //不存在 直接失败
                realm.beginTransaction();
                first.setProcessStatusFile(ProcessStatus.STATUS_FAIL_LOCAL_FILR_NOT_EXIST.getCode());
                first.setTimeStrapFile(System.currentTimeMillis());
                realm.commitTransaction();

                //网络资源 去下载
                if (path.startsWith("http")) {
                    WxMessageHttpResourceDownloadService.startSelf(getApplicationContext() ,path);
                }
                return;
            }

            String fileMD5String = MD5Utils.getFileMD5String(file);
            if (TextUtils.isEmpty(fileMD5String)) {
                //获取md5失败
                realm.beginTransaction();
                first.setProcessStatusFile(ProcessStatus.STATUS_FAIL_OBTAIN_MD5_EXCEPTION_OCCOUR.getCode());
                first.setTimeStrapFile(System.currentTimeMillis());
                realm.commitTransaction();
                return;
            }
            try {
                //校验服务器是否存在
                Response<StatusEntity> execute = H.with().fileExist(new SimpleBody().id(fileMD5String)).execute();
                if (execute != null && execute.body() != null) {
                    if (ApiRequestCode.API_LOGIN_OK.equals(execute.body().getCode())) {
                        //存在
                        L.e("服务器文件存在:" + path);
                        realm.beginTransaction();
                        int fileNeedUpLoadFlag = flag ^ flagCurrent;
                        first.setFileNeedUpLoadFlag(fileNeedUpLoadFlag);
                        first.setProcessStatusFile(fileNeedUpLoadFlag == 0 ? ProcessStatus.STATUS_DONE.getCode() : ProcessStatus.STATUS_UNSTART.getCode());
                        if (flagCurrent == 0b01) {
                            first.setImgPathMd5(fileMD5String);
                        } else {
                            first.setVideoImgPathMd5(fileMD5String);
                        }
                        realm.commitTransaction();
                        return;
                    } else {
                        //不存在
                        L.e("服务器文件不存在:" + path);
                    }
                }


                //同步上传文件
                int fileType;
                switch (first.getType()) {
                    case WxMessageEntity.PIC:
                        fileType = MessageServerType.PIC;
                        break;
                    case WxMessageEntity.VOICE:
                        fileType = MessageServerType.VOICE;
                        break;
                    case WxMessageEntity.VIDEO:
                        fileType = MessageServerType.VIDEO;
                        break;
                    case WxMessageEntity.FILE:
                        fileType = MessageServerType.FILE;
                        break;
                    default:
                        fileType = -1;
                }

                RequestBody md5RequestBody = RequestBody.create(MediaType.parse("multipart/form-data"), fileMD5String);
                RequestBody fileTypeRequestBody = RequestBody.create(MediaType.parse("multipart/form-data"), String.valueOf(fileType));
                MultipartBody.Part fileRequestBody = MultipartBody.Part.createFormData("file", file.getName(), RequestBody.create(MediaType.parse("*/*"), file));
                Response<DataStringEntity> execute1 = H.with().uploadWxFile(md5RequestBody, fileTypeRequestBody, fileRequestBody).execute();
                if (execute1 != null && execute1.body() != null && ApiRequestCode.API_LOGIN_OK.equals(execute1.body().getCode())) {
                    String successMd5 = execute1.body().getData();
                    realm.beginTransaction();
                    int fileNeedUpLoadFlag = flag ^ flagCurrent;
                    first.setFileNeedUpLoadFlag(fileNeedUpLoadFlag);
                    first.setProcessStatusFile(fileNeedUpLoadFlag == 0 ? ProcessStatus.STATUS_DONE.getCode() : ProcessStatus.STATUS_UNSTART.getCode());
                    if (flagCurrent == 0b01) {
                        first.setImgPathMd5(successMd5);
                    } else {
                        first.setVideoImgPathMd5(successMd5);
                    }
                    realm.commitTransaction();
                } else {
                    realm.beginTransaction();
                    first.setProcessStatusFile(ProcessStatus.STATUS_FAIL.getCode());
                    realm.commitTransaction();
                }

            } catch (Exception e) {
                realm.beginTransaction();
                first.setProcessStatusFile(ProcessStatus.STATUS_FAIL.getCode());
                realm.commitTransaction();
                e.printStackTrace();
            }
        }
    }

    public static void startSelf(Context context) {
        if (!ServiceUtil.isServiceRunning(context, WxFileUploadService.class.getName())) {
            context.startService(new Intent(context, WxFileUploadService.class));
        }
    }
}

//这是拿没有上传 和 上传失败需要重试的微信记录
            RealmResults<WxMessageEntity> allAsync = 
            mGlobalRealm
            .where(WxMessageEntity.class)
            .notEqualTo("processStatus",ProcessStatus.STATUS_DONE.getCode())
            .and()
            .equalTo("0)
            .findAllAsync();
            allAsync.addChangeListener(list -> WxMessageUploadService.startSelf(this));

//这个是上传微信记录的service,继承intentservice,同步http请求,这样就可以一条一条的上传啦
public class WxMessageUploadService extends IntentService {
    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     */
    public WxMessageUploadService() {
        super("WxMessageUploadService");
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        if (!NetUtil.isNetConnect()) {
            return;
        }
        Realm realm = Realm.getDefaultInstance();
        WxMessageEntity first = realm.where(WxMessageEntity.class)
                .notEqualTo("processStatus", ProcessStatus.STATUS_DONE.getCode())
                .and()
                .notEqualTo("processStatus", ProcessStatus.STATUS_DOING.getCode())
                .and()
                .equalTo("fileNeedUpLoadFlag", 0)
                .and()
                .lessThan("retry", 1).findFirst();
        if (first != null) {
            upload2Server(realm, first);
        }
        realm.close();
    }

    private static void upload2Server(Realm realm, WxMessageEntity first) {
        realm.beginTransaction();
        first.setRetry(first.getRetry() + 1);
        first.setProcessStatus(ProcessStatus.STATUS_DOING.getCode());
        first.setTimeStrap(System.currentTimeMillis());
        realm.commitTransaction();

        Response<StatusEntity> execute = HttpSyncRequestWrapper.excute(H.with().uploadWxMessage(WxMessageEntity.obtainUploadBody(first)));
        if (execute != null) {
            realm.beginTransaction();
            first.setProcessStatus(ProcessStatus.STATUS_DONE.getCode());
            realm.commitTransaction();
        } else {
            realm.beginTransaction();
            first.setProcessStatus(ProcessStatus.STATUS_FAIL.getCode());
            realm.commitTransaction();
        }
    }


    public static void startSelf(Context context) {
        if (!ServiceUtil.isServiceRunning(context, WxMessageUploadService.class.getName())) {
            context.startService(new Intent(context, WxMessageUploadService.class));
        }
    }
}

然后我这边用一个定时service来定时清理retry的值,来达到触发重试上传的目的.


/**
 * 守护服务 给微信发消息 和 上传微信消息
 * 
 */

public class DeamonService extends Service {
    //servie 自启动的间隔时间 10分钟
    private static final long DELAY_TIME = 10 * 60 * 1000;

    //超时时间 10分钟
    private static final long ACTION_TIME_OUT = 10 * 60 * 1000;

    //最小的被启动的时间间隔 5分钟
    private static final long MIN_START_INTERVAL = 5 * 60 * 1000;
    private static long timeStrap;
    private Handler mHandler;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mHandler = new Handler(Looper.getMainLooper());
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        L.e(DeamonService.class.getSimpleName() + " 启动...");
        mHandler.removeCallbacksAndMessages(null);
        if (Calendar.getInstance().get(Calendar.HOUR_OF_DAY) > 6 && SocketApp.accountAvalible() && NetUtil.isNetConnect()) {
            //6 - 24点 账户可用 网络可用 才去处理失败的请求

            //删除三天前的socket日志
            if (SocketLib.get().mGlobalRealm.where(SocketLogEntity.class).greaterThan("timeStrap", System.currentTimeMillis() - 24 * 60 * 60 * 1000).count() > 100) {
                //最近三天的日志超过100条 才去删除之前的
                RealmResults<SocketLogEntity> socketLogLimit1000 = SocketLib.get().mGlobalRealm.where(SocketLogEntity.class).lessThan("timeStrap", System.currentTimeMillis() - 24 * 60 * 60 * 1000).limit(10000).findAll();
                SocketLib.get().mGlobalRealm.beginTransaction();
                socketLogLimit1000.deleteAllFromRealm();
                SocketLib.get().mGlobalRealm.commitTransaction();
            }

            //超时十分钟 重置状态 未开始
            RealmResults<WxMessageEntity> all = SocketLib.get().mGlobalRealm
                    .where(WxMessageEntity.class)
                    .notEqualTo("processStatus", ProcessStatus.STATUS_DONE.getCode())
                    .and()
                    .equalTo("fileNeedUpLoadFlag", 0)
                    .and()
                    .lessThan("timeStrap", System.currentTimeMillis() - ACTION_TIME_OUT)
                    .findAll();
            SocketLib.get().mGlobalRealm.beginTransaction();
            for (WxMessageEntity wxMessageEntity : all) {
                wxMessageEntity.setRetry(0);
                wxMessageEntity.setProcessStatus(ProcessStatus.STATUS_UNSTART.getCode());
            }
            SocketLib.get().mGlobalRealm.commitTransaction();


            RealmResults<WxMessageEntity> allWxFile = SocketLib.get().mGlobalRealm
                    .where(WxMessageEntity.class)
                    .notEqualTo("fileNeedUpLoadFlag", 0)
                    .and()
                    .notEqualTo("processStatusFile", ProcessStatus.STATUS_DONE.getCode())
                    .and()
                    .lessThan("timeStrapFile", System.currentTimeMillis() - ACTION_TIME_OUT)
                    .findAll();
            SocketLib.get().mGlobalRealm.beginTransaction();
            for (WxMessageEntity wxMessageEntity : allWxFile) {
                wxMessageEntity.setRetryFile(0);
                wxMessageEntity.setProcessStatusFile(ProcessStatus.STATUS_UNSTART.getCode());
            }
            SocketLib.get().mGlobalRealm.commitTransaction();


            RealmResults<PushEntity> allUnCommitPushResult = SocketLib.get().mGlobalRealm
                    .where(PushEntity.class)
                    .equalTo("needUploadAckResult", true)
                    .and()
                    .notEqualTo("processStatus", ProcessStatus.STATUS_DONE.getCode())
                    .and()
                    .notEqualTo("ack", AckStatus.ACK_NO_RESPONSE)
                    .and()
                    .lessThan("timeStrap", System.currentTimeMillis() - ACTION_TIME_OUT)
                    .findAll();
            SocketLib.get().mGlobalRealm.beginTransaction();
            for (PushEntity wxMessageEntity : allUnCommitPushResult) {
                wxMessageEntity.setRetry(0);
                wxMessageEntity.setProcessStatus(ProcessStatus.STATUS_UNSTART.getCode());
            }
            SocketLib.get().mGlobalRealm.commitTransaction();
        }

        mHandler.postDelayed(() -> DeamonService.startSelf(this), DELAY_TIME);
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        startService(new Intent(this, DeamonService.class));
        super.onDestroy();
    }

    public static void startSelf(Context context) {
        if (System.currentTimeMillis() - timeStrap > MIN_START_INTERVAL) {
            timeStrap = System.currentTimeMillis();
            context.startService(new Intent(context, DeamonService.class));
        }
    }

    public static void startSelfDelay(Handler handler, Context context) {
        handler.postDelayed(() -> startSelf(context), 30 * 1000);
    }
}


下篇介绍realm和recycleView的搭配.

猜你喜欢

转载自blog.csdn.net/Aiction/article/details/89887518