Confused about _ID (ContentProviders)

Put problem concerning Views, Layouts and other XML-Resources (like AndroidManifest) here.

Confused about _ID (ContentProviders)

Postby mangaluve » Thu Mar 26, 2009 11:23 am

Im reading about ContentProviders, but something is confusing me. All the docs says that I have to have a field called _ID. But where do I need this field to have exactly this name? For instance if I store my data in a database. Is the database required to have a field with exactly that name? Or can I call it whatever I want? Where is exactly that name needed?
mangaluve
Experienced Developer
Experienced Developer
 
Posts: 82
Joined: Mon Mar 23, 2009 8:59 pm

Top

Postby WarrenFaith » Thu Mar 26, 2009 11:38 am

Check the class BaseColumns.
I implement it with every table I use so I dont have to care about the primary id :)
WarrenFaith
Moderator
Moderator
 
Posts: 227
Joined: Fri Mar 13, 2009 10:59 am
Location: Berlin, Germany

Postby mangaluve » Thu Mar 26, 2009 12:37 pm

I don't really understand what you mean. Where do you use it and how (BaseColumns). Is the _ID field required at all (with that exact name)? Couldn't I have a database where the id of a row is called MYID instead? is it somethings pecial with the name _ID?
mangaluve
Experienced Developer
Experienced Developer
 
Posts: 82
Joined: Mon Mar 23, 2009 8:59 pm

Postby WarrenFaith » Thu Mar 26, 2009 1:15 pm

Sorry, i am on my way out, but here is my provider and my data classes. Simply inspired by the notepad tutorial:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. package com.droidnova.android.lineofsight.data;
  2.  
  3.  
  4.  
  5. import android.net.Uri;
  6.  
  7. import android.provider.BaseColumns;
  8.  
  9.  
  10.  
  11. /**
  12.  
  13.  * Convenience definitions for PlayerProvider.
  14.  
  15.  *
  16.  
  17.  * @author Martin
  18.  
  19.  */
  20.  
  21. public final class LineOfSightData {
  22.  
  23.     public static final String AUTHORITY = "com.droidnova.android.lineofsight.provider.LineOfSightData";
  24.  
  25.  
  26.  
  27.     /**
  28.  
  29.      * The name of the database file.
  30.  
  31.      */
  32.  
  33.     public static final String DATABASE_NAME = "avatar.db";
  34.  
  35.  
  36.  
  37.     /**
  38.  
  39.      * User table.
  40.  
  41.      *
  42.  
  43.      * @author Martin
  44.  
  45.      */
  46.  
  47.     public static final class Player implements BaseColumns {
  48.  
  49.         private Player() {
  50.  
  51.         }
  52.  
  53.  
  54.  
  55.         /**
  56.  
  57.          * The content:// style URL for this table
  58.  
  59.          */
  60.  
  61.         public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/avatar");
  62.  
  63.  
  64.  
  65.         /**
  66.  
  67.          * The MIME type of {@link #CONTENT_URI} providing a directory of users.
  68.  
  69.          */
  70.  
  71.         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.lineofsight.avatar";
  72.  
  73.  
  74.  
  75.         /**
  76.  
  77.          * The MIME type of a {@link #CONTENT_URI} sub-directory of a single
  78.  
  79.          * user.
  80.  
  81.          */
  82.  
  83.         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.lineofsight.avatar";
  84.  
  85.  
  86.  
  87.         /**
  88.  
  89.          * The default sort order for this table
  90.  
  91.          */
  92.  
  93.         public static final String DEFAULT_SORT_ORDER = "id DESC";
  94.  
  95.  
  96.  
  97.         /**
  98.  
  99.          * The name of the character.
  100.  
  101.          */
  102.  
  103.         public static final String NAME = "name";
  104.  
  105.  
  106.  
  107.         /**
  108.  
  109.          * The gender of the character.
  110.  
  111.          */
  112.  
  113.         public static final String GENDER = "gender";
  114.  
  115.  
  116.  
  117.         /**
  118.  
  119.          * The Race of the character.
  120.  
  121.          */
  122.  
  123.         public static final String RACE = "race";
  124.  
  125.  
  126.  
  127.         /**
  128.  
  129.          * The level the character currently is.
  130.  
  131.          */
  132.  
  133.         public static final String LEVEL = "level";
  134.  
  135.  
  136.  
  137.         /**
  138.  
  139.          * The amount of experience the character has.
  140.  
  141.          */
  142.  
  143.         public static final String EXPERIENCE = "experience";
  144.  
  145.        
  146.  
  147.         /**
  148.  
  149.          * The amount of health the character has.
  150.  
  151.          */
  152.  
  153.         public static final String CURRENT_HEALTH = "current_health";
  154.  
  155.        
  156.  
  157.         /**
  158.  
  159.          * The amount of witcheries the character currently has.
  160.  
  161.          */
  162.  
  163.         public static final String CURRENT_WITCHERIES = "current_witcheries";
  164.  
  165.  
  166.  
  167.         /**
  168.  
  169.          * The strength the character has.
  170.  
  171.          */
  172.  
  173.         public static final String STRENGTH = "strength";
  174.  
  175.  
  176.  
  177.         /**
  178.  
  179.          * The agility the character has.
  180.  
  181.          */
  182.  
  183.         public static final String AGILITY = "agility";
  184.  
  185.  
  186.  
  187.         /**
  188.  
  189.          * The life the character has.
  190.  
  191.          */
  192.  
  193.         public static final String LIFE = "life";
  194.  
  195.  
  196.  
  197.         /**
  198.  
  199.          * The witchcraft the character has.
  200.  
  201.          */
  202.  
  203.         public static final String WITCHCRAFT = "witchcraft";
  204.  
  205.        
  206.  
  207.         /**
  208.  
  209.          * Free points to assign to other things.
  210.  
  211.          */
  212.  
  213.         public static final String ATTRIBUTE_POINTS = "attribute_points";
  214.  
  215.     }
  216.  
  217. }
