As I was working through the following tutorial, I came across this code :
public void onClickRetrieveStudents(View view) {
// Retrieve student records
String URL = "content://com.example.provider.College/students";
I am interested to see what kind of data this is, so I tried to go to the website http://com.example.provider.College/students to view the data, however it just gave some kind of error. Therefore my question is , is this URL some kind of xml document? what exactly is the format for this data... and how can I view it ?
I would recommend you familiarize yourself with the following documenation:
Content Providers:
http://developer.android.com/guide/topics/providers/content-providers.html
Essentially when you pass that "URL" to the ContentResolver (presumably you're doing somethign like this):
// Queries the user dictionary and returns results
mCursor = getContentResolver().query(
UserDictionary.Words.CONTENT_URI, // The content URI of the words table
mProjection, // The columns to return for each row
mSelectionClause // Selection criteria
mSelectionArgs, // Selection criteria
mSortOrder); // The sort order for the returned rows
You're asking android to resolve that URL to a ContentProvider which is set up to handle that URL. The URL is not "imaginary" so much as it's targets are Local objects and processes which exist and are defined by applications which use the ContentProvider mechanism to store and make data available to other applications.
The goal of that URL (which is converted to a URI in this case) is to specify which ContentProvider you want, and what you want from it.
ContentProviders are generally used by applications that want to manage a database and make that information available to other applications while minimizing access violations etc..
EDIT:
This code is from your tutorial. See added comments:
/// this url points to the content provider.
//The content provider uses it to
///reference a specific database which it has knowledge of
//This URI doesn't represent an
//actual FILE on your system, rather it represents a way for you to tell the content //provider what DATABASE to access and what you want from it.
String URL = "content://com.example.provider.College/students";
// This line converts yoru "URL" into a URI
Uri students = Uri.parse(URL);
/// This call returns a Cursor - a cursor is a object type which contains the results of your QUERY in an order manner. IN this case it is a set of rows, each of which has a number of columns coresponding to your query and database, which can be iterated over to pull information from the DB..
/// managedQuery takes, as an argument, the URI conversion of the URL - this is
// where you are actually calling to the contentprovider, asking it to do a query on the
// databse for some information
Cursor c = managedQuery(students, null, null, null, "name");
// This line moves to the first ROW in the cursor
if (c.moveToFirst()) {
// this does somethign as long as the while loop conditional is true.
do{
// This line creates a pop up toast message with the information stored in the columns of the row you the cursor is currently on.
Toast.makeText(this,
c.getString(c.getColumnIndex(StudentsProvider._ID)) +
", " + c.getString(c.getColumnIndex( StudentsProvider.NAME)) +
", " + c.getString(c.getColumnIndex( StudentsProvider.GRADE)),
Toast.LENGTH_SHORT).show();
} while (c.moveToNext());
}
Your question in the comments was:
"all I need is an example of this file: String URL = "content://com.example.provider.College/students"; , what would the data look like ? "
The answer to this is that you have an Sqlite Database on your phone somewhere - generally (and in this case definitely) created by the application and/or content provider you are accessing. You also know that the content resolver accepts this URI and some other information and will return you a CURSOR.
This question addresses what a cursor is.
use of cursor in android
If you read the tutorial fully you will find this code::
public class StudentsProvider extends ContentProvider {
static final String PROVIDER_NAME = "com.example.provider.College";
static final String URL = "content://" + PROVIDER_NAME + "/students";
static final Uri CONTENT_URI = Uri.parse(URL);
static final String _ID = "_id";
static final String NAME = "name";
static final String GRADE = "grade";
You will also find, in the manifest of your tutorial:
<provider android:name="StudentsProvider"
android:authorities="com.example.provider.College">
</provider>
Which is the registration of your ContentProvider for the URI at question.
You will note that your URL and the "PROVIDER_NAME" and "URL" have eerie similarities. This is because the ContentProvider is utilizing these values to identify itself as the resolver for this partiuclar URI to the android system.
You should create the files as described in the tutorial, make the sample app function, and you will be able to start understanding this more clearly.
It's not real, and it's not a web url. That is an example of a hypothetical ContentURI.
As an example, you might consult the UserDictionary like so -
// Queries the user dictionary and returns results
mCursor = getContentResolver().query(
UserDictionary.Words.CONTENT_URI, // The content URI of the words table
mProjection, // The columns to return for each row
mSelectionClause // Selection criteria
mSelectionArgs, // Selection criteria
mSortOrder); // The sort order for the returned rows
You might also create your own.
Related
I'm trying to read text files .txt with more than 10.000 lines per file, splitting them and inserting the data in Access database using Java and UCanAccess. The problem is that it becomes slower and slower every time (as the database gets bigger).
Now after reading 7 text files and inserting them into database, it would take the project more than 20 minutes to read another file.
I tried to do just the reading and it works fine, so the problem is the actual inserting into database.
N.B: This is my first time using UCanAccess with Java because I found that the JDBC-ODBC Bridge is no longer available. Any suggestions for an alternative solution would also be appreciated.
If your current task is simply to import a large amount of data from text files straight into the database, and it does not require any sophisticated SQL manipulations, then you might consider using the Jackcess API directly. For example, to import a CSV file you could do something like this:
String csvFileSpec = "C:/Users/Gord/Desktop/BookData.csv";
String dbFileSpec = "C:/Users/Public/JackcessTest.accdb";
String tableName = "Book";
try (Database db = new DatabaseBuilder()
.setFile(new File(dbFileSpec))
.setAutoSync(false)
.open()) {
new ImportUtil.Builder(db, tableName)
.setDelimiter(",")
.setUseExistingTable(true)
.setHeader(false)
.importFile(new File(csvFileSpec));
// this is a try-with-resources block,
// so db.close() happens automatically
}
Or, if you need to manually parse each line of input, insert a row, and retrieve the AutoNumber value for the new row, then the code would be more like this:
String dbFileSpec = "C:/Users/Public/JackcessTest.accdb";
String tableName = "Book";
try (Database db = new DatabaseBuilder()
.setFile(new File(dbFileSpec))
.setAutoSync(false)
.open()) {
// sample data (e.g., from parsing of an input line)
String title = "So, Anyway";
String author = "Cleese, John";
Table tbl = db.getTable(tableName);
Object[] rowData = tbl.addRow(Column.AUTO_NUMBER, title, author);
int newId = (int)rowData[0]; // retrieve generated AutoNumber
System.out.printf("row inserted with ID = %d%n", newId);
// this is a try-with-resources block,
// so db.close() happens automatically
}
To update an existing row based on its primary key, the code would be
Table tbl = db.getTable(tableName);
Row row = CursorBuilder.findRowByPrimaryKey(tbl, 3); // i.e., ID = 3
if (row != null) {
// Note: column names are case-sensitive
row.put("Title", "The New Title For This Book");
tbl.updateRow(row);
}
Note that for maximum speed I used .setAutoSync(false) when opening the Database, but bear in mind that disabling AutoSync does increase the chance of leaving the Access database file in a damaged (and possibly unusable) state if the application terminates abnormally while performing the updates.
Also, if you need to use slq/ucanaccess, you have to call setAutocommit(false) on the connection at the begin, and do a commit each 200/300 record. The performances will improve drammatically (about 99%).
I would like to limit the amount of contacts displayed in my app. Currently it is querying my Contactscontract.Contacts DB and returning every primary display name that has a phone number. Is there a simple way to reduce this to a numerical amount (say only display 5 contacts), or to certain specified ID's?
This is what I have so far:
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// load from the "Contacts table"
Uri contentUri = ContactsContract.Contacts.CONTENT_URI;
// no sub-selection, no sort order, simply every row
// projection says we want just the _id and the name column
return new CursorLoader(getActivity(),
contentUri,
PROJECTION,
ContactsContract.Contacts.HAS_PHONE_NUMBER + " =?", // This is selection string, were looking for records that HAS_PHONE_NUMER is 1
new String[]{"1"}, // 1 means that contact has a phone number
ContactsContract.Contacts._COUNT,
new String[] {"5"},
null);
}
Whenever I try to add new parameters in the return section, Android Studio immediately goes red saying cannot resolve constructor. Is this because the CursorLoader is not defined to receive more parameters?
I defined it earlier in my code as:
mAdapter = new SimpleCursorAdapter(context, layout, c, FROM, TO, flags);
Cheers,
Shyam
To achieve a limitation of query results, please add (string concatenate) a " LIMIT 5" to your query:
...
ContactsContract.Contacts.HAS_PHONE_NUMBER + "=? LIMIT 5" //This is selection string, were looking for records that HAS_PHONE_NUMER is 1 AND
// the result set is limited to 5 rows
new String[]{"1"},
null);
...
Referring to the question and answer on Best way to store a single user in an Android app?
How does shared preferences actually work?
What I'd like to do is:
First time user opens app adds a login id and password
Next time user opens app uses the previous id/password and data to login. (I don't want automatic login because data in my app will be sensitive and thus even a friend taking the mobile shouldn't be able to see it.)
Ability for the user to change this id/password
Is this possible through Shared Preferences? Or do I need to use SQLlite?
I am completely new to Android so I'd really appreciate it if you attach a working code and explanation.
You can do this with shared preferences, as long as you are comfortable storing reasonably confidential data there. You will need some shared codes between storing and retrieving:
final static String pfName = "com.super.stuff.preffile.name";
final static String pfCodeForID = "com.super.stuff.pf.id";
final static String pfCodeForPassword = "com.super.stuff.pf.passwd";
final static String pfNoStringPresent = "NO-STRING-PRESENT-HERE";
final static pfCodes = MODE_PRIVATE; // See http://developer.android.com/reference/android/content/Context.html#getSharedPreferences(java.lang.String, int)
To store the information:
String ID = //whatever;
String password = //whatever;
SharedPreferences settings = context.getSharedPreferences(pfName, pfCodes);
SharedPreferences.Editor editor = settings.edit();
editor.putString(pfCodeForID, ID);
editor.putString(pfCodeForPassword, password);
editor.commit();
To retrieve the information:
SharedPreferences settings = context.getSharedPreferences(pfName, pfCodes);
String ID = editor.getString(pfCodeForID, pfNoStringPresent);
String password = editor.getString(pfCodeForPassword, pfNoStringPresent);
if (ID.contentEquals(pfNoStringPresent) && password.contentEquals(pfNoStringPresent)) {
// Handle the case of nothing stored, ie get ID and password
}
Obviously this fails if both the username and the password are the same as pfNoStringPresent!
If you are concerned about storing sensitive data in this way, then you will need to store it either in a database, or encrypt it in some way. You will need to decide how critical it is for the information to be protected when it is being stored on a device belonging to the person who is giving you the ID information, how important getting this information from the phone would be to a thief, etc etc.
Use Sqlite, its fairly simple. Follow this:
public SQLiteDatabase sampleDB;
sampleDB = this.openOrCreateDatabase(TABLE_NAME, MODE_PRIVATE, null);
sampleDB.execSQL("CREATE TABLE IF NOT EXISTS " +
TABLE_NAME+ "(" + COLUMN_ID
+ " integer primary key autoincrement, " + COLUMN1
+ " text not null,"+ COLUMN2
+ " text not null);");
Here i have three fields where column1 and column2 are strings having values "username" and "password". After this creation you can execute query as what ever you need.
Integrate with AccountManager then use setUserData for it...the best way i think. :)
I'm new here and would be great if someone could help me with this small crisis I have been having. I have been following Jeff Sharkeys Separate List Adapter tutorial which can be found here and I got it all working appropriately to how he explains it.
My problem is I have a database, pre made one which has a table that I am trying to put the extracted data into a list view using Jeffs adapter. I need this data to be put in different sections according to the Category ID column.
The table I am currently extracting data from is the Food table, which has 6 columns, categoriID, menuID, Item, Description, price and a PK _id
My database works properly as in other activities I use a SimpleCursorAdapter to bind data to a list view. (from other tables)
I use the following method in the Database Helper class to retrieve the data I need
public List<FoodModel> getData(String catid, String menuid) {
List<FoodModel> FoodListModel = new ArrayList<FoodModel>();
Cursor cursor = myDataBase.query(FOOD_TABLE, new String [] {FOODITEM_COLUMN, FOODITEMDESCRIPTION_COLUMN,FOODPRICE_COLUMN}, "catid = ? AND menuid = ?",
new String[] { catid, menuid},null, null, null, null);
if (cursor.moveToFirst()){
do{
FoodModel FoodModel = new FoodModel();
FoodModel.setItem(cursor.getString(0));
FoodModel.setdescrription(cursor.getString(1));
FoodModel.setprice(Double.parseDouble(cursor.getString(2)));
FoodListModel.add(FoodModel);} while (cursor.moveToNext());
}
return FoodListModel;
}
the Food Model class is the standard get set class to store the cursors data.
This public method works accordingly as in my main activity (jeffs ListSample.java) I output to the log cat the required information using
Log.d("Reading: ", "Testing Cursor");
List<FoodModel> Data1 = dba.getData("1", "1");
for (FoodModel fd : Data1){
String log = "Item: "+fd.getitem()+" ,Description: " + fd.getdescription() + " ,Price: " + fd.getprice();
Log.d("Name: ", log);
This outputs a list of all the data I need to put into 1 section of the SeperateListAdapter but to the log cat
The 3 things i am trying to output to the list view are the Item, description and price.
My problem is How do I add this data to the list view under the correct section?
as oposed to manually inserting it as Jeff shows
List<Map<String,?>> security = new LinkedList<Map<String,?>>();
security.add(createItem("Remember passwords", "Save usernames and passwords for Web sites"));
security.add(createItem("Clear passwords", "Save usernames and passwords for Web sites"));
security.add(createItem("Show security warnings", "Show warning if there is a problem with a site's security"));
I didn't want to start my first experience of using this site by pasting all my classes is as this is my first time using this website, my English is not the best and it took me a while to write this I hope it is acceptable as a question, I would be really great full if someone could kindly help me or point me in the right direction.
EDIT: Will gladly post the rest of my code just didnt whant to bombard everyone with loads of information
When trying to update a record for one of my records I am using this code
private void UpdateCattleRecord(UpdateCattleRecord updateRecord){
mDB.beginTransaction();
String where = "_ID=";
String[] RecordToUpdate = {Cattle._ID};
Toast.makeText(this,"Updating Animal "+ RecordToUpdate, Toast.LENGTH_LONG).show();
try {
ContentValues CattleFieldsToUpdate = new ContentValues();
CattleFieldsToUpdate.put(Cattle.CATTLE_ANIMALID,updateRecord.getCattleName());
CattleFieldsToUpdate.put(Cattle.CATTLE_TYPE, updateRecord.getCattleType());
CattleFieldsToUpdate.put(Cattle.CATTLE_LOCATION, updateRecord.getCattleLocation());
CattleFieldsToUpdate.put(Cattle.CATTLE_DOB, updateRecord.getCattleDob());
CattleFieldsToUpdate.put(Cattle.CATTLE_DAM, updateRecord.getCattleDam());
CattleFieldsToUpdate.put(Cattle.CATTLE_SEX, updateRecord.getCattleSex());
mDB.update(Cattle.CATTLE_TABLE_NAME,CattleFieldsToUpdate, where, RecordToUpdate);
mDB.setTransactionSuccessful();
} finally {
mDB.endTransaction();
}
}
My log shows
Tag Database sqlite returned: error code =1, msg = near "=": syntax error
After researching this, I think I have everything in the right place but obviously I don't,
when I look at the next error in the log it's of course in 'red' and it shows me all the correct data,
03-27 15:15:29.291: E/Database(12011): Error updating date_of_birth=March 27, 2012 animaltype=Calf sex=F location=Eastern dam=601 animal_id=601A using UPDATE cattle SET date_of_birth=?, animaltype=?, sex=?, location=?, dam=?, animal_id=? WHERE _ID=
I've obviously got a problem with the value for _ID but can't seem to locate it. Can someone please point out where my Syntax error is?
Update
The problem occurred because I was failing to pass the actual value of the record (_ID) that I wanted to update. Once I passed that as a parameter to my updaterecords function the update went as scheduled.
Thanks for the input, it helped me narrow down what I was doing wrong.
Check your database creation, your probably have a column named _id(although you refer to it by _ID, its name is _id) and not _ID:
String where = "_id= ?"; // ? represent the value from the selection arguments String array
or better:
String where = Cattle._ID + "= ?";
Edit:
In your where selection argument you put:
String[] RecordToUpdate = {Cattle._ID};
you probably want to put in there some id you get from somewhere(of the record you want to update, a long number), right now you're doing:
WHERE _ID = _ID (or _id)
and this will fail.
try:
mDB.update(Cattle.CATTLE_TABLE_NAME,CattleFieldsToUpdate, "_ID="+Cattle._ID, null);
try:
mDB.update(Cattle.CATTLE_TABLE_NAME,CattleFieldsToUpdate, "_ID="+updateRecord.getId(), null);