Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sqlite Database updates triggers Service to update via Content Observer

I'm trying to use a Content Observer to update a Service when any changes happen to the sqlite database in my app.

I'm confused as to what to do, so I put together some code below. Usually, Content Observers are used with contacts or mediaplayer with a background service. In my research I read that it can be used with the sqlite database on the phone.

Questions: 1. Since Sqlite database does not have a uri, what info do I replace People.CONTENT_URI in

this.getContentResolver().registerContentObserver (People.CONTENT_URI, true, contentObserver);

2. In my research I didn't find any code that would go into the database class that would alert the ContentObserver. Does all the code for the Content Observer work within the service class?

Note that this question is similar to Android SQLite DB notifications and how to listen for changes in Contact Database Both questions do not explicitly answer my question. If you have code that explains this, that would be very helpful.

Here is my semi-pusedo code below. It does not work. I'm using it to learn about how to update a service when the database info changes.

package com.example.com.test.content.observer;

import java.sql.Date;
import java.util.Calendar;
import java.util.List;

import com.google.android.gcm.demo.app.Alerts.AlarmsService;
import com.google.android.gcm.demo.app.Alerts.Alerts;
import com.google.android.gcm.demo.app.sqllite.DatabaseSqlite;

import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.provider.Contacts.People;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.database.ContentObserver;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import android.support.v4.app.NavUtils;

public class AlarmService extends Service
{

    Handler mHandler = new Handler();
    DatabaseSqlite db = new DatabaseSqlite(this);
    List<Alerts> listAlerts;
    PendingIntent pendingIntent;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.getApplicationContext()
                .getContentResolver()
                .registerContentObserver(?????, true,
                        contentObserver);
    }


    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("TAG", "started onstart command Created from Alerts service .");
        return super.onStartCommand(intent, flags, startId);// START_STICKY;
    }

    @Override
    public void onStart(final Intent intent, int startId) {
        super.onStart(intent, startId);

         runThread();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(this, "Service destroyed...", Toast.LENGTH_LONG).show();
    }

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

    private class MyContentObserver extends ContentObserver {

        @SuppressLint("ParserError")
        public MyContentObserver(Handler mHandler) {
            super(mHandler);
        }

        @Override
        public void onChange(boolean selfChange) {

             runThread();

            super.onChange(selfChange);
        }



        public void runThread(){

            Thread thread = new Thread() {
                @Override
                public void run() {

                    Boolean x = true;
                    while (x) {

                        db.open();
                        listAlerts = db.getAlarmsForService();
                        db.close();
                        int alerts=listAlerts.size();
                        for (int i = 0; i < alerts; i++) {
                            Alerts item = listAlerts.get(i);
                            item.getRowId();
                            item.getRemoteServerId();
                        String alertInMills = item.getAlertDateInMills();
                        String alertDuration = item.getAlertDurationInMinutes();
                        String eventName = item.getEventName();


                        long longAlertInMills = Long.parseLong(alertInMills);



                         pendingIntent = PendingIntent.getService(AlarmsService.this, 0,intent, 0);

                         AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

                         Calendar calendar = Calendar.getInstance();

                        // go to data base for time in mills

                         calendar.setTimeInMillis(longAlertInMills);

                         alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
                         pendingIntent);
                        //
                         System.out.println(calendar.toString());

                        }

                        //
                        System.out.println("thread");
                        x = false;

                    }

                }
            };

            thread.start();
        }

        }


    MyContentObserver contentObserver = new MyContentObserver(mHandler);

    this.getContentResolver().registerContentObserver (People.CONTENT_URI, true, contentObserver);



}
like image 509
Leoa Avatar asked Oct 07 '22 22:10

Leoa


1 Answers

In general, there are two parts to handling this: you have the ContentObserver which needs to register to receive changes, as you've pointed out, and the SQLiteDatabase which has to notify the registered observers of any changes. If this is a database you own, you can create the URI that you can use to listen for.

(1) First define your URI, typically in your Database definition file.

public static final Uri CONTENT_URI = Uri.parse("mycontent://packagename/something");

(2) for your database Content Provider:

Each db function (insert, update, delete) should call through to notifyChange() after completing the operation in order to inform the observers that changes have happened.

    rowId = db.insert(tableName, null, cv);
    ...
    getContext().getContentResolver().notifyChange(newUri, null);

(3) Create and register your ContentObserver in the Service, as described in the same link you provided above (remember to override the deliverSelfNotifications() to return true)

public class MyService extends Service {
    private MyContentObserver mObserver;

    @Override
    public void onStartCommand(Intent intent, int flags, int startId) {
        ...
        mObserver = new MyContentObserver();
        getContentResolver().registerContentObserver(Dbfile.CONTENT_URI, null, mObserver);
    }

    @Override
    public void onDestroy() {
        ...
        if (mObserver != null) {
            getContentResolver().unregisterContentObserver(mObserver);
            mObserver = null;
        }
    }

    // define MyContentObserver here
}

(4) In your ContentObserver.onChange(), you can post something to the Service or handle the change right there if possible.

Also, if it helps your cause, you can customize the URI definition to handle different types of data that you are observing, register your observer for each URI, and then override ContentObserver.onChange(boolean, Uri) instead.

Hope this helps!

like image 141
anddev84 Avatar answered Oct 10 '22 02:10

anddev84