Cursor : Invalid Statement in fillWindow()

Forums » Android - Learning Android book > Cursor : Invalid Statement in fillWindow()
July 29, 2011 11:05:16 AM PDT (one year ago). Seen 2,990 times. 2 replies.
Photo Adithya Narayan
Engineer
SGS
Member since Jul 19, 2011
Forum Posts: 23
Hi,

I am getting this error while the
UpdaterService
is broadcasting the Intent and the
TimelineActivity
is receiving it.

What i am doing is :
Through Web i am updating a status. Then through my application i am starting the service manually and the service is fetching updates. When it is fetching my update (and any new updates if available ) the service is broadcasting the intent specified and my TimelineActivity is receiving it properly. but when it tried requering the cursor in
onReceive
i faced the below mentioned error. I was thinking that onPause might be getting called whenever i open the menu but that isn't the case as i verified using LogCat comments. I read somewhere that my database is not in scope when i am requering my cursor but now how do i figure that out ? I have closed the adapter's cursor and the database's cursor wherever possible like onPause(),onStop() of TimelineActivity. That is of no use though as they aren't getting called at all in any way until i close the activity !

ERROR/Cursor(320): Invalid statement in fillWindow()
. The error is occuring in the statement cursor.requery().

1)TimelineActivity.java

Code:
public class TimelineActivity extends BaseActivity {

public static final String TAG = "TimelineActivity";
private Cursor cursor;
private ListView listTimeline;
//Adapter for connecting ListView and the cursor containing info from database
private SimpleCursorAdapter timelineAdapter;
static final String[] FROM = { DBHelper.C_CREATED_AT, DBHelper.C_USER,
DBHelper.C_TEXT };
static final int[] TO = { R.id.textCreatedAt, R.id.textUser, R.id.textText };

YambaApplication yamba;
private TimelineReceiver timelineReceiver = null;
private IntentFilter intentFilter = new IntentFilter("com.pack.android.yamba.NEW_STATUS");

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.timeline);

//Fetch the views
listTimeline = (ListView) findViewById(R.id.listTimeline);

yamba = (YambaApplication) getApplication();
if(yamba.getSharedPreferences().getString("username", null) == null)
{
startActivity(new Intent(this, PrefsActivity.class)); //
Toast.makeText(this, R.string.msgSetupPrefs, Toast.LENGTH_LONG).show();
}

// Check if preferences have been set
if (yamba.getSharedPreferences().getString("username", null) == null) { //
startActivity(new Intent(this, PrefsActivity.class));
Toast.makeText(this, R.string.msgSetupPrefs, Toast.LENGTH_LONG).show();
}

timelineReceiver = new TimelineReceiver();
}

@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "On Destroy of Timeline Activity called !");
//close the database
yamba.getStatusData().close();
}

//TODO : check for onWindowFocusChanged(boolean hasFocus) method for detailed test
@Override
protected void onResume() {
super.onResume();
Log.d(TAG, "On Resume of Timeline Activity called !");
setUpList();
Log.d(TAG, "Setting up list completed !");
registerReceiver(timelineReceiver, intentFilter);
}

@Override
protected void onPause() {
super.onPause();
Log.d(TAG, "On Pause of Timeline Activity called !");
Log.d(TAG, "In onPause timelineAdapter.getCursor().close() "+timelineAdapter.getCursor());
timelineAdapter.getCursor().close();
Log.d(TAG, "Closed timelineAdapter.getCursor");
Log.d(TAG, "In onPause cursor = "+cursor);
cursor.close();
Log.d(TAG, "Closed cursor");
unregisterReceiver(timelineReceiver);
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
Log.d(TAG, "Does Timeline Activity has focus ? "+ hasFocus);
}

@Override
protected void onStop() {
super.onStop();
Log.d(TAG, "OnStop of Timeline Activity called !");
Log.d(TAG, "In onStop timelineAdapter.getCursor().close() "+timelineAdapter.getCursor());
timelineAdapter.getCursor().close();
Log.d(TAG, "Closed timelineAdapter.getCursor");
Log.d(TAG, "In onStop cursor = "+cursor);
cursor.close();
Log.d(TAG, "Closed cursor");
}

