Skip to content

Commit

Permalink
Add DragSortCursorAdapter helper classes
Browse files Browse the repository at this point in the history
These classes take care of virtualizing the reordering of
data coming from a Cursor. They act just like the
CursorAdapter, ResourceCursorAdapter, and SimpleCursorAdapter
classes from the android library.

Also, since it is common to implement the drag-sort Listeners
as part of a custom ListAdapter, DSLV now recognizes if
the ListAdapter given to it implements a Listener interface.
If so, the provided ListAdapter replaces the current
Listeners.
  • Loading branch information
bauerca committed Oct 30, 2012
1 parent 63260b8 commit bab3968
Show file tree
Hide file tree
Showing 12 changed files with 1,236 additions and 1 deletion.
2 changes: 2 additions & 0 deletions demo/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,7 @@
android:label="Background handle" />
<activity android:name="Sections"
android:label="Sections" />
<activity android:name="CursorDSLV"
android:label="DB backed" />
</application>
</manifest>
19 changes: 19 additions & 0 deletions demo/res/layout/cursor_main.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<com.mobeta.android.dslv.DragSortListView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dslv="http://schemas.android.com/apk/res/com.mobeta.android.demodslv"
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dp"
android:layout_margin="10dp"
android:dividerHeight="1px"
dslv:drag_enabled="true"
dslv:collapsed_height="1px"
dslv:drag_scroll_start="0.33"
dslv:float_alpha="0.6"
dslv:slide_shuffle_speed="0.3"
dslv:drag_start_mode="onDown"
dslv:drag_handle_id="@id/drag_handle"
dslv:remove_enabled="true"
dslv:remove_mode="flingLeft" />
6 changes: 6 additions & 0 deletions demo/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<item>Warp</item>
<item>Background handle</item>
<item>Sections</item>
<item>CursorAdapter</item>
</string-array>
<string-array name="activity_descs">
<item>
Expand All @@ -32,6 +33,11 @@
Demonstrates floating View control from a custom
FloatViewManager. Restrict item drags to list sections.
</item>
<item>
Demonstrates usage of the DragSortCursorAdapter class,
which abstracts drag-sorts with a remapping of Cursor
positions to ListView positions.
</item>
</string-array>
<string name="ok">OK</string>
<string name="cancel">Cancel</string>
Expand Down
135 changes: 135 additions & 0 deletions demo/src/com/mobeta/android/demodslv/AbstractCursorLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* Copyright (c) 2011-2012 CommonsWare, LLC
* portions Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.mobeta.android.demodslv;

import android.support.v4.content.AsyncTaskLoader;
import android.content.Context;
import android.database.Cursor;

abstract public class AbstractCursorLoader extends AsyncTaskLoader<Cursor> {
abstract protected Cursor buildCursor();
Cursor lastCursor=null;

public AbstractCursorLoader(Context context) {
super(context);
}

/**
* Runs on a worker thread, loading in our data. Delegates
* the real work to concrete subclass' buildCursor() method.
*/
@Override
public Cursor loadInBackground() {
Cursor cursor=buildCursor();

if (cursor!=null) {
// Ensure the cursor window is filled
cursor.getCount();
}

return(cursor);
}

/**
* Runs on the UI thread, routing the results from the
* background thread to whatever is using the Cursor
* (e.g., a CursorAdapter).
*/
@Override
public void deliverResult(Cursor cursor) {
if (isReset()) {
// An async query came in while the loader is stopped
if (cursor!=null) {
cursor.close();
}

return;
}

Cursor oldCursor=lastCursor;
lastCursor=cursor;

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

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

/**
* Starts an asynchronous load of the list data.
* When the result is ready the callbacks will be called
* on the UI thread. If a previous load has been completed
* and is still valid the result may be passed to the
* callbacks immediately.
*
* Must be called from the UI thread.
*/
@Override
protected void onStartLoading() {
if (lastCursor!=null) {
deliverResult(lastCursor);
}
if (takeContentChanged() || lastCursor==null) {
forceLoad();
}
}

/**
* Must be called from the UI thread, triggered by a
* call to stopLoading().
*/
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}

/**
* Must be called from the UI thread, triggered by a
* call to cancel(). Here, we make sure our Cursor
* is closed, if it still exists and is not already closed.
*/
@Override
public void onCanceled(Cursor cursor) {
if (cursor!=null && !cursor.isClosed()) {
cursor.close();
}
}

/**
* Must be called from the UI thread, triggered by a
* call to reset(). Here, we make sure our Cursor
* is closed, if it still exists and is not already closed.
*/
@Override
protected void onReset() {
super.onReset();

// Ensure the loader is stopped
onStopLoading();

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

lastCursor=null;
}
}
33 changes: 33 additions & 0 deletions demo/src/com/mobeta/android/demodslv/ContentChangingTask.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* Copyright (c) 2012 -- CommonsWare, LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package com.mobeta.android.demodslv;

import android.os.AsyncTask;
import android.support.v4.content.Loader;

public abstract class ContentChangingTask<T1, T2, T3> extends
AsyncTask<T1, T2, T3> {
private Loader<?> loader=null;

ContentChangingTask(Loader<?> loader) {
this.loader=loader;
}

@Override
protected void onPostExecute(T3 param) {
loader.onContentChanged();
}
}
111 changes: 111 additions & 0 deletions demo/src/com/mobeta/android/demodslv/CursorDSLV.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package com.mobeta.android.demodslv;

import java.util.List;
import java.util.ArrayList;

import com.mobeta.android.dslv.DragSortListView;
import com.mobeta.android.dslv.SimpleDragSortCursorAdapter;
import com.mobeta.android.dslv.SimpleFloatViewManager;

import android.content.Context;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import android.view.View;
import android.view.ViewGroup;


public class CursorDSLV extends FragmentActivity implements LoaderCallbacks<Cursor> {

private SimpleDragSortCursorAdapter adapter;

private SQLiteOpenHelper mOpenHelper;

private class OpenHelper extends SQLiteOpenHelper {

private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "jazz";
public static final String TABLE_NAME = "jazz_artists";
private static final String ARTIST_NAME = "name";
private static final String TABLE_CREATE =
"CREATE TABLE " + TABLE_NAME + " (" +
"_id PRIMARY_KEY, " +
ARTIST_NAME + " TEXT);";

private Context mContext;

OpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
mContext = context;
}

@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(TABLE_CREATE);

// get jazz names
String[] artistNames = mContext.getResources().getStringArray(R.array.jazz_artist_names);

ContentValues v = new ContentValues();
int id = 0;
for (String artist : artistNames) {
v.put("_id", id);
v.put(ARTIST_NAME, artist);
db.insert(TABLE_NAME, null, v);
v.clear();
id++;
}
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// do nothing
}
}


/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.cursor_main);

String[] cols = {"name"};
int[] ids = {R.id.text};
adapter = new SimpleDragSortCursorAdapter(this,
R.layout.list_item_handle_right, null, cols, ids, 0);

DragSortListView dslv = (DragSortListView) findViewById(android.R.id.list);
dslv.setAdapter(adapter);

mOpenHelper = new OpenHelper(this);
getSupportLoaderManager().initLoader(0, null, this);
}

//Loader callbacks
@Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
Loader<Cursor> loader = new SQLiteCursorLoader(this, mOpenHelper,
"SELECT _id, name "
+ "FROM " + OpenHelper.TABLE_NAME
+ " ORDER BY name", null);
return loader;
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
adapter.changeCursor(cursor);
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
adapter.changeCursor(null);
}
}
Loading

0 comments on commit bab3968

Please sign in to comment.