Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loaders and cursors for DBFlow #1091

Open
wants to merge 56 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
91326fb
First pass at external foreign key references
hilljh82 Jan 31, 2016
50382fc
Added missing files
hilljh82 Jan 31, 2016
a1ff768
Merge from Raizlabs
hilljh82 Jan 31, 2016
35567d3
Foreign key on primary key failed if column was a model and not a mod…
hilljh82 Feb 3, 2016
a92a9d1
Removed debug code
hilljh82 Feb 3, 2016
de30375
Overrided getSupportedOptions() to handle processor warnings
hilljh82 Feb 3, 2016
bf4b415
Foreign key definition failed with model container
hilljh82 Feb 3, 2016
50e409b
Reverted change
hilljh82 Feb 3, 2016
6dfd5d6
Removed test files
hilljh82 Feb 23, 2016
f3935e1
Merge from raizlabs/develop
hilljh82 Feb 23, 2016
0947f8c
Added missing code for checkNeedsReferences()
hilljh82 Mar 10, 2016
118204a
Removed faulty line of code
hilljh82 Mar 10, 2016
2a450a2
Added missing check for external foreign key
hilljh82 Mar 10, 2016
36b7fa7
Overrided the newInstance() method
hilljh82 Mar 14, 2016
f98ebc2
Merge from Raizlabs/master
hilljh82 Jul 3, 2016
9431b13
Fixed error preventing Jitpack from working
hilljh82 Jul 3, 2016
e483520
Merge from master
hilljh82 Jul 3, 2016
1e05a47
Fixed build errors
hilljh82 Jul 4, 2016
ccdb83b
Fixed build error
hilljh82 Jul 4, 2016
49d3993
Fixed compilation errors
hilljh82 Jul 4, 2016
25403c8
Merge branch 'master' into develop
hilljh82 Jul 4, 2016
e3b8ecb
Switch to AsyncTaskLoader in Android support library
hilljh82 Jul 7, 2016
536a5bb
Added missing dependency
hilljh82 Jul 7, 2016
36b144d
Fixed build issues with API version
hilljh82 Jul 7, 2016
cff3e40
Merge from Raizlabs/develop
hilljh82 Jul 7, 2016
09f1be7
Merge from Raizlabs/master
hilljh82 Jul 7, 2016
956fc1b
Merge branch 'master' into develop
hilljh82 Jul 7, 2016
63fe220
Fixed issues in implementation
hilljh82 Jul 21, 2016
008dc04
Loaders for single model queries
hilljh82 Jul 21, 2016
a7105b4
Relocated file
hilljh82 Aug 4, 2016
1508e00
Added support for Travis CI
hilljh82 Aug 4, 2016
464ba50
Moved Travis-CI config to different branch
hilljh82 Aug 28, 2016
f5a5b13
Moved ExternalForeignKey annotation to its own branch
hilljh82 Aug 28, 2016
d983e5f
Added documentation; fixed spacing issues
hilljh82 Aug 28, 2016
9632cd8
Fixed format
hilljh82 Aug 28, 2016
7d79b78
Fixed format
hilljh82 Aug 28, 2016
aa85b79
Removed unused variables; fixed formatting
hilljh82 Aug 28, 2016
f0ab254
Fixed merge: Updated sdk version numbers to be compatible with depend…
hilljh82 Aug 28, 2016
344a9a5
Fixed build error
hilljh82 Nov 29, 2016
dea07b7
Merge from Raizlabs/develop
hilljh82 Nov 30, 2016
a1b9485
Fixed build errors related to updates to raizlabs/develop
hilljh82 Dec 1, 2016
56392ad
Fixed merge conflicts
hilljh82 Dec 1, 2016
34acd05
Fixed merge conflicts
hilljh82 Dec 1, 2016
0212982
Fixed merge conflicts
hilljh82 Dec 1, 2016
d1a52cb
Fixed merge conflicts
hilljh82 Dec 1, 2016
fd72253
Removed obsolete file
hilljh82 Dec 1, 2016
0554ec4
Fixed formatting issues
hilljh82 Dec 1, 2016
8d72965
For some reason, lintOptions was added to the build config
hilljh82 Dec 1, 2016
d019191
PropertyExtensions was changed during the merge; this file should not…
hilljh82 Dec 1, 2016
aff9722
Removed obsolete file
hilljh82 Dec 1, 2016
a613727
Fixed naming convention on class variables
hilljh82 Dec 1, 2016
d7d188e
Fixed naming convention on class variables
hilljh82 Dec 1, 2016
c97f1b3
Fixed refactoring error
hilljh82 Dec 1, 2016
83ac02d
Fixed refactoring error
hilljh82 Dec 1, 2016
4cd5e39
Fixed naming conventions errors
hilljh82 Dec 1, 2016
0067c1e
Fixed naming conventions errors
hilljh82 Dec 1, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.raizlabs.android.dbflow.kotlinextensions