Parsed in 0.040 seconds, using GeSHi 1.0.8.4
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. package com.droidnova.android.lineofsight.provider;
  2.  
  3.  
  4.  
  5. import java.util.HashMap;
  6.  
  7.  
  8.  
  9. import android.content.ContentProvider;
  10.  
  11. import android.content.ContentUris;
  12.  
  13. import android.content.ContentValues;
  14.  
  15. import android.content.Context;
  16.  
  17. import android.content.UriMatcher;
  18.  
  19. import android.database.Cursor;
  20.  
  21. import android.database.sqlite.SQLiteDatabase;
  22.  
  23. import android.database.sqlite.SQLiteOpenHelper;
  24.  
  25. import android.net.Uri;
  26.  
  27. import android.text.TextUtils;
  28.  
  29. import android.util.Log;
  30.  
  31.  
  32.  
  33. import com.droidnova.android.lineofsight.data.LineOfSightData;
  34.  
  35. import com.droidnova.android.lineofsight.data.LineOfSightData.Player;
  36.  
  37.  
  38.  
  39. /**
  40.  
  41.  * Entity class for a database with one table.
  42.  
  43.  *
  44.  
  45.  * @author Martin
  46.  
  47.  */
  48.  
  49. public class AvatarProvider extends ContentProvider {
  50.  
  51.    
  52.  
  53.     /* Tag for logging */
  54.  
  55.     private static final String TAG = "AvatarProvider";
  56.  
  57.    
  58.  
  59.     private static final int CHARACTER = 1;
  60.  
  61.     private static final int CHARACTER_ID = 2;
  62.  
  63.    
  64.  
  65.     private static final String DATABASE_TABLE = "avatar";
  66.  
  67.  
  68.  
  69.     private static final int DATABASE_VERSION = 1;
  70.  
  71.  
  72.  
  73.     private static final UriMatcher uriMatcher;
  74.  
  75.    
  76.  
  77.     private static HashMap<String, String> userProjectionMap;
  78.  
  79.    
  80.  
  81.     private DatabaseHelper openHelper;
  82.  
  83.    
  84.  
  85.     @Override
  86.  
  87.     public boolean onCreate() {
  88.  
  89.         openHelper = new DatabaseHelper(getContext());
  90.  
  91.         return true;
  92.  
  93.     }
  94.  
  95.  
  96.  
  97.     @Override
  98.  
  99.     public int delete(Uri uri, String where, String[] whereArgs) {
  100.  
  101.         SQLiteDatabase db = openHelper.getWritableDatabase();
  102.  
  103.         int count;
  104.  
  105.         switch (uriMatcher.match(uri)) {
  106.  
  107.             case CHARACTER:
  108.  
  109.                 count = db.delete(DATABASE_TABLE, where, whereArgs);
  110.  
  111.                 break;
  112.  
  113.    
  114.  
  115.             case CHARACTER_ID:
  116.  
  117.                 String playerId = uri.getPathSegments().get(1);
  118.  
  119.                 count = db.delete(DATABASE_TABLE, Player._ID + "=" + playerId
  120.  
  121.                         + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
  122.  
  123.                 break;
  124.  
  125.    
  126.  
  127.             default:
  128.  
  129.                 throw new IllegalArgumentException("Unknown URI " + uri);
  130.  
  131.         }
  132.  
  133.  
  134.  
  135.         getContext().getContentResolver().notifyChange(uri, null);
  136.  
  137.         return count;
  138.  
  139.     }
  140.  
  141.  
  142.  
  143.     @Override
  144.  
  145.     public String getType(Uri uri) {
  146.  
  147.         switch (uriMatcher.match(uri)) {
  148.  
  149.             case CHARACTER:
  150.  
  151.                 return Player.CONTENT_TYPE;
  152.  
  153.    
  154.  
  155.             case CHARACTER_ID:
  156.  
  157.                 return Player.CONTENT_ITEM_TYPE;
  158.  
  159.    
  160.  
  161.             default:
  162.  
  163.                 throw new IllegalArgumentException("Unknown URI " + uri);
  164.  
  165.         }
  166.  
  167.     }
  168.  
  169.  
  170.  
  171.     @Override
  172.  
  173.     public Uri insert(Uri uri, ContentValues values) {
  174.  
  175.         // validate the uri
  176.  
  177.         if (uriMatcher.match(uri) != CHARACTER) {
  178.  
  179.             throw new IllegalArgumentException("Unknown URI " + uri);
  180.  
  181.         }
  182.  
  183.        
  184.  
  185.         SQLiteDatabase db = openHelper.getWritableDatabase();
  186.  
  187.         long id = db.insert(DATABASE_TABLE, null, values);
  188.  
  189.         if (id == -1) {
  190.  
  191.             return null;
  192.  
  193.         } else {
  194.  
  195.             return ContentUris.withAppendedId(Player.CONTENT_URI, id);
  196.  
  197.         }
  198.  
  199.     }
  200.  
  201.  
  202.  
  203.     @Override
  204.  
  205.     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
  206.  
  207.         SQLiteDatabase db = openHelper.getWritableDatabase();
  208.  
  209.         return db.query(DATABASE_TABLE, projection, selection, selectionArgs, null, null, sortOrder);
  210.  
  211.     }
  212.  
  213.  
  214.  
  215.     @Override
  216.  
  217.     public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
  218.  
  219.         SQLiteDatabase db = openHelper.getWritableDatabase();
  220.  
  221.         int count;
  222.  
  223.         switch (uriMatcher.match(uri)) {
  224.  
  225.             case CHARACTER:
  226.  
  227.                 count = db.update(DATABASE_TABLE, values, where, whereArgs);
  228.  
  229.                 break;
  230.  
  231.    
  232.  
  233.             case CHARACTER_ID:
  234.  
  235.                 String playerId = uri.getPathSegments().get(1);
  236.  
  237.                 count = db.update(DATABASE_TABLE, values, Player._ID + "=" + playerId
  238.  
  239.                         + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
  240.  
  241.                 break;
  242.  
  243.    
  244.  
  245.             default:
  246.  
  247.                 throw new IllegalArgumentException("Unknown URI " + uri);
  248.  
  249.         }
  250.  
  251.  
  252.  
  253.         getContext().getContentResolver().notifyChange(uri, null);
  254.  
  255.         return count;
  256.  
  257.     }
  258.  
  259.    
  260.  
  261.     static {
  262.  
  263.         uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  264.  
  265.         uriMatcher.addURI(LineOfSightData.AUTHORITY, "avatar", CHARACTER);
  266.  
  267.         uriMatcher.addURI(LineOfSightData.AUTHORITY, "avatar/#", CHARACTER_ID);
  268.  
  269.  
  270.  
  271.         userProjectionMap = new HashMap<String, String>();
  272.  
  273.         userProjectionMap.put(Player._ID, Player._ID);
  274.  
  275.         userProjectionMap.put(Player.NAME, Player.NAME);
  276.  
  277.         userProjectionMap.put(Player.GENDER, Player.GENDER);
  278.  
  279.         userProjectionMap.put(Player.RACE, Player.RACE);
  280.  
  281.         userProjectionMap.put(Player.LEVEL, Player.LEVEL);
  282.  
  283.         userProjectionMap.put(Player.EXPERIENCE, Player.EXPERIENCE);
  284.  
  285.         userProjectionMap.put(Player.CURRENT_HEALTH, Player.CURRENT_HEALTH);
  286.  
  287.         userProjectionMap.put(Player.CURRENT_WITCHERIES, Player.CURRENT_WITCHERIES);
  288.  
  289.         userProjectionMap.put(Player.STRENGTH, Player.STRENGTH);
  290.  
  291.         userProjectionMap.put(Player.AGILITY, Player.AGILITY);
  292.  
  293.         userProjectionMap.put(Player.LIFE, Player.LIFE);
  294.  
  295.         userProjectionMap.put(Player.WITCHCRAFT, Player.WITCHCRAFT);
  296.  
  297.         userProjectionMap.put(Player.ATTRIBUTE_POINTS, Player.ATTRIBUTE_POINTS);
  298.  
  299.     }
  300.  
  301.    
  302.  
  303.     /**
  304.  
  305.      * This class helps open, create, and upgrade the database file.
  306.  
  307.      *
  308.  
  309.      * @author Martin
  310.  
  311.      */
  312.  
  313.     private static class DatabaseHelper extends SQLiteOpenHelper {
  314.  
  315.  
  316.  
  317.         DatabaseHelper(Context context) {
  318.  
  319.             super(context, LineOfSightData.DATABASE_NAME, null, DATABASE_VERSION);
  320.  
  321.         }
  322.  
  323.  
  324.  
  325.         @Override
  326.  
  327.         public void onCreate(SQLiteDatabase db) {
  328.  
  329.             db.execSQL("CREATE TABLE " + DATABASE_TABLE + " ("
  330.  
  331.                     + Player._ID + " INTEGER PRIMARY KEY,"
  332.  
  333.                     + Player.NAME + " TEXT,"
  334.  
  335.                     + Player.GENDER + " TEXT,"
  336.  
  337.                     + Player.RACE + " TEXT,"
  338.  
  339.                     + Player.LEVEL + " INTEGER,"
  340.  
  341.                     + Player.EXPERIENCE + " INTEGER,"
  342.  
  343.                     + Player.CURRENT_HEALTH + " INTEGER,"
  344.  
  345.                     + Player.CURRENT_WITCHERIES + " INTEGER,"
  346.  
  347.                     + Player.STRENGTH + " INTEGER,"
  348.  
  349.                     + Player.AGILITY + " INTEGER,"
  350.  
  351.                     + Player.LIFE + " INTEGER,"
  352.  
  353.                     + Player.WITCHCRAFT + " INTEGER,"
  354.  
  355.                     + Player.ATTRIBUTE_POINTS + " INTEGER);");
  356.  
  357.         }
  358.  
  359.  
  360.  
  361.         @Override
  362.  
  363.         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  364.  
  365.             Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data");
  366.  
  367.             db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
  368.  
  369.             onCreate(db);
  370.  
  371.         }
  372.  
  373.     }
  374.  
  375. }