private void setUpList() {

// Get the data from the database
// TODO : verify for honeycomb which will use loaderManagers for managing lifecycle of a cursor
Log.d(TAG, "Setting up the list");
cursor = yamba.getStatusData().getStatusUpdates();
Log.d(TAG, "cursor is "+ cursor);
startManagingCursor(cursor);

// Setup Adapter
timelineAdapter = new SimpleCursorAdapter(this, R.layout.row, cursor, FROM, TO);
Log.d(TAG, "Timeline adapter is "+ timelineAdapter);
Log.d(TAG, "Count of data = " + timelineAdapter.getCount());
Log.d(TAG, "Is cursor empty ? " + timelineAdapter.isEmpty());
timelineAdapter.setViewBinder(VIEW_BINDER); //
listTimeline.setAdapter(timelineAdapter);
}

static final ViewBinder VIEW_BINDER = new ViewBinder() {

@Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
if(view.getId() != R.id.textCreatedAt)
return false;

// Update the created at text to relative time
long timeStamp = cursor.getLong(columnIndex);
CharSequence relativetime = DateUtils.getRelativeTimeSpanString(timeStamp);
((TextView)view).setText(relativetime);
return true;
}
};

class TimelineReceiver extends BroadcastReceiver
{
private static final String TAG = "TimelineReceiver";
@Override
public void onReceive(Context context, Intent intent)
{
Log.d(TAG, "Just before requery, cursor is " + cursor);
cursor.requery(); //
Log.d(TAG, "Just after requery");
timelineAdapter.notifyDataSetChanged(); //
Log.d(TAG, "on Receive of "+TAG);
}
}
}


2)UpdaterService

Code:
public class UpdaterService extends Service {

private static final String TAG = "UpdaterService";
final static int DELAY = 60000;
private boolean runFlag;
private Thread updaterThread = null;
private YambaApplication yambaApplication = null;
private List<Twitter.Status> tweets = null;

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

@Override
public void onCreate() {
try
{
super.onCreate();
yambaApplication = (YambaApplication) getApplication();
Log.d(TAG, "onCreated of UpdaterService");
}
catch(Exception e)
{
Log.d(TAG, e.toString());
}
}

@Override
public void onDestroy() {
try
{
super.onDestroy();
this.runFlag = false;
yambaApplication.setServiceRunning(false);
if(this.updaterThread != null)
{
this.updaterThread.interrupt();
this.updaterThread = null;
}
Log.d(TAG, "onDestroyed");
}
catch(Exception e)
{
Log.d(TAG, e.toString());
}
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
try
{
Log.d(TAG, "On Start Command of Updater Service");
updaterThread = new Thread(new UpdaterThread(),"Status Updater thread");
updaterThread.start();
yambaApplication.setServiceRunning(true);
this.runFlag = yambaApplication.isServiceRunning();
Log.d(TAG, "Is Yamba Applications' service running ? "+ yambaApplication.isServiceRunning());
Log.d(TAG, "Is Run flag true ? "+runFlag);
tweets = new ArrayList<Twitter.Status>();
}
catch(Exception e)
{
Log.d(TAG, e.toString());
return 0;
}
return START_STICKY;
}

class UpdaterThread implements Runnable
{
UpdaterService updaterService = UpdaterService.this;

@Override
public void run()
{
Log.d(TAG, "Inside Updater thread run !");
while(updaterService.runFlag)
{
Log.d(TAG, Thread.currentThread().getName()+" running");
try
{
YambaApplication yamba = (YambaApplication) updaterService
.getApplication(); //
int newUpdates = yamba.fetchStatusUpdates(); //
if (newUpdates > 0)
{ //
Log.d(TAG, "We have a new status");

//Broadcast intent so that timeline activity is updated whenever a new status is received
Intent intent = new Intent("com.pack.android.yamba.NEW_STATUS");
String NEW_STATUS_EXTRA_COUNT = "com.pack.android.yamba.EXTRA_COUNT";
intent.putExtra(NEW_STATUS_EXTRA_COUNT, newUpdates);
updaterService.sendBroadcast(intent);
}

Log.d(TAG, "Updater thread going to sleep..");
Thread.sleep(DELAY);
Log.d(TAG, "Updater thread is about to resume..");
}
catch(InterruptedException ie)
{
updaterService.runFlag = false;
Log.d(TAG, ie.toString());
ie.printStackTrace();
}
}
}
}
}


