ProviderTestCase2 returns null on getMockContentResolver() - android

I'm using ProviderTestCase2 to test my ContentProvider, LinesCP, but calling getMockContentResolver() returns null.
The class path to LinesCP is 'com.olfybsppa.inglesaventurero/start/LinesCP.java'. This is a segment of the code showing the AUTHORITY.
public class LinesCP extends ContentProvider {
private static final String database_name = "lines.db";
public static final String AUTHORITY = "com.olfybsppa.inglesaventurero.start.LinesCP";
I am running it using BuildVariants Unit Test, my other unit tests work. Here is the test that isn't working.
public class ContentProviderUTest extends ProviderTestCase2<LinesCP> {
private static String ALPHABET = "AL-00";
private MockContentResolver cr;
public ContentProviderUTest () {
super(LinesCP.class, "com.olfybsppa.inglesaventurero.start");
//super(LinesCP.class, LinesCP.AUTHORITY);
}
public ContentProviderUTest (Class<LinesCP> providerClass, String providerAuthority) {
super(providerClass, providerAuthority);
}
#Override
protected void setUp() throws Exception {
super.setUp();
cr = getMockContentResolver(); // cr is null.
}
public void testSceneInsert() {
Uri uri = LinesCP.sceneTableUri;
ContentValues sceneValues = new ContentValues();
sceneValues.put(LinesCP.scene_id, ALPHABET);
sceneValues.put(LinesCP.english_title, "Alphabet");
sceneValues.put(LinesCP.spanish_title, "Alphabeto");
MockContentResolver cr = getMockContentResolver();
Uri resultingUri = getMockContentResolver().insert(uri, sceneValues);
assertNotNull(resultingUri);
long rowId = ContentUris.parseId(resultingUri);
assertTrue(rowId > 0);
}
}
I really think this should be working, any ideas welcome.

Quick Orientation: My ContentProvider is named LinesCP. LinesCP holds a table of CPHints. CPHint is my own class. My Test is ProviderInsertHintsTest which extends ProviderTestCase2
Even though ProviderTestCase2 does not inherit from InstrumentationTestCase, I am running ProviderInsertHintsTest using the Build Variants 'Android Instrumentation Tests'. ProviderInsertHintsTest is in my src/androidTest/java/ folder. So, I previously thought ProviderTestCase2 should be run with BuildVariants 'Unit Test', and I think that was my main mistake.
In ProviderInsertHintsTest, I test LineCP's insert(Uri, ContentValues) method. I get mMockResolver in setUp(). I use mMockResolver to insert a ContentValues I made from hint1. Then I use mMockResolver.query to get 'fromCP' back from the Content Provider. Then I assert that the original 'hint1' is equal to 'fromCP'.
public class ProviderInsertHintsTest extends ProviderTestCase2<LinesCP> {
private MockContentResolver mMockResolver;
private CPHint hint1;
private CPHint hint2;
public ProviderInsertHintsTest() {
super(LinesCP.class, LinesCP.AUTHORITY);
}
#Override
protected void setUp() throws Exception {
super.setUp();
mMockResolver = getMockContentResolver();
hint1 = new CPHint(1);
hint1.setNormalStartTime(1001);
hint1.setNormalEndTime(1010);
hint2 = new CPHint(2);
hint2.setNormalStartTime(2001);
hint2.setNormalEndTime(2010);
}
#Override
protected void tearDown() throws Exception {
super.tearDown();
}
public void testInsertHint () {
ContentValues cv = hint1.getContentValues(111);
mMockResolver.insert(LinesCP.hintTableUri, cv);
Cursor cursor = mMockResolver.query(LinesCP.hintTableUri, null, null, null, null);
cursor.moveToFirst();
assertEquals(1, cursor.getCount());
CPHint fromCP = CPHint.extractCPHint(cursor);
cursor.close();
assertTrue(fromCP.equals(hint1));
}
public void testInsertTwoHintsDeleteOne () {
ContentValues cv1 = hint1.getContentValues(111);
ContentValues cv2 = hint2.getContentValues(111);
mMockResolver.insert(LinesCP.hintTableUri, cv1);
mMockResolver.insert(LinesCP.hintTableUri, cv2);
Cursor cursor1 = mMockResolver.query(LinesCP.hintTableUri, null, null, null, null);
assertEquals(2, cursor1.getCount());
cursor1.close();
mMockResolver.delete(LinesCP.hintTableUri, Ez.where(BaseColumns._ID, "" + 1), null);
Cursor cursor2 = mMockResolver.query(LinesCP.hintTableUri, null, null, null, null);
assertEquals(1, cursor2.getCount());
cursor2.close();
}
}
The only leap of faith is the CPHint.extractCPHint(Cursor cursor). It is only for drying up the code. It asks what is the value at LineCP's column index that matches the column name, then creates a new CPHint. Here it is, just in case.
public static CPHint extractCPHint(Cursor cursor) {
Integer position = cursor.getInt(cursor.getColumnIndex(LinesCP.pos_id));
CPHint hint = new CPHint(position);
hint.setTimes(cursor.getLong(cursor.getColumnIndex(LinesCP.normal_start_time)),
cursor.getLong(cursor.getColumnIndex(LinesCP.normal_end_time)),
return hint;
}
To test delete, I take mMockResolver and add hint1 and hint2 to the ContentProvider. Then I delete the CPHint that matches BaseColumns.ID equal to 1. Then I query the Content Provider again and assert that it only has one row, where as before it had two rows.

Related

These three RX observables all work as expected...which way is the best?

I'm trying to make a call to my contentResolver that accesses my sql DB in a reactive way. I know sqlBrite exists, but I have to use sqLite. I'm new to rxJava(2) and somehow stitched together 3 calls that all work as expected magically. I don't know which one to use. I'm using rxJava2 and some of the articles I read that brought me to this point seemed old. What's the preferred way to accomplish this? I'm also not using retroLambda...baby steps for me(I'll admit, it does make things look really nice though).
This is the starting call and subscribe function:
Observable<Cursor> dbObserver = mTmdbDatabaseService.getCursor1(123456);
dbObserver.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(testDBObserver());
private Observer<Cursor> testDBObserver() {
return new Observer<Cursor>() {
#Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "testDBObserver.onSubscribe");
//Save the disposable to remove it later onDestroy
mCompositeDisposable.add(d);
}
#Override
public void onNext(Cursor c) {
int num = c.getCount();
Log.d(TAG, "testDBObserver.onNext: " + c.getCount());
}
#Override
public void onError(Throwable e) {
Log.d(TAG, "testDBObserver.onError");
}
#Override
public void onComplete() {
Log.d(TAG, "testDBObserver.onComplete");
}
};
}
These are the three RxJava functions that for now query my DB:
public Observable getCursor1(final int value) {
Observable<Cursor> cursorObservable = Observable.fromCallable(new Callable<Cursor>() {
#Override
public Cursor call() throws Exception {
int id = value;
String stringId = Integer.toString(id);
Uri uri = MovieContract.MovieEntry.CONTENT_URI;
uri = uri.buildUpon().appendPath(stringId).build();
Cursor c = mContext.getContentResolver().query(uri,
null,
null,
null,
MovieContract.MovieEntry.COLUMN_MOVIE_ID);
return c;
}
});
return cursorObservable;
}
public Observable<Cursor> getCursor2(final int value) {
return Observable.defer(new Callable<ObservableSource<? extends Cursor>>() {
#Override
public ObservableSource<? extends Cursor> call() throws Exception {
int id = value;
String stringId = Integer.toString(id);
Uri uri = MovieContract.MovieEntry.CONTENT_URI;
uri = uri.buildUpon().appendPath(stringId).build();
Cursor c = mContext.getContentResolver().query(uri,
null,
null,
null,
MovieContract.MovieEntry.COLUMN_MOVIE_ID);
return Observable.just(c);
}
});
}
public Observable<Cursor> getCursor3(final int value) {
Observable<Cursor> observable = Observable.create(new ObservableOnSubscribe<Cursor>() {
#Override
public void subscribe(#NonNull ObservableEmitter<Cursor> subscriber) throws Exception {
int id = value;
String stringId = Integer.toString(id);
Uri uri = MovieContract.MovieEntry.CONTENT_URI;
uri = uri.buildUpon().appendPath(stringId).build();
Cursor c = mContext.getContentResolver().query(uri,
null,
null,
null,
MovieContract.MovieEntry.COLUMN_MOVIE_ID);
subscriber.onNext(c);
subscriber.onComplete();
}
});
return observable;
}
Observable.fromCallable is the best choice here because it just fits your needs: execute some code and return a value. defer and create are meant for more complex cases such as wrapping callbacks or manipulating the lifecycle of the stream.
Tip: since you are using a Cursor, I think a better design solution would be to emit exact data from your data source (instead of cursor itself) and close the cursor onsite:
Observable<Result> cursorObservable = Observable.fromCallable ... {
#Override
public Cursor call() throws Exception {
...
Cursor c = ...
Result result = ... //get your data from the cursor
c.close();
return result;
}
});
P.S. SQLBrite is just a reactive wrapper around SQLite.

Cannot close the Db correctly

Following is my code,
public class CommentsDataSource {
private SQLiteDatabase database;
private MySQLiteHelper dbHelper;
private String[] allColumns = { MySQLiteHelper.COLUMN_ID,
MySQLiteHelper.COLUMN_COMMENT };
public CommentsDataSource(Context context) {
dbHelper = new MySQLiteHelper(context);
}
public void open() throws SQLException {
database = dbHelper.getWritableDatabase();
}
public void close() {
if (database != null) {
database.close();
}
dbHelper.close();
}
public String getComment_1() {
List<Comment> comments = new ArrayList<Comment>();
Cursor cursor = database.query(MySQLiteHelper.TABLE_COMMENTS,
allColumns, null, null, null, null, null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
Comment comment = cursorToComment(cursor);
comments.add(comment);
cursor.moveToNext();
}
// make sure to close the cursor
cursor.close();
return comments.get(0).getComment();
}
private Comment cursorToComment(Cursor cursor) {
Comment comment = new Comment();
comment.setId(cursor.getLong(0));
comment.setComment(cursor.getString(1));
return comment;
}
public class MyService extends BackgroundService implements LocationListener {
#Override
public void onCreate() {
context = getApplicationContext();
datasource = new CommentsDataSource(context);
gps = new GPSTracker(context);
datasource.open();
mHelloTo = datasource.getComment_1();
datasource.close();
}
}
In the Above Code use to retrieve some data from database inside a Background Service. It Works Fine but Sometimes it gives the Following Error even though i close the cursor database and dbhelper correctly.
01-08 14:31:58.691: E/SQLiteDatabase(13854): close() was never explicitly called on database '/data/data/org.apache.cordova.example/databases/commments.db'
This only happens on platforms before JellyBean. JellyBean and later have this error message removed.
Even though it is logged with error log level and contains exception stacktrace, it is not an exception that was thrown. SQLiteDatabase constructor just stores the stacktrace of its caller in a member variable exception and in finalizer logs the stacktrace in case the database is still open.
You can see the stacktrace to see where the unclosed database was opened.
To get specific help with your code, include relevant parts of MySQLiteHelper in the question
Try changing this:
public String getComment_1() {
open(); // open database
List<Comment> comments = new ArrayList<Comment>();
Cursor cursor = database.query(MySQLiteHelper.TABLE_COMMENTS,
allColumns, null, null, null, null, null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
Comment comment = cursorToComment(cursor);
comments.add(comment);
cursor.moveToNext();
}
// make sure to close the cursor
cursor.close();
close(); // close database
return comments.get(0).getComment();
}
Also what dbHelper.close(); does? You're closing the connection with the db calling database.close() so why do you need this?
You're calling the methods correctly, but please change the open() and close() methods to the following :
public void open() throws SQLException {
dbHelper= new MySQLiteHelper (ctx);
database = dbHelper.getWritableDatabase();
return this;
}
public void close() {
dbHelper.close();
}
But instead of opening and closing the database each time you make a read/write operation, I'd recommend you open() the database once in your Application.onCreate(). The closing will be done automatically when your application exits or is closed by Android OS. Since SQLite data integrity, you don't have to worry about losing data.

How to save (and later retrieve) the selected item of a spinner to SQLite

Alright... I've had enough.
I'm thoroughly frustrated.
So I'd rather ask for help instead of a new monitor.
...And those are VERY expensive here.
Long story short... I have a database. And a table.
private String DEFINE_PROP_TYPES = "CREATE TABLE " + TABLE_PROP_TYPES + "("
+ TABLE_ID + " INTEGER PRIMARY KEY, "
+ TABLE_PROP_TYPE_NAME + " TEXT NOT NULL"
+ ")";
With an 'Adapter' class thrown in for good measure to manage it.
public abstract class DBAdapter
{
static public final String C_COLUMN_ID = "_id";
protected Context context;
protected DBHelper dbHelper;
protected SQLiteDatabase db;
protected String managedTable;
protected String[] columns;
public String getTableManaged()
{
return managedTable;
}
public void setTableManaged(String managedTable)
{
this.managedTable = managedTable;
}
public void setColumns(String[] columns)
{
this.columns = columns;
}
public DBAdapter(Context context)
{
this.context = context;
}
public void close()
{
dbHelper.close();
}
public DBAdapter open() throws SQLException
{
dbHelper = new DBHelper(context);
db = dbHelper.getWritableDatabase();
return this;
}
public Cursor getList()
{
Cursor c = db.query(true, managedTable, columns, null, null, null, null, null, null);
return c;
}
public long insert(ContentValues reg)
{
return 0;
}
}
public class PropTypesDBAdapter extends DBAdapter
{
static public final String C_TABLE_PROP_TYPES = "PROP_TYPES";
static public final String C_COLUMN_ID = "_id",
C_COLUMN_PROP_TYPES_NAME = "re_prop_type";
public PropTypesDBAdapter(Context context)
{
super(context);
this.setTableManaged(C_TABLE_PROP_TYPES);
this.setColumns(new String[] { C_COLUMN_ID,
C_COLUMN_PROP_TYPES_NAME });
}
public long insert(ContentValues reg)
{
if (db == null)
{
open();
}
return db.insert(C_TABLE_PROP_TYPES, null, reg);
}
}
And besides this pile of cute I have an activity class.
With spinners.
public class PropDetailActivity extends Activity implements LocationListener
{
// insert here some blah-blah constants not needed by spinners
private PropDBAdapter mHouses;
private RatingsDBAdapter mRatings;
private PropTypesDBAdapter mPropTypes;
private Cursor mCursorHouses,
mCursorRatings,
mCursorPropTypes;
long mPropType;
private long mPropId;
private Spinner spinnerRating, spinnerType;
AdapterView.OnItemSelectedListener spnLstPropType, spnLstRating;
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_house_detail);
Intent intent = getIntent();
Bundle extra = intent.getExtras();
if (extra == null)
{
return;
}
// Figure all view widgets being retrieved here, including...
spinnerRating = (Spinner) findViewById(R.id.spinnerRating);
spinnerType = (Spinner) findViewById(R.id.spinnerType);
// Create adapter and cursor-y things here
mHouses = new PropDBAdapter(this);
mHouses.open();
// And now, for the juicy, deliciously irritating stuff:
String[] from = new String[] { PropTypesDBAdapter.C_COLUMN_PROP_TYPES_NAME };
int[] to = new int[] { android.R.id.text1 };
mPropTypes = new PropTypesDBAdapter(this);
mPropTypes.open();
mCursorPropTypes = mPropTypes.getList();
#SuppressWarnings("deprecation")
SimpleCursorAdapter adapterPropTypes = new SimpleCursorAdapter(this,
android.R.layout.simple_spinner_item,
mCursorPropTypes,
from, /*new String[] { RatingsDBAdapter.C_COLUMN_RATING_NAME }, */
to); /*new int[] { android.R.id.text1 } */
adapterPropTypes.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerType.setAdapter(adapterPropTypes);
spinnerRating.setSelection(pos);
spnLstPropType = new AdapterView.OnItemSelectedListener()
{
#Override
public void onItemSelected(AdapterView<?> parent, View view,
int pos, long id)
{
mPropType = id;
}
#Override
public void onNothingSelected(AdapterView<?> arg0) { }
};
spinnerType.setOnItemSelectedListener(spnLstPropType);
private int getItemPositionById(Cursor c, long id, DBAdapter adapter)
{
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext())
{
if (c.getLong(c.getColumnIndex(DBAdapter.C_COLUMN_ID)) == id)
{
return c.getPosition();
}
}
return 0;
}
private void query(long id)
{
mCursorHouses = mHouses.getRecord(id);
// Figure values being retrieved and set on their widgets instead of this comment... and now...
mPropType = mCursorHouses.getInt(mCursorHouses.getColumnIndex(PropDBAdapter.C_PROP_TYPE_ID));
spinnerType.setSelection(
getItemPositionById(
mCursorRatings,
mCursorHouses.getColumnIndex(PropDBAdapter.C_PROP_TYPE_ID),
mPropTypes
)
);
private void save()
{
ContentValues reg = new ContentValues();
// Read: values being put into 'reg'... eventually it should reach this:
reg.put(PropDBAdapter.C_PROP_TYPE_ID, mPropType);
try
{
if (mFormMode == PropListActivity.C_CREATE)
{
mHouses.insert(reg);
Toast.makeText(PropDetailActivity.this, R.string.house_create_notice, Toast.LENGTH_LONG).show();
}
else if (mFormMode == PropListActivity.C_EDIT)
{
Toast.makeText(PropDetailActivity.this, R.string.house_edit_notice, Toast.LENGTH_LONG).show();
reg.put(PropDBAdapter.C_COLUMN_ID, mPropId);
long resultCode = mHouses.update(reg);
Log.i(this.getClass().toString(), "Database operation result code: " + resultCode);
}
}
catch(SQLException e)
{
Log.i(this.getClass().toString(), e.getMessage());
}
setResult(RESULT_OK);
finish();
}
}
Spinners are being bad boys. Lazy bad boys on top of that.
They do load up the data -a list of real estate property types- they are meant to display.
After some spanking, that is.
But, hoping them to save THE VALUE YOU SELECT to SQLite? And to show THAT EXACT VALUE when fetching stuff back from the database?
Oh, no, no way no how.
They stubbornly stick to displaying always the same value upon activity startup.
So... please... I must draw upon your collective wisdom to save my sorry excuse for a project...
Pleasepleaseplease? :)
(IF you feel like diving into the whole uncut code, here's a GIT repository for you: https://github.com/CruxMDQ/Quoterv3)
Checking your code, I think I found the problem, change the following lines in your query method in PopDetailActivity.java.
For spinnerRating do:
spinnerRating.setSelection(
getItemPositionById(
mCursorRatings,
mCursorHouses.getInt(mCursorHouses.getColumnIndex(PropDBAdapter.C_PROP_RATING_ID)),
mRatings
)
);
and for spinnerType do:
spinnerType.setSelection(
getItemPositionById(
mCursorPropTypes,
mCursorHouses.getInt(mCursorHouses.getColumnIndex(PropDBAdapter.C_PROP_TYPE_ID)),
mPropTypes
)
);
EDIT:
In your query method, you initialize mPropTypeId, with the call to getItemPositionById() but in that call the first parameter should be mCursorPropTypes instead of mCursorHouses
A few things:
(1) I don't really see anywhere above where you actually create a SQLite database or use the SQLiteOpenHelper class to access that data. Take a look at this tutorial. It uses a simple single table set up to store data. Once you create the database it should be easy to read and write from it. Verify that you actually have a database created.
(2) Where are your SQL queries to return the data you're looking for? Even if data is being added you need to make sure you are getting the right data with your Cursor when you're done. If you're getting the same values each time is it possible that you are simply adding new data every time and retrieving the same value with your cursor - i.e. you're not telling the cursor to get the newly added data becuase you keep grabing the same index?
If you need to replace the data that's there you should be using update queries and not inserts.

How to set up Android's MockContentProvider

I'm currently testing Android's ContentProvider and running into some issues mocking it. I've already spent days on the internet but didn't find any useful examples except of the introduction on the Android Developer Site.
I implemented a ContentProvider and wrote some tests. Everything works here completely fine. The result of the tests are matching my expectations.
public class DirectMessageProviderTest extends ProviderTestCase2<DirectMessageProvider>{
#SmallTest
public void testInsert() {
Log.d(TAG, "testInsert");
/*
* result retrieves twitterId for the newly inserted item
*/
Uri result = provider.insert(
DirectMessageProvider.CONTENT_URI,
createContentValues());
Log.i(TAG, "INSERT; id for newly inserted item: " + result);
assertNotNull("INSERT!!! failed", result);
if (result != null) {
isDirectMessageInserted = true;
}
}
#SmallTest
public void testQuery() {
Log.d(TAG, "testQuery");
Uri uri = Uri.withAppendedPath(
DirectMessageProvider.CONTENT_URI,
String.valueOf(directMessage.getTwitterId()));
/*
* result retrieves a cursor or null
*/
Cursor result = provider.query(
uri,
null,
null,
null,
null);
Log.i(TAG, "QUERY; number of rows inside the cursor: " + result.getCount());
int expected = isDirectMessageInserted ? 1 : 0;
assertEquals("QUERY!!! failed", expected, result.getCount());
}
}
I also implemented a class which capsules the ContentProvider and provides more complex methods than delete, insert, query and update. Take a look!
public class DirectMessageDataAccessImpl implements
DirectMessageDataAccessInterface {
#Override
public boolean isStored(TwitterDirectMessage directMessage)
throws DataAccessException {
Log.d(TAG, "isStored");
try {
Uri uri = Uri.withAppendedPath(
DirectMessageProvider.CONTENT_URI,
String.valueOf(directMessage.getTwitterId()));
Cursor cursor = resolver.query(
uri,
null,
null,
null,
null);
cursor.moveToFirst();
boolean result = (cursor.getCount() > 0 ? true: false);
cursor.close();
return result;
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
throw new DataAccessException(e.getMessage());
}
}
}
Finally we`re coming to my problem writing a test for this class. I want to write independent tests for this class using a mocked ContentResolver. I've found this [example] (http://www.androidadb.com/source/npr-android-app-read-only/Npr_Test/src/org/npr/android/util/PlaylistProviderTest.java.html) on the internet and tried to use MockContentResolver.
First of all, I created a new ContentProvider which will retrieve the delete, insert, query and update calls from the tested class, to create the same answer again and again.
public class DirectMessageDataAccessTest extends ProviderTestCase2<DirectMessageProvider>{
private ContentProvider provider = new ContentProvider() {
#Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
Log.d(TAG, "update");
return 0;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
Log.w(TAG, "query");
return null;
}
#Override
public boolean onCreate() {
Log.d(TAG, "onCreate");
return false;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
Log.d(TAG, "insert");
return null;
}
#Override
public String getType(Uri uri) {
Log.d(TAG, "getType");
return null;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
Log.d(TAG, "delete");
return 0;
}
};
}
After this, I modified my setUp Method in order to create a MockContentResolver and added my ContentProvider above
#Override
protected void setUp() throws Exception {
super.setUp();
/*
* MockContentResolver overrides Android's normal way of resolving providers by authority
*/
MockContentResolver resolver = new MockContentResolver();
/*
* Adds access to a provider based on its authority
*/
resolver.addProvider(DirectMessageProvider.AUTHORITY, provider);
context = new IsolatedContext(resolver, getContext());
this.setContext(context);
}
Last but not least, I wrote a test case for my isStored Method.
public void testIsStored() {
Log.d(TAG, "testIsStored");
TwitterDirectMessage directMessage = new TwitterDirectMessage();
directMessage.setTwitterId(123456);
DirectMessageDataAccessInterface dataAccess =
new DirectMessageDataAccessImpl(context);
try {
assertFalse(dataAccess.isStored(directMessage));
} catch (DataAccessException e) {
e.printStackTrace();
fail("...");
}
}
Unfortunately, android.content.ContentProvider always throws a NullPointerException. I'm calling resolver.query(...)in line 72 of DirectMessageDataAccessImpl
E/DirectMessageDataAccessImpl(1758): null
E/DirectMessageDataAccessImpl(1758): java.lang.NullPointerException
E/DirectMessageDataAccessImpl(1758): at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:284)
E/DirectMessageDataAccessImpl(1758): at android.content.ContentProvider$Transport.query(ContentProvider.java:177)
E/DirectMessageDataAccessImpl(1758): at android.content.ContentResolver.query(ContentResolver.java:311)
E/DirectMessageDataAccessImpl(1758): at xxx.xxxxx.xxxxxxx.app.database.dataaccess.implementation.DirectMessageDataAccessImpl.isStored(DirectMessageDataAccessImpl.java:72)
E/DirectMessageDataAccessImpl(1758): at xxx.xxxxx.xxxxxxx.app.test.dataaccess.DirectMessageDataAccessTest.testIsStored(DirectMessageDataAccessTest.java:107)
In constructor you should set
public YourClass() {
super(DBProvider.class, "com.yourpackage.main");// class of Your Content provider and application package
}
and then just call
MockContentResolver mockContentResolver = getMockContentResolver();
assertNotNull(mockContentResolver);
in a tests

Addressing "Releasing statement in a finalizer. Please ensure that you explicitly call close() on your cursor"

I have two DB clsses, one copies the db file from assets to the phone.
the Second is where I have been putting my DB calls but in the log I am getting an awrful lot error about I should close the cursor. This I am getting confused about as all my calls have a cursor.close() on the end.
Code of second:
public class DatabaseTools extends Common {
private Context context;
private SQLiteDatabase db;
private DatabaseHelper dbHelper;
private Cursor cursor;
public DatabaseTools(Context context) {
this.context = context;
dbHelper = new DatabaseHelper(context);
db = dbHelper.getWritableDatabase();
}
// MARKS
public ArrayList<String> getNames(String value) {
Names = new ArrayList<String>();
selectStatement = new String[] { DB_COMMON_COL_NAME };
fromStatement = DB_COMMON_COL_VALUE + " = '" + value + "'";
cursor = db.query(
DB_DISTANCE_TABLE_NAME,
selectStatement,
fromStatement,
null,
null,
null,
null);
int distanceIndex = cursor.getColumnIndex(DB_COMMON_COL_NAME);
if (cursor.moveToFirst()) {
do {
distanceNames.add(cursor.getString(distanceIndex));
} while (cursor.moveToNext());
}
cursor.close();
return names;
}
Try the following modification to ensure you close your cursor. Also you're getting database instance in your constructor. That's not good. You should get database instance right before you work with the database, and call close() on the database, as soon as you're finished. I would suggest moving db = dbHelper.getWritableDatabase() inside the getNames(String value) method, than calling db.close() when you're done - also in finally block.
public ArrayList<String> getNames(String value) {
Names = new ArrayList<String>();
selectStatement = new String[] { DB_COMMON_COL_NAME };
fromStatement = DB_COMMON_COL_VALUE + " = '" + value + "'";
cursor = db.query(
DB_DISTANCE_TABLE_NAME,
selectStatement,
fromStatement,
null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
try {
int distanceIndex = cursor.getColumnIndexOrThrow(DB_COMMON_COL_NAME);
while(cursor.moveToNext()) {
distanceNames.add(cursor.getString(distanceIndex));
}
} finally {
if (!cursor.isClosed()) {
cursor.close();
}
}
return names;
}

Categories

Resources