Parsed in 0.060 seconds, using GeSHi 1.0.8.4
WarrenFaith
Moderator
Moderator
 
Posts: 227
Joined: Fri Mar 13, 2009 10:59 am
Location: Berlin, Germany

Postby mangaluve » Thu Mar 26, 2009 1:42 pm

Thanks! But I was wondering more about the _ID, do I have to have a field in the (for instance) sql-database with the Exact name _ID? And do I have to have a field (which you inherit from BaseColumns) that has the name _ID? Or could I just name it whatever I want?
mangaluve
Experienced Developer
Experienced Developer
 
Posts: 82
Joined: Mon Mar 23, 2009 8:59 pm

Postby Alexandro » Fri Mar 27, 2009 8:42 am

mangaluve wrote:Thanks! But I was wondering more about the _ID, do I have to have a field in the (for instance) sql-database with the Exact name _ID? And do I have to have a field (which you inherit from BaseColumns) that has the name _ID? Or could I just name it whatever I want?


It's not required to have the "_id" field, but without it you won't be able to use CursorAdapter and probably some other things. Having an _id field is only a + to your db.
And no, you can't use some other field. For some things to work you need exactly "_id" field, it doesn't necessary have to be a primary key though.
Alexandro
Junior Developer
Junior Developer
 
Posts: 24
Joined: Thu Mar 05, 2009 5:42 pm