3)YambaApplication

Code:
public class YambaApplication extends Application implements OnSharedPreferenceChangeListener
{
private static final String TAG = YambaApplication.class.getSimpleName();
private Twitter twitter = null;
private SharedPreferences sharedPreferences = null;
private boolean serviceRunning = false;

private StatusData statusData = null;

public SharedPreferences getSharedPreferences() {
return sharedPreferences;
}

public void setSharedPreferences(SharedPreferences sharedPreferences) {
this.sharedPreferences = sharedPreferences;
}

public StatusData getStatusData() {
return statusData;
}

public void setStatusData(StatusData statusData) {
this.statusData = statusData;
}

public boolean isServiceRunning() {
return serviceRunning;
}

public void setServiceRunning(boolean serviceRunning) {
this.serviceRunning = serviceRunning;
}

public void setTwitter(Twitter twitter) {
this.twitter = twitter;
}

@Override
public void onCreate()
{
super.onCreate();
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
sharedPreferences.registerOnSharedPreferenceChangeListener(this);

statusData = new StatusData(getApplicationContext());

Log.i(TAG, "onCreated");
}

@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key)
{
this.twitter = null;
}

@Override
public void onTerminate()
{
super.onTerminate();
Log.i(TAG, "onTerminated");
}

public synchronized int fetchStatusUpdates()
{
Log.d(TAG, "Fetching status updates");
Twitter twitter = this.getTwitter();

if (twitter == null)
{
Log.d(TAG, "Twitter connection info not initialized");
return 0;
}

try
{
List<Status> statusUpdates = twitter.getFriendsTimeline();
long latestStatusCreatedAtTime = this.getStatusData()
.getLatestStatusCreatedAtTime();

int count = 0;
ContentValues values = new ContentValues();

for (Status status : statusUpdates)
{
values.clear();
values.put(StatusData.C_ID, status.getId());
long createdAt = status.getCreatedAt().getTime();
values.put(StatusData.C_CREATED_AT, createdAt);
values.put(StatusData.C_TEXT, status.getText());
values.put(StatusData.C_USER, status.getUser().getName());
Log.d(TAG, "Got update with id " + status.getId() + ". Saving");
this.getStatusData().insertOrIgnore(values);
if (latestStatusCreatedAtTime < createdAt) {
count++;
}
}
Log.d(TAG, count > 0 ? "Got " + count + " status updates"
: "No new status updates");

return count;
}
catch (RuntimeException e)
{
Log.e(TAG, "Failed to fetch status updates", e);
return 0;
}
}

public synchronized Twitter getTwitter()
{
if (this.twitter == null)
{
String username = sharedPreferences.getString("username", "");
String password = sharedPreferences.getString("password", "");
String apiRoot = sharedPreferences.getString("apiRoot",
"http://yamba.marakana.com/api");

if (!TextUtils.isEmpty(username) && !TextUtils.isEmpty(password)
&& !TextUtils.isEmpty(apiRoot))
{
this.twitter = new Twitter(username, password);
this.twitter.setAPIRootUrl(apiRoot);
}
}
return this.twitter;
}
}


4)StatusData

