Android - broken XML parsing example - android

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.

Related

Is it a good thing to write logic based on the hex value of id generated in R.java android

This what I have seen in an android application. They have a number of image buttons with ids
R.java :
public static final int img1=0x7f090080;
public static final int img2=0x7f090081;
public static final int img3=0x7f090082;
public static final int img4=0x7f090083;
public static final int img5=0x7f090084;
public static final int img6=0x7f090085;
public static final int img7=0x7f090086;
public static final int img8=0x7f090087;
In one of the activity they are traversing a for loop like below:
for (int i = 0; i < NoOfButtons; i++) {
if (i == pos) {
((ImageView) vi.findViewById(R.id.img1 + i)).setImageResource(R.drawable.circular_pagination_red);
} else {
((ImageView) vi.findViewById(R.id.img1 + i)).setImageResource(R.drawable.circular_pagination_brown);
}
I want to know how much safe and advisable it is.
One thing this is working absolutely fine. I been a part of this from months and never seen a problem in this logic. But still it irks me a bit.
Note : I am not getting any error and I know the alternate solution also. My only concern is if it is not advisable/safe I want to know why? Another is scenarios where it can create havoc for me. I have a good understanding about R.java.
Though this might work OK most of the times, this is definitely not advisable. The R class is generated automatically thus you have no control over it and it could change. There is a solution to this problem using a typed array in resources. Check for example this answer.
You might want to use reflection.
Add this method to your code:
protected final static int getResourceID
(final String resName, final String resType, final Context ctx)
{
final int ResourceID =
ctx.getResources().getIdentifier(resName, resType,
ctx.getApplicationInfo().packageName);
if (ResourceID == 0)
{
throw new IllegalArgumentException
(
"No resource string found with name " + resName
);
}
else
{
return ResourceID;
}
}
And use it like this:
int myID =
getResourceID("your_resource_name", "drawable", getApplicationContext());
Note: no path (and no extension, in case of images).

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

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

How to fix error with .add, arrayList, and String array values in android?

In my Const.java I have
public static final String[] MONTHS = new String[]{<list of string values>}
public static final String[] YEARS = new String[]{<list of string values>}
public static int MONTH_NUM = <some int>;
public static int YEAR_NUM = <some int>;
in my other file i have
ArrayList<String> skList = new ArrayList<String>();
String month = Const.MONTHS[Const.MONTH_NUM];
String year = Const.YEARS[Const.YEAR_NUM];
skList.add(month);
skList.add(year);
then I got this error: The method add(String) in the type ArrayList is not applicable for the arguments (String[])
on lines:
skList.add(month);
skList.add(year);
Hope you can help. I already used all possible keywords I can come up w/ in Google.
Thanks.
Note: After I restarted eclipse and rebuild, several times, it ran.
thanks guys for all your comments.

How to use SectionIndexer on dates

I have been searching on ways to use the SectionIndexer on dates in my listView. I would like to show the "short date" when fast scrolling my list. I saw a post from a couple years ago with a guy saying he had it working and he had a different issue, but sadly he didn't post any code for his method.
I figure I will have to do something to my custom ArrayAdapter but I am not really sure what, anyone have any ideas of where I can look for something like this?
Thanks,
-Eric
Ok so here is what I ended up doing to get it to work properly, just in case someone else in the future is looking for something similar.
private class TransactionAdapter extends ArrayAdapter<Transaction> implements SectionIndexer
{
private ArrayList<Transaction> items;
private Context context;
LinkedHashMap<String, Integer> dateIndexer;
String[] sections;
public TransactionAdapter(Context context, int textViewResourceId, ArrayList<Transaction> items)
{
super(context, textViewResourceId, items);
this.context = context;
this.items = items;
this.dateIndexer = new LinkedHashMap<String, Integer>();
int size = items.size();
String prDate = " ";
for (int x = 0; x < size; x++)
{
Transaction tr = items.get(x);
Calendar date = tr.getDate();
String month = date.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault());
String year = String.valueOf(date.get(Calendar.YEAR));
String shortDate = month + " " + year;
if( !shortDate.equals(prDate))
{
this.dateIndexer.put(shortDate, x);
prDate = shortDate;
}
}
Set<String> sectionDates = this.dateIndexer.keySet();
// create a list from the set to sort
ArrayList<String> sectionList = new ArrayList<String>(sectionDates);
this.sections = new String[sectionList.size()];
sectionList.toArray(this.sections);
}
public int getPositionForSection(int section)
{
return dateIndexer.get(this.sections[section]);
}
public int getSectionForPosition(int position)
{
return 0;
}
public Object[] getSections()
{
return this.sections;
}
}
I found the answer in a combination of two places:
This tutorial helped me with the initial implementation of the SectionIndexter: Android ListView with fastscroll and section index
This post fixed an issue I had with the HashMap changing my ordering of my array, it suggested using a LinkedHashMap instead. is the Java HashMap keySet() iteration order consistent
You can use this library. This is the Simpliest Section Adapter available for Android's ListView. It works with list adapters that you already have. No project specific dependencies. Just include the latest jar or the sources to your Android project.

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