Top

Postby mangaluve » Fri Mar 27, 2009 10:18 am

Okey thanks.. which are those things? I mean it makes sense to have some kind of ID (of course) and it's nice to always name it _ID by convention, but I want to know where exactly that name is required. I guess my DataBase doesn't need to have a field named exactly ID (since everything goes through the content provider). But where is _ID needed? I understand that some objects assumes that the _ID-fields exists since it's convention, but do I really need it if I write everything by myself and don't use any "helpers" except for ContentProvider and Cursor?

For instance, suppose I implement a simple Phonebook with a textfile (here I cannot really talk about a field named _ID, lets say that every row has a number in front which is the ID). Now I extend ContentProvider and implements the query/insert and so on, and an own Cursor. Where do I need _ID here, do my ContentProvider Have to have that field in order for the android system to accept is as a "shared" ContentProvider or what?
mangaluve
Experienced Developer
Experienced Developer
 
Posts: 82
Joined: Mon Mar 23, 2009 8:59 pm

Postby Alexandro » Fri Mar 27, 2009 11:01 am

mangaluve wrote:Okey thanks.. which are those things? I mean it makes sense to have some kind of ID (of course) and it's nice to always name it _ID by convention, but I want to know where exactly that name is required. I guess my DataBase doesn't need to have a field named exactly ID (since everything goes through the content provider). But where is _ID needed? I understand that some objects assumes that the _ID-fields exists since it's convention, but do I really need it if I write everything by myself and don't use any "helpers" except for ContentProvider and Cursor?

