implement the android content provider's query method,with multiple tables in use -


i have 3 tables , use content provider manage them.below code content provider:

private static final urimatcher surimatcher = new urimatcher(         urimatcher.no_match); static {     surimatcher.adduri(authority, meter_path, all_meters);     surimatcher.adduri(authority, meter_path + "/#", single_meter);      surimatcher.adduri(authority, customers_path, all_customers);     surimatcher.adduri(authority, customers_path + "/#", single_customer);      surimatcher.adduri(authority, bill_path, all_bills);     surimatcher.adduri(authority, bill_path + "/#", single_bill);  }  @override public cursor query(uri uri, string[] projection, string selection,         string[] selectionargs, string sortorder) {      sqlitedatabase db = database.getwritabledatabase();      // using sqlitequerybuilder instead of query() method     sqlitequerybuilder querybuilder = new sqlitequerybuilder();  querybuilder             .settables(metertabledetails.table_meters                     + " meters "                     + " inner join "                     + customertabledetails.table_customers                     + " customers "                     + " on "                     + (metertabledetails.meter_id = customertabledetails.key_meter_id)                     + " inner join "                     + waterbilltabledetails.table_water_bill                     + " waterbills "                     + " on "                     + (customertabledetails.key_meter_id = waterbilltabledetails.bill_meter_id));     int uritype = surimatcher.match(uri);     switch (uritype) {      case all_meters:         break;     case single_meter:         // adding id original query          string id = uri.getpathsegments().get(1);         querybuilder.appendwhere(metertabledetails.meter_id + "=" + id);          break;      case all_customers:         break;     case single_customer:         // adding id original query         string id1 = uri.getpathsegments().get(1);         querybuilder.appendwhere(customertabledetails.key_customer_id + "="                 + id1);         break;      case all_bills:         break;     case single_bill:         // adding id original query         string id2 = uri.getpathsegments().get(1);         querybuilder.appendwhere(waterbilltabledetails.bill_id + "=" + id2);         break;      default:         throw new illegalargumentexception("unknown uri: " + uri);     }      cursor cursor = querybuilder.query(db, projection, selection,             selectionargs, null, null, sortorder);     // make sure potential listeners getting notified     cursor.setnotificationuri(getcontext().getcontentresolver(), uri);      return cursor; }  

i have 3 tables,and have created joins in querybuilder.settables method.i'm trying display meter items in list meters table.i have simplecursoradapter loadercallbacks implementation. following error in logcat , think it's because of joins , query:

03-20 15:11:59.692: e/sqlitecursor(2001): requesting column name table name -- meters._id 03-20 15:11:59.692: e/sqlitecursor(2001): java.lang.exception 03-20 15:11:59.692: e/sqlitecursor(2001):   @ android.database.sqlite.sqlitecursor.getcolumnindex(sqlitecursor.java:180) 03-20 15:11:59.692: e/sqlitecursor(2001):   @ android.database.abstractcursor.getcolumnindexorthrow(abstractcursor.java:301) 03-20 15:11:59.692: e/sqlitecursor(2001):   @ android.database.cursorwrapper.getcolumnindexorthrow(cursorwrapper.java:78) 03-20 15:11:59.692: e/sqlitecursor(2001):   @ android.support.v4.widget.simplecursoradapter.findcolumns(simplecursoradapter.java:317) 03-20 15:11:59.692: e/sqlitecursor(2001):   @ android.support.v4.widget.simplecursoradapter.swapcursor(simplecursoradapter.java:328) 03-20 15:11:59.692: e/sqlitecursor(2001):   @ com.isys.waterbillingsystem.metersactivity.onloadfinished(metersactivity.java:180) 03-20 15:11:59.692: e/sqlitecursor(2001):   @ com.isys.waterbillingsystem.metersactivity.onloadfinished(metersactivity.java:1) 

edit

private static final string create_customer_view = ""         + "create view " + table_customer_view          + " select "+metertabledetails.table_meters+"."+metertabledetails.meter_id+" "+ metertabledetails.table_meters+"."+metertabledetails.meter_id +","+         " "+customertabledetails.key_first_name+","+         " "+customertabledetails.key_last_name+","+         " "+customertabledetails.key_meter_id+","+         " "+customertabledetails.key_meter_number+","+         " "+customertabledetails.key_plot_number+","+         " "+customertabledetails.table_customers+"."+ customertabledetails.key_customer_id+         " "+customertabledetails.table_customers+" customers "+" inner join "+metertabledetails.table_meters+" meters"+         " on "+customertabledetails.key_meter_id+" = "+metertabledetails.table_meters+"."+metertabledetails.meter_id;    public static tabledescriptor getdescriptor() {     tabledescriptor descriptor = new tabledescriptor();     descriptor.settablename(table_customer_view);     descriptor.setcolumnid(customer_view_id);     string[] available = { viewcustomers.customer_view_id,             viewcustomers.customer_view_lastname,             viewcustomers.customer_view_lastname,             viewcustomers.customer_view_key_meter_id,             viewcustomers.customer_view_meter,             viewcustomers.customer_view_plot};      descriptor.setavailablecolumns(available);     return descriptor;     }     

edit 2

private static final string create_meter_reading_view = ""         + "create view " + table_meter_reading_view         + " select " + waterbilltabledetails.table_water_bill+ ".*"         + ", " +customertabledetails.table_customers+"."+customertabledetails.key_meter_number+","         +" "+customertabledetails.table_customers+"."+customertabledetails.key_plot_number+","         +" "+customertabledetails.table_customers+"."+customertabledetails.key_account_number+","          +" "+customertabledetails.table_customers+"."+customertabledetails.key_meter_id+""         +" "+waterbilltabledetails.table_water_bill+" waterbills "+" join "+customertabledetails.table_customers+" customers"         +" on "+waterbilltabledetails.bill_customer_id+" ="+customertabledetails.table_customers+"."+customertabledetails.key_customer_id; 

logcat error

03-25 10:45:03.476: e/androidruntime(1144): fatal exception: main 03-25 10:45:03.476: e/androidruntime(1144): java.lang.runtimeexception: unable start activity  componentinfo{com.isys.waterbillingsystem/com.isys.waterbillingsystem.customerdetailsaccountsactivity}:   java.lang.nullpointerexception 03-25 10:45:03.476: e/androidruntime(1144): caused by: java.lang.nullpointerexception 03-25 10:45:03.476: e/androidruntime(1144):     @  com.isys.waterbillingsystem.customerdetailsaccountsactivity.oncreate(customerdetailsaccountsactivity.java:48 ) 

here quick example views:

public class hektordatabasehelper extends sqliteopenhelper {      private static final string database_name = "hektor.db";     private static final int database_version = 91;      public hektordatabasehelper(context context) {         super(context, database_name, null, database_version);     }      // method called during creation of database     @override     public void oncreate(sqlitedatabase database) {         appointmenttypestable.oncreate(database);     }      // method called during upgrade of database,     // e.g. if increase database version     @override     public void onupgrade(sqlitedatabase database, int oldversion,             int newversion) {         appointmenttypestable.onupgrade(database, oldversion, newversion);     }   } 

this standard sqliteopenhelper.

    public class appointmentwithtypeandcontactsview {      public static final string table_name = "appointments_with_type_and_contacts";      public static final string column_id = appointmentstable.column_id;     public static final string column_external_id = appointmentstable.column_external_id;     public static final string column_start_date = appointmentstable.column_start_date;      private static final string database_create = ""             + "create view " + table_name              + " select " + appointmentstable.table_name + ".*"             + ", " + appointmenttypestable.table_name + "." + appointmenttypestable.column_name             + ", " + buyerstable.table_name + "." + buyerstable.column_title + " || ' ' || " + buyerstable.table_name + "." + buyerstable.column_last_name + " || ' ' || " + buyerstable.table_name + "." + buyerstable.column_first_name + " " + buyerstable.column_last_name             + ", " + sellersdetailstable.table_name + "." + sellersdetailstable.column_title + " || ' ' || " + sellersdetailstable.table_name + "." + sellersdetailstable.column_last_name + " || ' ' || " + sellersdetailstable.table_name + "." + sellersdetailstable.column_first_name + " " + sellersdetailstable.column_last_name             + " " + appointmentstable.table_name + " left outer join " + appointmenttypestable.table_name             + " on " + appointmentstable.table_name + "." + appointmentstable.column_type              + " = " + appointmenttypestable.table_name + "." + appointmenttypestable.column_external_id             + " left outer join " + buyerstable.table_name             + " on " +  appointmentstable.table_name + "." + appointmentstable.column_buyer             + " = " + buyerstable.table_name + "." + buyerstable.column_external_id             + " left outer join " + sellersdetailstable.table_name             + " on " +  appointmentstable.table_name + "." + appointmentstable.column_seller             + " = " + sellersdetailstable.table_name + "." + sellersdetailstable.column_external_id;        public static void oncreate(sqlitedatabase database) {         database.execsql(database_create);     }      public static void onupgrade(sqlitedatabase database, int oldversion,             int newversion) {         log.w(appointmentwithtypeandcontactsview.class.getname(), "upgrading database version "                 + oldversion + " " + newversion                 + ", destroy old data");         database.execsql("drop view if exists " + table_name);         oncreate(database);     }      public static tabledescriptor getdescriptor() {         tabledescriptor descriptor = new tabledescriptor();         descriptor.settablename(table_name);         descriptor.setcolumnid(column_id);          string[] appointmentsavailablecolumns = appointmentstable.getdescriptor().getavailablecolumns();         string[] typesavailablecolumns = new string[] {appointmenttypestable.column_name};         string[] buyersavailablecolumns = new string[] {buyerstable.column_last_name};         string[] sellerssavailablecolumns = new string[] {sellersdetailstable.column_last_name};          descriptor.setavailablecolumns(arrayutils.concatall(appointmentsavailablecolumns, typesavailablecolumns, buyersavailablecolumns, sellerssavailablecolumns));         return descriptor;     }  } 

i've updated table class include utility methods.

public class tabledescriptor {     private string tablename;     private string columnid;     private string[] availablecolumns;      public string gettablename() {         return tablename;     }      public void settablename(string tablename) {         this.tablename = tablename;     }      public string getcolumnid() {         return columnid;     }      public void setcolumnid(string columnid) {         this.columnid = columnid;     }      public string[] getavailablecolumns() {         return availablecolumns;     }      public void setavailablecolumns(string[] availablecolumns) {         this.availablecolumns = availablecolumns;     } } 

tabledescriptor container class.

public final class hektorcontentprovidercontract {     public static final string authority = "fr.intuitiv.hektor.contentprovider";      public static final string appointment_with_type_base_path = "appointment_with_type";     public static final uri appointment_with_type_content_uri = uri.parse("content://" + authority             + "/" + appointment_with_type_base_path);     public static final string appointment_with_type_content_type = contentresolver.cursor_dir_base_type             + "/vnd." + authority + "." + appointment_with_type_base_path;     public static final string appointment_with_type_content_item_type = contentresolver.cursor_item_base_type             + "/vnd." + authority + "." + appointment_with_type_base_path; } 

i create "contract" classes store public constants.

public class contentproviderhelper {     private context context;      public context getcontext() {         return context;     }      public void setcontext(context context) {         this.context = context;     }      public contentproviderhelper(context context) {         this.setcontext(context);     }      public cursor query(sqliteopenhelper database, tabledescriptor table,             boolean issingular, uri uri, string[] projection, string selection,             string[] selectionargs, string sortorder) {          // uisng sqlitequerybuilder instead of query() method         sqlitequerybuilder querybuilder = new sqlitequerybuilder();          // set table         querybuilder.settables(table.gettablename());          if (issingular) {             querybuilder.appendwhere(table.getcolumnid() + "="                     + uri.getlastpathsegment());         }          sqlitedatabase db = database.getwritabledatabase();         cursor cursor = querybuilder.query(db, projection, selection,                 selectionargs, null, null, sortorder);         // make sure potential listeners getting notified         cursor.setnotificationuri(getcontext().getcontentresolver(), uri);          return cursor;     }      public uri insert(sqliteopenhelper database, tabledescriptor table, uri uri, contentvalues values) {         sqlitedatabase sqldb = database.getwritabledatabase();         long id = 0;         id = sqldb.insertwithonconflict(table.gettablename(), null, values, sqlitedatabase.conflict_replace);         getcontext().getcontentresolver().notifychange(uri, null);         return uri.withappendedpath(gettableuri(table), long.tostring(id));     }      public int delete(sqliteopenhelper database, tabledescriptor table, boolean issingular, uri uri, string selection, string[] selectionargs) {         int rowsdeleted = 0;         sqlitedatabase sqldb = database.getwritabledatabase();         if (!issingular) {             rowsdeleted = sqldb.delete(table.gettablename(), selection,                     selectionargs);         } else {             string id = uri.getlastpathsegment();             if (textutils.isempty(selection)) {                 rowsdeleted = sqldb.delete(table.gettablename(),                         table.getcolumnid() + "=" + id, null);             } else {                 rowsdeleted = sqldb.delete(table.gettablename(),                         table.getcolumnid() + "=" + id + " , " + selection,                         selectionargs);             }         }         getcontext().getcontentresolver().notifychange(uri, null);         return rowsdeleted;     }      public int update(sqliteopenhelper database, tabledescriptor table, boolean issingular, uri uri, contentvalues values, string selection,             string[] selectionargs) {          sqlitedatabase sqldb = database.getwritabledatabase();         int rowsupdated = 0;         if (!issingular) {             rowsupdated = sqldb.update(table.gettablename(), values, selection,                     selectionargs);         } else {             string id = uri.getlastpathsegment();             if (textutils.isempty(selection)) {                 rowsupdated = sqldb.update(table.gettablename(), values,                         table.getcolumnid() + "=" + id, null);             } else {                 rowsupdated = sqldb.update(table.gettablename(), values,                         table.getcolumnid() + "=" + id + " , " + selection,                         selectionargs);             }         }         getcontext().getcontentresolver().notifychange(uri, null);         return rowsupdated;     }      public void checkcolumns(tabledescriptor table, string[] projection) {         string[] available = table.getavailablecolumns();         if (projection != null) {             hashset<string> requestedcolumns = new hashset<string>(                     arrays.aslist(projection));             hashset<string> availablecolumns = new hashset<string>(                     arrays.aslist(available));             // check if columns requested available             if (!availablecolumns.containsall(requestedcolumns)) {                 throw new illegalargumentexception(                         "unknown columns in projection");             }         }     }      protected uri gettableuri(tabledescriptor table) {         uri result = null;          string tablename = table.gettablename();         if (appointmentwithtypeview.table_name.equals(tablename)) {             result = hektorcontentprovidercontract.appointment_with_type_content_uri;         }          return result;     } } 

here utility class i'm using when working contentproviders. simplifies database management operations. quite handy if have lot of tables manage.

public class uridescriptor {     private tabledescriptor table;     private boolean singular;      public boolean issingular() {         return singular;     }      public void setsingular(boolean singular) {         this.singular = singular;     }      public tabledescriptor gettable() {         return table;     }      public void settable(tabledescriptor table) {         this.table = table;     } } 

this again container class - not interesting.

public class hektorcontentprovider extends contentprovider {      private contentproviderhelper helper;      // database     private hektordatabasehelper database;      // used urimacher     private static final int appointment_with_type = 290;     private static final int appointment_with_type_id = 300;      private static final urimatcher surimatcher = new urimatcher(             urimatcher.no_match);     static {         surimatcher.adduri(hektorcontentprovidercontract.authority,                 hektorcontentprovidercontract.appointment_with_type_base_path, appointment_with_type);         surimatcher.adduri(hektorcontentprovidercontract.authority,                 hektorcontentprovidercontract.appointment_with_type_base_path + "/#",                 appointment_with_type_id);     }      @override     public boolean oncreate() {         database = new hektordatabasehelper(getcontext());         helper = new contentproviderhelper(getcontext());         return false;     }      @override     public cursor query(uri uri, string[] projection, string selection,             string[] selectionargs, string sortorder) {          uridescriptor descriptor = getdescriptor(uri);         helper.checkcolumns(descriptor.gettable(), projection);          cursor cursor = helper.query(database, descriptor.gettable(),                 descriptor.issingular(), uri, projection, selection,                 selectionargs, sortorder);          return cursor;     }      @override     public string gettype(uri uri) {         return null;     }      @override     public uri insert(uri uri, contentvalues values) {         uridescriptor descriptor = getdescriptor(uri);         uri result = helper                 .insert(database, descriptor.gettable(), uri, values);         return result;     }      @override     public int delete(uri uri, string selection, string[] selectionargs) {         int rowsdeleted = 0;         uridescriptor descriptor = getdescriptor(uri);         rowsdeleted = helper.delete(database, descriptor.gettable(),                 descriptor.issingular(), uri, selection, selectionargs);         return rowsdeleted;     }      @override     public int update(uri uri, contentvalues values, string selection,             string[] selectionargs) {          uridescriptor descriptor = getdescriptor(uri);         int rowsupdated = helper.update(database, descriptor.gettable(),                 descriptor.issingular(), uri, values, selection, selectionargs);         return rowsupdated;     }      protected uridescriptor getdescriptor(uri uri) {         uridescriptor descriptor = new uridescriptor();          int uritype = surimatcher.match(uri);         switch (uritype) {         case appointment_with_type:             descriptor.setsingular(false);             descriptor.settable(appointmentwithtypeview.getdescriptor());             break;         case appointment_with_type_id:             descriptor.setsingular(true);             descriptor.settable(appointmentwithtypeview.getdescriptor());             break;         default:             throw new illegalargumentexception("unknown uri: " + uri);         }          return descriptor;     }  } 

that's contentprovider class. quite simple, since of work done in contentproviderhelper class.

this class representing view. write such classes each view or table want create in database. both entities pretty used same way - have change sql statement create view create table. can see, views can created based on select statement - useful if want join several tables. when inserting of appointmentstable / appointmenttypestable tables data available via view too. prefer create such view , contentprovider working on it. select queries simple (just read view). have handle insert / deletes differently though - i.e. insert data associated table.

my application loads data web service, i'm doing on background. i've create content_url in contentprovider each table (i.e. appointmentstable , appointmenttypestable). used background process insert / update data. ui uses content_urls connected views, since need read data.

let me know if you've got idea. share more code if needed. :)


Comments

Popular posts from this blog

java - WrongTypeOfReturnValue exception thrown when unit testing using mockito -

php - Magento - Deleted Base url key -

android - How to disable Button if EditText is empty ? -