Code:
public class StatusData 
{
private static final String TAG = StatusData.class.getSimpleName();
private static final String DATABASE = "timeline.db"; //
private static final int VERSION = 1; //
public static final String TABLE = "timeline"; //

public static final String C_ID = BaseColumns._ID;
public static final String C_CREATED_AT = "created_at";
public static final String C_SOURCE = "source";
public static final String C_TEXT = "txt";
public static final String C_USER = "user";

private static final String GET_ALL_ORDER_BY = C_CREATED_AT + " DESC";
private static final String[] MAX_CREATED_AT_COLUMNS = { "max("
+ StatusData.C_CREATED_AT + ")" };
private static final String[] DB_TEXT_COLUMNS = { C_TEXT };

private final DBHelper dbHelper;

public StatusData(Context context) {
this.dbHelper = new DBHelper(context);
Log.i(TAG, "Initialized data");
}

//Insert data into the database and ignore if there are any conflicts
public void insertOrIgnore(ContentValues values)
{ //
Log.d(TAG, "insertOrIgnore on " + values);
SQLiteDatabase db = this.dbHelper.getWritableDatabase(); //
try
{
db.insertWithOnConflict(TABLE, null, values,
SQLiteDatabase.CONFLICT_IGNORE); //
}
finally
{
db.close(); //
}
}

/**
*
* @return Cursor where the columns are _id, created_at, user, txt
*/
public Cursor getStatusUpdates() { //
SQLiteDatabase db = this.dbHelper.getReadableDatabase();
return db.query(TABLE, null, null, null, null, null, GET_ALL_ORDER_BY);
}

/**
*
* @return Timestamp of the latest status we have it the database
*/
public long getLatestStatusCreatedAtTime() { //
SQLiteDatabase db = this.dbHelper.getReadableDatabase();
try {
Cursor cursor = db.query(TABLE, MAX_CREATED_AT_COLUMNS, null, null, null,
null, null);
try {
return cursor.moveToNext() ? cursor.getLong(0) : Long.MIN_VALUE;
} finally {
cursor.close();
}
} finally {
db.close();
}
}
/**
*
* @param id of the status we are looking for
* @return Text of the status
*/
public String getStatusTextById(long id) { //
SQLiteDatabase db = this.dbHelper.getReadableDatabase();
try {
Cursor cursor = db.query(TABLE, DB_TEXT_COLUMNS, C_ID + "=" + id, null,
null, null, null);
try {
return cursor.moveToNext() ? cursor.getString(0) : null;
} finally {
cursor.close();
}
} finally {
db.close();
}
}

public void close()
{
this.dbHelper.close();
}

public void delete()
{

}

class DBHelper extends SQLiteOpenHelper{

private DBHelper(Context context) {
super(context, DATABASE, null, VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {

Log.i(TAG, "Creating Database");
String sql = "create table " + TABLE + " (" + C_ID + " int primary key, "
+ C_CREATED_AT + " int, " + C_USER + " text, " + C_TEXT + " text, " + C_SOURCE + " text)";

db.execSQL(sql);

Log.d(TAG, "Created a table");
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

// db.execSQL("alter table " + TABLE + " add " + C_SOURCE + " text");
db.execSQL("drop table if exists " + TABLE); // drops the old database
Log.d(TAG, "onUpdated");
onCreate(db); // run onCreate to get new database
}
}
}



After this error my Timeline Activity doesn't anything on the ListView of the window.
Please help.

Can someone explain ?


Edited 2 times. Last edit by Adithya Narayan on Jul 29, 2011 at 11:05:16 AM (about one year ago).
July 31, 2011 6:18:35 AM PDT (one year ago)
Photo Adithya Narayan
Engineer
SGS
Member since Jul 19, 2011
Forum Posts: 23
Hi,

I resolved this issue by using the cursor of StatusData. Probably there were many cursors pointing to the database which was giving that exception to me.
April 12, 2012 5:57:23 PM PDT (one year ago)
Photo Aaron Bernstein
NA
Member since Apr 12, 2012
Forum Posts: 2
Can you show me what you did? I am having the same problem. Thank You.