For instance, suppose I implement a simple Phonebook with a textfile (here I cannot really talk about a field named _ID, lets say that every row has a number in front which is the ID). Now I extend ContentProvider and implements the query/insert and so on, and an own Cursor. Where do I need _ID here, do my ContentProvider Have to have that field in order for the android system to accept is as a "shared" ContentProvider or what?


SimpleCursorAdapter and CursorAdapter require your cursor (the one you supply to them) to provide data from database with "_id" field.
I had an issue where I was getting a really big database from internet (in binary .sql) and there was no "_db" field. Tried to work it around with SimpleAdapter, but got a lot of lags because of the size, so i had to create "_id" field in it. Not sure where else this field might be needed.
Alexandro
Junior Developer
Junior Developer
 
Posts: 24
Joined: Thu Mar 05, 2009 5:42 pm

Postby mangaluve » Fri Mar 27, 2009 11:54 am

Thanks!

But for now suppose I don't have a database, I just have a textfile with the info. And I don't want to use a CursorAdaptor or show something, say I just want to print the first retrieved element or something. Is an _ID needed then? I know a lot of the standard classes rely on that and _ID field is present, but is it really Required if I dont use these classes? Or is it possible to do a simple ContentProvider and some kind of Cursor where the "id-field" has another name?
mangaluve
Experienced Developer
Experienced Developer
 
Posts: 82
Joined: Mon Mar 23, 2009 8:59 pm

Postby WarrenFaith » Fri Mar 27, 2009 12:15 pm

I would say: try it!
I can't say more than: just use _ID... where is the problem to use a convention? It is nearly everywhere needed...
WarrenFaith
Moderator
Moderator
 
Posts: 227
Joined: Fri Mar 13, 2009 10:59 am
Location: Berlin, Germany

Postby mangaluve » Fri Mar 27, 2009 12:53 pm

Well it's because I just want to know if it's neccesary.. I know I should try but I haven't had the time..it just disturbed me that the document said that I should have a _ID field, then I want to know, what fails if I dont have it. Just the way I learn things. If I want to know why something isn't working, it's not an alternative that Im after :)
mangaluve
Experienced Developer
Experienced Developer
 
Posts: 82
Joined: Mon Mar 23, 2009 8:59 pm

Top

Return to View, Layout & Resource Problems

Who is online

Users browsing this forum: No registered users and 7 guests