import com.raizlabs.android.dbflow.sql.language.property.*
import com.raizlabs.android.dbflow.sql.queriable.ModelQueriable
import com.raizlabs.android.dbflow.structure.Model

/**
* Description: Provides some very nice Property class extensions.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import com.raizlabs.android.dbflow.structure.Model
/**
* Description: Provides property methods in via infix functions.
*/

infix fun <T : Any> Property<T>.eq(value: T) = this.eq(value)

infix fun <T : Any> Property<T>.`is`(value: T) = this.`is`(value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ fun <T : Any> update(modelClass: KClass<T>): Update<T> = SQLite.update(modelClas

infix fun <T : Any> Update<T>.set(sqlCondition: SQLCondition) = set(sqlCondition)


// delete

inline fun <reified T : Any> delete() = SQLite.delete(T::class.java)
Expand Down
1 change: 0 additions & 1 deletion dbflow-processor/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"

testCompile 'junit:junit:4.12'

}

apply from: '../java-artifacts.gradle'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ public class DBFlowProcessor extends AbstractProcessor {

private ProcessorManager manager;

@Override
public Set<String> getSupportedOptions() {
Set <String> supportedOptions = new LinkedHashSet<>();
supportedOptions.add("targetModuleName");

return supportedOptions;
}

/**
* If the processor class is annotated with {@link
* javax.annotation.processing.SupportedAnnotationTypes}, return an unmodifiable set with the
Expand Down
2 changes: 0 additions & 2 deletions dbflow/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ android {
dependencies {
compile project("${dbflow_project_prefix}dbflow-core")
compile "com.android.support:support-annotations:25.0.0"


}

apply from: '../android-artifacts.gradle'
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.raizlabs.android.dbflow.list;

import android.annotation.TargetApi;
import android.content.Context;
import android.database.Cursor;
import android.widget.CursorAdapter;

import com.raizlabs.android.dbflow.config.FlowManager;
import com.raizlabs.android.dbflow.structure.Model;
import com.raizlabs.android.dbflow.structure.ModelAdapter;

/**
* Specialization of CursorAdapter for DBFLow models. The getItem() method
* returns a model element instead of a Cursor object.
*
* @param <TModel>
*/
public abstract class FlowCursorAdapter <TModel extends Model> extends CursorAdapter {
private final ModelAdapter<TModel> modelAdapter;

public FlowCursorAdapter(Context context, Class<TModel> modelClass, Cursor c, boolean autoRequery) {
super(context, c, autoRequery);

this.modelAdapter = FlowManager.getModelAdapter(modelClass);
}

@TargetApi(11)
public FlowCursorAdapter(Context context, Class<TModel> modelClass, Cursor c, int flags) {
super(context, c, flags);

this.modelAdapter = FlowManager.getModelAdapter(modelClass);
}

@Override
public TModel getItem(int position) {
Cursor cursor = (Cursor) super.getItem(position);
return cursor != null ? this.modelAdapter.loadFromCursor(cursor) : null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
package com.raizlabs.android.dbflow.list;

import android.annotation.TargetApi;
import android.content.AsyncTaskLoader;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import com.raizlabs.android.dbflow.runtime.FlowContentObserver;
import com.raizlabs.android.dbflow.sql.language.SQLCondition;
import com.raizlabs.android.dbflow.sql.queriable.Queriable;
import com.raizlabs.android.dbflow.structure.BaseModel;
import com.raizlabs.android.dbflow.structure.Model;

import java.util.Collection;
import java.util.HashSet;

/**
* Specialization of AsyncTaskLoader for Cursor objects in DBFlow.
*/
@TargetApi(11)
public class FlowCursorLoader extends AsyncTaskLoader<Cursor> {
/// Models to be observed for changes.
private final HashSet<Class<? extends Model>> models = new HashSet<>();

/// Queriable operation that the loader executes.
private Queriable queriable;

/// Cursor for the loader.
private Cursor cursor;

/// The observer that triggers the loader to reload anytime if it receives
/// notification of a change.
private final ForceLoadContentObserver observer = new ForceLoadContentObserver();

private boolean listening = false;

/**
* Creates a fully-specified CursorLoader. See {@link android.content.ContentResolver#query(Uri,
* String[], String, String[], String) ContentResolver.query()} for documentation on the meaning
* of the parameters. These will be passed as-is to that call.
*/
public FlowCursorLoader(Context context, Queriable queriable) {
super(context);

this.queriable = queriable;
}

@Override
public Cursor loadInBackground() {
Cursor cursor = this.queriable.query();

if (cursor != null) {
cursor.getCount();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#? what is this supposed to do

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This forces the cursor to load the load the count.

}

return cursor;
}

@Override
public void deliverResult(Cursor cursor) {
if (this.isReset()) {
// An async query came in while the loader is stopped
if (cursor != null) {
cursor.close();
}

return;
}

Cursor oldCursor = this.cursor;
this.cursor = cursor;

if (this.isStarted()) {
super.deliverResult(cursor);
}

if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
oldCursor.close();
}

// Now that the result has been delivered, start listening for changes
// to the target models. Doing this at anytime earlier runs the risk of
// listening for changes while we are still loading content.
this.startListeningForChanges();
}

/**
* Register the loader for changes to a Flow model. When changes to the model are
* detected, then the loader will automatically reload the content.
*
* @param model
*/
public void registerForContentChanges(Class<? extends Model> model) {
if (this.models.contains(model)) {
return;
}

this.models.add(model);
this.observer.registerForContentChanges(this.getContext(), model);
}

@Override
protected void onStartLoading() {
if (this.cursor != null) {
this.deliverResult(this.cursor);
}

if (this.takeContentChanged() || this.cursor == null) {
this.forceLoad();
}
}

@Override
protected void onStopLoading() {
// Make sure the loading has stopped.
this.cancelLoad();
}

@Override
public void onCanceled(Cursor cursor) {
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}

this.stopListeningForChanges();
}

@Override
protected void onReset() {
super.onReset();

this.startLoading();

if (cursor != null && !cursor.isClosed()) {
cursor.close();
}

cursor = null;

this.observer.unregisterForContentChanges(this.getContext());
}

private void startListeningForChanges() {
if (!this.listening) {
this.observer.addModelChangeListener(this.observer);
this.listening = true;
}
}

private void stopListeningForChanges() {
if (this.listening) {
this.observer.removeModelChangeListener(this.observer);
this.listening = false;
}
}

public Collection<Class<? extends Model>> getModels() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#req rename to something like getModelClasses()

return this.models;
}

public FlowContentObserver getContentObserver() {
return this.observer;
}

private final class ForceLoadContentObserver extends FlowContentObserver
implements FlowContentObserver.OnModelStateChangedListener {
private boolean endOfTransaction = false;

@Override
public boolean deliverSelfNotifications() {
return false;
}

@Override
public void onModelStateChanged(@Nullable Class<?> table, BaseModel.Action action, @NonNull SQLCondition[] primaryKeyValues) {
if (!this.endOfTransaction) {
if (action == BaseModel.Action.INSERT || action == BaseModel.Action.DELETE || action == BaseModel.Action.UPDATE) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#? what about the other two, CHANGE + SAVE?

Copy link
Contributor Author

@hilljh82 hilljh82 Dec 1, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is CHANGE new? I did not add SAVE since for some reasons I was seeing SAVE being fired with either INSERT or UPDATE in 3.1.x. So, it was triggering the loader twice. Is this a true understanding of those events being fired.

How is CHANGE different from UPDATE?

onContentChanged();
}
}
}

@Override
public void endTransactionAndNotify() {
// Mark this as the end of a transactions, and pass control to the base class
// to perform the notifications.
this.endOfTransaction = true;
super.endTransactionAndNotify();

// Notify the observer the content has changed.
this.endOfTransaction = false;
onContentChanged();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.raizlabs.android.dbflow.list;


import android.annotation.TargetApi;
import android.content.Context;
import android.database.Cursor;
import android.widget.SimpleCursorAdapter;

import com.raizlabs.android.dbflow.config.FlowManager;
import com.raizlabs.android.dbflow.structure.Model;
import com.raizlabs.android.dbflow.structure.ModelAdapter;

/**
* Specialization of SimpleCursorAdapter designed for DBFlow. The getItem() method
* return a model element instead of a Cursor element.
*
* @param <TModel>
*/
public class FlowSimpleCursorAdapter <TModel extends Model> extends SimpleCursorAdapter {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#? not sure the difference here between this and the FlowCursorAdapter

Copy link
Contributor Author

@hilljh82 hilljh82 Dec 1, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Adapter is specialization of the SimpleCursorAdapter in the Android SDK designed for DBFlow.

The FlowCursorAdapter requires allows the developer to have different layouts for model. For example, you are storing inherited data in a SQL database, and create a query that aggregates different model types into a single result set. In this case, you have a different layout for each data type referenced in the data set. You therefore have to implement newView and bindView.

In some cases, however, the data you result set will be a homogenous data types, and the mapping between columns and views is straightforward text populations. In this case, you only need a single layout, and a mapping between columns and views. The FlowSimpleCursorAdapter is designed to support this need since you only have to provide the layout id and the necessary mapping in the constructor.

private final Class<TModel> mModel;
private final ModelAdapter<TModel> mModelAdapter;

@TargetApi(11)
public FlowSimpleCursorAdapter(Context context, Class<TModel> modelClass, int layout, Cursor c, String[] from, int[] to, int flags) {
super(context, layout, c, from, to, flags);

this.mModel = modelClass;
this.mModelAdapter = FlowManager.getModelAdapter(modelClass);
}

@Override
public TModel getItem(int position) {
Cursor cursor = (Cursor) super.getItem(position);
return cursor != null ? this.mModelAdapter.loadFromCursor(cursor) : null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.raizlabs.android.dbflow.single;

import android.annotation.TargetApi;
import android.content.Context;

import com.raizlabs.android.dbflow.config.FlowManager;
import com.raizlabs.android.dbflow.sql.queriable.Queriable;
import com.raizlabs.android.dbflow.structure.Model;

/**
* Load a single model from the database.
*
* @param <TModel>
*/
@TargetApi(11)
public class FlowModelLoader <TModel extends Model>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#req no model restriction anywhere please.

Copy link
Contributor Author

@hilljh82 hilljh82 Dec 1, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#? How do you ensure the class is only parameterized by DBFlow Model-like classes? Is this no longer a concern with 4.x.x? Also, doing so will mean removing restrictions on certain methods that should only be called with class that derive from Model, such as registerForContentChanges. This would be an introduction of an accidental complicity in the design.

extends FlowSingleModelLoader<TModel> {

public FlowModelLoader(Context context, Class<TModel> model, Queriable queriable) {
super(context, model, FlowManager.getModelAdapter(model), queriable);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.raizlabs.android.dbflow.single;

import android.annotation.TargetApi;
import android.content.Context;

import com.raizlabs.android.dbflow.config.FlowManager;
import com.raizlabs.android.dbflow.sql.queriable.Queriable;
import com.raizlabs.android.dbflow.structure.BaseModelView;
import com.raizlabs.android.dbflow.structure.InstanceAdapter;
import com.raizlabs.android.dbflow.structure.Model;

/**
* Load a single DBFlow model from a ViewModel.
*
* @param <TModel>
*/
@TargetApi(11)
public class FlowModelViewLoader <TModel extends Model, TModelView extends BaseModelView>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#req no Model restriction on the TModel

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#? How do you ensure the class is only parameterized by DBFlow Model-like classes? Is this no longer a concern with 4.x.x? Also, doing so will mean removing restrictions on certain methods that should only be called with class that derive from Model, such as registerForContentChanges. This would be an introduction of an accidental complicity in the design.

extends FlowSingleModelLoader<TModel> {

@SuppressWarnings("unchecked")
public FlowModelViewLoader(Context context, Class<TModel> model, Class<TModelView> modelView, Queriable queriable) {
super(context, model, (InstanceAdapter<TModel>) FlowManager.getModelViewAdapter(modelView), queriable);
}
}
Loading