Android, Content Provider delete method on a table doesn't work - android

I'm trying to download some data from a server : a list of products and associate icons. This two are in two differents services.
In the class RPCS.java {list of products}, I have :
public void importPCR() {
final List<PriceCollectRow> priceCollectRows = mWebServices.getPriceCollectRows(mApplicationProperties.getProperty("store_id"));
final ContentValues[] pcrAsContentValues = pcrToContentValues(priceCollectRows);
int k = mContext.getContentResolver().delete(PriceCollectRowContract.CONTENT_URI, null, null);
mContext.getContentResolver().bulkInsert(PriceCollectRowContract.CONTENT_URI, pcrAsContentValues);
}
This work fine (k = 35).
In the RIS.java {icons}:
public void download() {
List<Integer> artList = new ArrayList<>();
artList.add(101640);
final List<Image> images = mWebServices.getImages(artList);
final ContentValues[] imagesAsContentValues = imagesToContentValues(images);
int m = mContext.getContentResolver().delete(ImageContract.CONTENT_URI, null, null);
int l = mContext.getContentResolver().bulkInsert(ImageContract.CONTENT_URI, imagesAsContentValues);
}
m = 0 (doesn't work), and l = 1.
So, this two are very similary, but only one work.
Have you any idea why ?
EDIT :
Found : I didn't implement the delete method in my ImageProvider (noob)

Thanks to zozelfelfo, I have to implement the delete method in my ImageProvider

Related

load text from String array and set text to textview is very slow in big string array

hi
why load text from String array and set text to textview is very slow in big string array?
please help to me.
//get khotbe text from database and copy to khotbe activity
private void setkhotbetextarabicfarsi() {
this.sqliteDB = SQLiteDatabase.openOrCreateDatabase(this.getDatabasePath("aliname").getPath(), (SQLiteDatabase.CursorFactory) null);
Itemid = this.getIntent().getIntExtra("selectedFromListid", 1);
Cursor cursorLines = this.sqliteDB.rawQuery("SELECT * FROM khotbe where IDFehrest=" + this.Itemid , (String[]) null);
allrecs = cursorLines.getCount();
matn = new String[allrecs];
if (this.allrecs != 0) {
cursorLines.moveToFirst();
for (int i = 0; i < this.allrecs; ++i) {
String TextArabicOfKhotbe = cursorLines.getString(cursorLines.getColumnIndex("TextArabicOfKhotbe"));
int IDkhotbe = cursorLines.getInt(cursorLines.getColumnIndex("IDkhotbe"));
this.matn[i] = TextArabicOfKhotbe;
cursorLines.moveToNext();
}
}
and main code:
for(int var1 = 0; var1 < this.allrecs; ++var1) {
tvArabic = new JustifiedTextView(this);
tvArabic.setText(matn[var1]);
you are creating the textviews in loop that might making it slow.. try populating the array values using an adapter..
Also check the number of rows you are accessing from the DB. if they are huge in number, they would require more time to be fetched.
Use limit in that case.

Update on Content Provider does nothing

I'm trying to make an Android app to help people suffering from headaches. I have a sqlite database to store the crisis, and users can add a crisis by pushing a button. The same button is used to indicate the crisis is over. In other words, when you feel the headache coming, you push the button ; then, when it's over, you press it again and the application updates the corresponding entry whith the "end date".
But if my insert does well, my update does not update at all. Here is how it is supposed to work :
I first retrieve the latest entry in my database (which is the one with the greatest id), then I get the actual date, and put it in a ContentValue. Finally I update the entry.
Here is the button code :
public void onClickStartStop(View v){
Log.v("andromed", "Starting/Stopping crisis");
String d = new Date().toString();
ContentValues cv = new ContentValues();
String user_info = "";
String[] projection = {CriseContract.COLUMN_NAME_CRISE_ID, CriseContract.COLUMN_NAME_CRISE_DEBUT,CriseContract.COLUMN_NAME_CRISE_FIN};
Cursor criseCursor = getContentResolver().query(CriseContract.CONTENT_URI, projection,"SELECT MAX("+CriseContract.COLUMN_NAME_CRISE_ID+") FROM "+CriseContract.TABLE_NAME, null, null);
Log.v("andromed",""+criseCursor.getCount());
if(criseCursor.getCount()>=0){
while(criseCursor.moveToNext()){
String date_fin = criseCursor.getString(criseCursor.getColumnIndex(CriseContract.COLUMN_NAME_CRISE_FIN));
if(!(date_fin==(null))){
Log.v("andromed","Date exists "+date_fin);
user_info = "Crise enregistrée";
cv.put(CriseContract.COLUMN_NAME_CRISE_DEBUT, d);
Uri u = getContentResolver().insert(CriseContract.CONTENT_URI, cv);
}else{
String date_deb = criseCursor.getString(criseCursor.getColumnIndex(CriseContract.COLUMN_NAME_CRISE_DEBUT));
if(date_deb==null){
Log.v("andromed","No date in db");
user_info = "Crise enregistrée";
cv.put(CriseContract.COLUMN_NAME_CRISE_DEBUT, d);
Uri u = getContentResolver().insert(CriseContract.CONTENT_URI, cv);
}else{
Log.v("andromed", "Need to close the crisis");
cv.put(CriseContract.COLUMN_NAME_CRISE_FIN, d);
int tmp = getMaxId();
String where = CriseContract.COLUMN_NAME_CRISE_ID+"="+tmp;
String[] st = {""+tmp};
int nup = getContentResolver().update(CriseContract.CONTENT_URI,cv, where, null);
Log.v("andromed", nup+" rows updated");
user_info = "Crise terminée";
}
}
}
}else{
user_info = "Erreur lors de la lecture";
}
Toast t = Toast.makeText(getApplicationContext(),user_info, Toast.LENGTH_LONG);
t.show();
}
(Don't mind the Log and the toast stuff, just for me).
Here is my function to retrieve the maximum id :
private int getMaxId(){
String[] projection = {CriseContract.COLUMN_NAME_CRISE_ID};
String selection = "SELECT MAX("+CriseContract.COLUMN_NAME_CRISE_ID+") FROM "+CriseContract.TABLE_NAME;
Cursor c = getContentResolver().query(CriseContract.CONTENT_URI, projection, selection, null, null);
Log.v("andromed", ""+c.getCount());
int maxid=-1;
if(c!=null){
while(c.moveToNext()){
maxid = c.getInt(c.getColumnIndex(CriseContract.COLUMN_NAME_CRISE_ID));
}
}
Log.v("andromed", "Greatest id in table Crise : "+maxid);
return maxid;
}
And of course, my contract class :
public final static class CriseContract{
public static final String AUTHORITY = "com.piertris.andromed";
public static final String BASE_PATH = "database";
public static final Uri CONTENT_URI = Uri.parse("content://"+AUTHORITY+"/"+BASE_PATH);
public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE+"/"+BASE_PATH;
public static final String CONTENT_ITEM_TYPE= ContentResolver.CURSOR_ITEM_BASE_TYPE+"/andromed";
public static final String TABLE_NAME = "crises";
public static final String COLUMN_NAME_CRISE_ID = "criseid";
public static final String COLUMN_NAME_CRISE_DEBUT = "date_debut";
public static final String COLUMN_NAME_CRISE_FIN = "date_fin";
public static final String COLUMN_NAME_INTENSITE = "intensite";
public static final String COLUMN_NAME_SYMPTOM = "symptome";
public static final String COLUMN_NAME_MED = "prise_med";
public static final String COLUMN_NAME_MEDS = "type_med";
public static final String COLUMN_NAME_AURA = "aura";
public static final String COLUMN_NAME_COMMENT = "comments";
}
When I try to end the current crisis, my Logcat tells me that 0 rows were updated.
Thanks to SO, I already corrected other problems due to a wrong use of the function, but this time, the only link I found was this one : Android content provider not updating database and the OP just added a comment saying he updated his ContentProvider, but nothing more.
What am I doing wrong ? Did I "misnamed" my column names ? Do I misuse the update function ?
Thanks for your help.
EDIT
Thanks to Jozua, I realized that I didn't implement the update function in my ContentProvider file. Alright, I feel extremely dumb right now. I'll keep you informed on how does it work once the update() function is written.
Once again, thanks Jozua.
Alright, I kind of solved the problem, but in a really bad way.
Considering the fact that I retrieve the crisis just once in order to add almost everything that is needed but the beginning date and the id, I simply turned my update() request into a delete() followed by an update() in which I pass a ContentValue containing the values of the row I previously deleted.
I know it is really bad programming, but at least it works.
I won't accept my answer, in case someone find out what was wrong with my update() function and could possibly help someone else (and even me, so that I can improve my code).
That's it :)
Here is the portion of relevant code :
public void onClickStartStop(View v){
//go straight to relevant part
String date_deb = criseCursor.getString(criseCursor.getColumnIndex(CriseContract.COLUMN_NAME_CRISE_DEBUT));
Log.v("andromed", "Need to close the crisis");
cv.put(CriseContract.COLUMN_NAME_CRISE_ID, criseCursor.getInt(criseCursor.getColumnIndex(CriseContract.COLUMN_NAME_CRISE_ID)));
cv.put(CriseContract.COLUMN_NAME_CRISE_DEBUT, date_deb);
cv.put(CriseContract.COLUMN_NAME_CRISE_FIN, d);
int ndel = getContentResolver().delete(CriseContract.CONTENT_URI, CriseContract.COLUMN_NAME_CRISE_ID+"=?", new String[] {""+criseCursor.getInt(criseCursor.getColumnIndex(CriseContract.COLUMN_NAME_CRISE_ID))});
Log.v("andromed", ndel+" rows deleted");
Uri u = getContentResolver().insert(CriseContract.CONTENT_URI, cv);
user_info = "Crise terminée";
//End of relevant code
}
Thanks to those who might have searched anyway.

How to do a findViewById (R.id.>> StringVarHere << )?

Searched and working on this a long while - no luck. ( It must be simple ? Thanks for the assist. )
Trying to get / set a screen full of EditTexts' text, but not with the usual, more hard-coded way:
... findViewById (R.id.SomeTextWidgetId) ;
Instead, I'm trying to figure out a reusable way via a variable holding the (String) name_of_widget.
In psuedo code:
findViewById (R.id.>> StringVarHere << ); // how to do that ?
I tried also this findViewById method, but it didn't work (!?)
//// given:
static final String FIELD_TV_FEE = "TextViewFee" ;
static final String FIELD_TV_FOO = "TextViewFoo" ;
static final String FIELD_TV_FUM = "TextViewFum" ;
//// and some arbitrary number more of similar fields
static final String [] ALL_FIELDS = {
FIELD_TV_FEE ,
FIELD_TV_FOO ,
FIELD_TV_FUM // ...
} ;
//// ...
//// this part works
int ResourceID;
String stringVarHere = FIELD_TV_FEE;
//// outputs a correct id, say '0x7f05000f' as in R.id.xxx below
ResourceID = context
.getResources()
.getIdentifier ( stringVarHere,
"id",
context
.getApplicationInfo()
.packageName
) ;
Log.d ("MyClass" , "RESID = " + Integer.toHexString(ResourceID) ) ;
/*
* that's where I'm stuck ^^^ ... how do I do:
*/
String field_name ;
for ( field_name : ALL_FIELDS ) {
(EditText) SomethingLike_a_findViewById(field_name).setText ("Hello Wurld") ;
}
I've tried .setId ...
//// details
<!-- excerpt from working xml layout -->
<EditText
android:id="#+id/TextViewFee"
android:inputType="text"
android:layout ... etc ...
/>
<EditText
android:id="#+id/TextViewFoo"
android:inputType="text"
android:layout ... etc ...
/>
<EditText
android:id="#+id/TextViewFum"
android:inputType="text"
android:layout ... etc ...
/>
As expected, the gen'ed R file has something like this:
// ...
public static final class id {
public static final int TextViewFee=0x7f05000f;
public static final int TextViewFum=0x7f05001c;
public static final int TextViewFoo=0x7f05001d;
// ... etc
Yes, thanks - it makes sense to do it in the activity. I was trying to keep it from getting too code bulky. Here's what I'm doing now, based on your and A-C's helpful suggestions. The intention is to get all the text of fields of a form back in one String[]. (I know I could brute force all the fields too.)
What do you all think about this below - seems very similar to your suggestion, madlymad ? I am wondering if this is a poor design approach ?
public class FoodBar {
private Activity activity;
private Context ctx;
public FoodBar ( Activity _activity ) {
this.activity = _activity;
this.ctx = this.activity.getApplicationContext() ;
}
public String[] getTextFromAllEditTexts () { // the UI views
int res_id = 0;
int i = 0;
String [] retValues = new String [MyClassName.ALL_FIELDS_LENGTH] ;
for (String field : MyClassName.ALL_FIELDS_ALL_VEHICLES) {
res_id = this.ctx.getResources()
.getIdentifier ( field, "id", this.ctx.getPackageName() );
((EditText) this.activity
.findViewById (res_id))
.setText( "Meat and Potatoes" ) ;
// redundant - get it right back to make sure it really went in !
retVal[i++] = ((EditText) this.activity
.findViewById (res_id))
.getText().toString() ;
}
return retVal;
} // end func
} // end class
Then from the Activity class, it's just:
String [] theFields = null;
FoodBar = new FoodBar (this);
try {
theFields = FoodBar.getTextFromAllEditTexts ();
} catch (Exception e) {
Log.d ("OOPS", "There's a big mess in the Foodbar: " + e.toString() );
}
The way you could do it is (as I understand the way you are trying):
This can be in non-Activity (YourClassname.java):
public static int getMyId(Context context, String field) {
return context.getResources().getIdentifier (field, "id", context.getPackageName());
}
in Activity-class:
for ( String field_name : YourClassname.ALL_FIELDS ) {
int resid = YourClassname.getMyId(context, field_name);
if(resid != 0) { // 0 = not found
EditText et = (EditText) findViewById(resid);
if (et != null) {
et .setText ("Hello Wurld") ;
}
}
}
But I think it's better to code in the activity class like:
String packageName = getPackageName();
Resources res = getResources();
for ( String field_name : YourClassname.ALL_FIELDS ) {
int resid = res.getIdentifier (field_name, "id", packageName);
if(resid != 0) {// 0 = not found
EditText et = (EditText) findViewById(resid);
if (et != null) {
et .setText ("Hello Wurld") ;
}
}
}
A-C suggested something along the lines of:
res_id = getResources().getIdentifier (field, "id", getPackageName());
((EditText)findViewById (res_id)).setText("NoLongerFubar");
this DOES work - when I tried it standalone in a test rig. Thanks ! Still not sure what was blowing up, but I suspect it was Context or Resource items not being accessible.
Note that variable names (such as R.id.some_id) are only available at compile time and cannot be accessed from a String value at run time. Since these ids are declared as ints, you might consider using an int[] or List<Integer> to store the ids. Depending on how dynamic your layout is and what you are doing with the Views in it, you might even want to simply create the Views at run time and store an array or List of them without using any ids at all.

Android - broken XML parsing example

Android SDK since release of API v. 11 contains XmlAdapter sample which is also referenced from the official site. This sample appears now in at least 3 folders: android-11, android-12 and android-13. And it is broken. The main (but not only) problem it declares android.content.XmlDocumentProvider provider which is nowhere to be found including https://android.googlesource.com
There are also compilation problems in Adapters.java:
mContext cannot be resolved to a variable line 973
mFrom cannot be resolved to a variable line 938
mTo cannot be resolved to a variable line 937
mTo cannot be resolved to a variable line 939
There are few question related to this on android-developers but no answer. Did anyone managed to track this elusive XmlDocumentProvider and make the sample work?
And most importantly - dear Android team, can you ether fix the sample or pull it out?
The missing XmlDocumentProvider is now shipping with the sample in SDK 14 and the project compiles against SDK 8 and above. To run it successfully however, you must modify the manifest to point to the correct provider:
<provider android:name="com.example.android.xmladapters.XmlDocumentProvider"
android:authorities="xmldocument" />
Besides fixing the AndroidManifest.xml as pointed out by Jeff Gilfelt, you can also change the code XmlCursorAdapter class in Adapters.java (the file showing the errors) like this:
/**
* Implementation of a Cursor adapter defined in XML. This class is a thin wrapper
* of a SimpleCursorAdapter. The main difference is the ability to handle CursorBinders.
*/
private static class XmlCursorAdapter extends SimpleCursorAdapter implements ManagedAdapter {
private Context mContext;
private String mUri;
private final String mSelection;
private final String[] mSelectionArgs;
private final String mSortOrder;
private final int[] mTo;
private final String[] mFrom;
private final String[] mColumns;
private final CursorBinder[] mBinders;
private AsyncTask<Void,Void,Cursor> mLoadTask;
XmlCursorAdapter(Context context, int layout, String uri, String[] from, int[] to,
String selection, String[] selectionArgs, String sortOrder,
HashMap<String, CursorBinder> binders) {
super(context, layout, null, from, to);
mContext = context;
mUri = uri;
mFrom = from;
mTo = to;
mSelection = selection;
mSelectionArgs = selectionArgs;
mSortOrder = sortOrder;
mColumns = new String[from.length + 1];
// This is mandatory in CursorAdapter
mColumns[0] = "_id";
System.arraycopy(from, 0, mColumns, 1, from.length);
CursorBinder basic = new StringBinder(context, new IdentityTransformation(context));
final int count = from.length;
mBinders = new CursorBinder[count];
for (int i = 0; i < count; i++) {
CursorBinder binder = binders.get(from[i]);
if (binder == null) binder = basic;
mBinders[i] = binder;
}
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
final int count = mTo.length;
final int[] to = mTo;
final CursorBinder[] binders = mBinders;
for (int i = 0; i < count; i++) {
final View v = view.findViewById(to[i]);
if (v != null) {
binders[i].bind(v, cursor, cursor.getColumnIndex(mFrom[i]));
}
}
}
......
......
......
I got the answer from the code found here:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android-apps/4.0.1_r1/com/example/android/xmladapters/Adapters.java?av=f
I got answer from Romain Guy, well sort of. The ticket that I opened yesterday now has a tag Status: FutureRelease which I suppose means that they will fix it in the next release. For the added reference here's link to the discussion on android-developers
I met the same error and searched around, found the same question has been asked for many times. This is how I fixed it.
There is a XmlDocumentProvider class I found.
I copied the XmlDocumentProvider.java into the XmlAdapter project and revised the AndroidManifest.xml by replacing:
<provider android:name="android.content.XmlDocumentProvider"
android:authorities="xmldocument" />
with:
<provider android:name="com.example.android.xmladapters.XmlDocumentProvider"
android:authorities="xmldocument" />
Now I am able to get the RssReaderActivity working.

How to get the number of unread gmail mails (on android)

Please note there is a new way of doing this
I've been trying to get the number of unread gmail mails with no luck.
I've read Gmail.java and gmail4j both links taken out of this site from this question: Android - How can I find out how many unread email the user has?
But still after having read all of that and a couple of other sites that talked about this particular subject my question remains:
Q: How can I get the Gmail Unread Count?
Sorry if it seams a bit insistent but I clearly lack the knowledge to find this out on my own from the source.
PS: I would like to clarify that I want to do it without having to ask the user for credentials.
Just 2 add some colors to the question let me show you the looks of my app.
Please note there is a new way of doing this
Here's some code snippet. Not sure it works and can't test it. But I hope it will help you to continue the investigation.
public static final class LabelColumns {
public static final String CANONICAL_NAME = "canonicalName";
public static final String NAME = "name";
public static final String NUM_CONVERSATIONS = "numConversations";
public static final String NUM_UNREAD_CONVERSATIONS = "numUnreadConversations";
}
public void queryLabels(){
String account="email#company.com";
Uri LABELS_URI = Uri.parse("content://gmail-ls/labels/");
Uri ACCOUNT_URI = Uri.withAppendedPath(LABELS_URI, account);
ContentResolver contentResolver=myActivity.getContentResolver();
Cursor cursor = contentResolver.query(ACCOUNT_URI, null, null, null, null);
//iterate over all labels in the account
if (cursor.moveToFirst()) {
int unreadColumn = cursor.getColumnIndex(LabelColumns.NUM_UNREAD_CONVERSATIONS);
int nameColumn = cursor.getColumnIndex(LabelColumns.NAME);
do {
String name = cursor.getString(nameColumn);
String unread = cursor.getString(unreadColumn);//here's the value you need
} while (cursor.moveToNext());
}
}
Requires permission
<uses-permission android:name="com.google.android.gm.permission.READ_GMAIL"/>
This is how I've seen it done in a simple widget for the awesome window manager (yes, that's its name :)). Original script is here: gmail.lua.
The basic concept is to just use the inbox feed and get all the mails (you'll get just the summaries, not the whole content) for the special 'unread' tag. The URL is https://mail.google.com/mail/feed/atom/unread, you just have to fetch it (after authentication, of course), and then parse it. You can either use some sort of XML parser or just a simple regexp (<fullcount>([%d]+)</fullcount>) - the number you are looking for is at the beginning, in the <fullcount> tag.
So, that's one way of doing it, quite simple and "dumb", but hey, it works :D It might not be the best solution, as it requires you to fetch the whole feed (depending on the number of your unread messages and the type/quality of connection, it might not be as fast as just fetching the number of unread messages), but as usual, real-life testing should clear that up :)
There is new way how to do it. Old way doesn´t work anymore (21.01.2013).
Check following link:
Gmail Public Labels API
Maybe you can use the Gmail ContentProvider, please see http://www.google.com/codesearch/p?hl=en#uX1GffpyOZk/core/java/android/provider/Gmail.java&q=Gmail.java&sa=N&cd=1&ct=rc
There is a method getNumUnreadConversations or you could use a Observer.
static final String AUTHORITY = "com.google.android.gm";
static final String BASE_URI_STRING = "content://" + AUTHORITY;
static final String LABELS_PARAM = "/labels";
static final String ACCOUNT_TYPE_GOOGLE = "com.google";
public static final String NUM_UNREAD_CONVERSATIONS = "numUnreadConversations";
public static final String CANONICAL_NAME = "canonicalName";
public static final String CANONICAL_NAME_INBOX_CATEGORY_PRIMARY = "^sq_ig_i_personal";
static String[] GMAIL_PROJECTION = {
CANONICAL_NAME, NUM_UNREAD_CONVERSATIONS
};
public static Uri getLabelsUri(String account) {
return Uri.parse(BASE_URI_STRING + "/" + account + LABELS_PARAM);
}
static String[] getAllAccountNames(Context context) {
final Account[] accounts = AccountManager.get(context).getAccountsByType(
ACCOUNT_TYPE_GOOGLE);
final String[] accountNames = new String[accounts.length];
for (int i = 0; i < accounts.length; i++) {
accountNames[i] = accounts[i].name;
}
return accountNames;
}
protected static int getGmail(Context context) {
ContentResolver cr = context.getContentResolver();
Cursor cursor = cr.query(Launcher.getLabelsUri(BadgeUtils.getAllAccountNames(context)[0]),
GMAIL_PROJECTION,
null, null,
null);
if (cursor == null || cursor.isAfterLast()) {
Log.d(TAG, "No Gmail inbox information found for account.");
if (cursor != null) {
cursor.close();
}
return 0;
}
int count = 0;
while (cursor.moveToNext()) {
if (CANONICAL_NAME_INBOX_CATEGORY_PRIMARY.equals(cursor.getString(cursor.getColumnIndex(CANONICAL_NAME)))) {
count = cursor.getInt(cursor.getColumnIndex(NUM_UNREAD_CONVERSATIONS));;
break;
}
}
cursor.close();
return count;
}
Hope above code helps. This should work on Android 2.2+.

Categories

Resources