Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8437395
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 10, 20262026-06-10T07:25:00+00:00 2026-06-10T07:25:00+00:00

I’ve watched the Google I/O REST talk and read the slides: http://www.google.com/events/io/2010/sessions/developing-RESTful-android-apps.html I’m still

  • 0

I’ve watched the Google I/O REST talk and read the slides: http://www.google.com/events/io/2010/sessions/developing-RESTful-android-apps.html

I’m still a bit unclear on how to nicely handle, say, an update error thrown by the remote server. I have implemented my own ContentProvider and SyncAdapter. Consider this scenario:

Update a user’s Contact Details via REST call:

  1. Request an update using a ContentResolver.
  2. My ContentProvider immediately updates the app’s local Sqlite database and requests a Sync (as per recommendations in the Google I/O talk).
  3. My SyncAdapter.onPerformSync() is called and does a REST call to update the remote data.
  4. Remote server responds with “ERROR: Invalid Phone Number” (for instance).

My question is, what is the best way for the SyncAdapter to signal to my ContentProvider that this change needs to be backed out of the app’s local database, and to also signal to my Activity that the update request failed (and pass the error messages returned from the Server)?

My activity needs to display a progress spinner while waiting for the result, and know whether the request succeeded or failed.


For updating the local app database with content from the Server, the SyncAdapter pattern makes complete sense to me, and I have that working fine. But for updates from the app to the server, I can’t seem to find a nice way to handle the above scenario.


And another thing… 😉

Say I call ContentResolver.notifyChange(uri, null, true); from within my ContentProvider’s update() method. true along with android:supportsUploading="true" will cause my SyncAdapter’s onPerformSync() to be called. Great, but inside onPerformSync(), how do I tell what URI I should sync? I don’t want to simply refresh my entire DB every time I get a Sync request. But you can’t even pass a Bundle into the notifyChangeCall() to be passed on to onPerformSync().

All the examples I’ve seen of onPerformSync() have been so simple, and not using a custom ContentProvider, any real world examples out there? And the docs are a bit of a bird’s nest. Virgil Dobjanschi, Sir, you’ve left me up the creek without a paddle.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-10T07:25:01+00:00Added an answer on June 10, 2026 at 7:25 am

    Short answer, if you’re targeting ~API level 7, is “Don’t”. The situation may have improved in later APIs but as it was… I would strongly recommend avoiding SyncAdapter completely; it’s documented very poorly and the “automatic” account/authentication management comes at a high price as the API for it is also convoluted and under-documented. This part of the API has not been thought through beyond the most trivial use cases.

    So here’s the pattern I ended up going with. Inside my activities I had a handler with a simple addition from a custom Handler superclass (could check for a m_bStopped bool):

    private ResponseHandler mHandler = new ResponseHandler();
    
    class ResponseHandler extends StopableHandler {
    
        @Override
        public void handleMessage(Message msg) {
            if (isStopped()) {
                return;
            }
            if (msg.what == WebAPIClient.GET_PLANS_RESPONSE) {
                ...
            } 
            ...
        }
    }
    

    The activity would invoke the REST requests as shown below. Notice, the handler is passed through to the WebClient class (a helper class for building/making the HTTP requests etc.). The WebClient uses this handler when it receives the HTTP response to message back to the activity and let it know the data has been received and, in my case, stored in an SQLite database (which I would recommend). In most Activities, I would call mHandler.stopHandler(); in onPause() and mHandler.startHandler(); in onResume() to avoid the HTTP response being signalled back to an inactive Activity etc. This turned out to be quite a robust approach.

    final Bundle bundle = new Bundle();
    bundle.putBoolean(WebAPIRequestHelper.REQUEST_CREATESIMKITORDER, true);
    bundle.putString(WebAPIRequestHelper.REQUEST_PARAM_KIT_TYPE, sCVN);       
    final Runnable runnable = new Runnable() { public void run() {
        VendApplication.getWebClient().processRequest(null, bundle, null, null, null,
                        mHandler, NewAccountActivity.this);
        }};
    mRequestThread = Utils.performOnBackgroundThread(runnable);
    

    Handler.handleMessage() is invoked on the main thread. So you can stop your progress dialogs here and do other Activity stuff safely.

    I declared a ContentProvider:

    <provider android:name="au.com.myproj.android.app.webapi.WebAPIProvider"
              android:authorities="au.com.myproj.android.app.provider.webapiprovider"
              android:syncable="true" />
    

    And implemented it to create and manage access to the SQLite db:

    public class WebAPIProvider extends ContentProvider
    

    So you can then get cursors over the database in your Activities like this:

    mCursor = this.getContentResolver().query (
              WebAPIProvider.PRODUCTS_URI, null, 
              Utils.getProductsWhereClause(this), null, 
              Utils.getProductsOrderClause(this));
    startManagingCursor(mCursor);
    

    I found the org.apache.commons.lang3.text.StrSubstitutor class to be immensely helpful in constructing the clumsy XML requests required by the REST API I had to integrate with e.g. in WebAPIRequestHelper I had helper methods like:

    public static String makeAuthenticateQueryString(Bundle params)
    {
        Map<String, String> valuesMap = new HashMap<String, String>();
        checkRequiredParam("makeAuthenticateQueryString()", params, REQUEST_PARAM_ACCOUNTNUMBER);
        checkRequiredParam("makeAuthenticateQueryString()", params, REQUEST_PARAM_ACCOUNTPASSWORD);
    
        valuesMap.put(REQUEST_PARAM_APIUSERNAME, API_USERNAME);
        valuesMap.put(REQUEST_PARAM_ACCOUNTNUMBER, params.getString(REQUEST_PARAM_ACCOUNTNUMBER));
        valuesMap.put(REQUEST_PARAM_ACCOUNTPASSWORD, params.getString(REQUEST_PARAM_ACCOUNTPASSWORD));
    
        String xmlTemplate = VendApplication.getContext().getString(R.string.XMLREQUEST_AUTHENTICATE_ACCOUNT);
        StrSubstitutor sub = new StrSubstitutor(valuesMap);
        return sub.replace(xmlTemplate);
    }
    

    Which I would append to the appropriate endpoint URL.

    Here’s some more details on how the WebClient class does the HTTP requests. This is the processRequest() method called earlier in the Runnable. Notice the handler parameter which is used to message the results back to the ResponseHandler I described above. The syncResult is in out parameter used by the SyncAdapter to do exponential backoff etc. I use it in the executeRequest(), incrementing it’s various error counts etc. Again, very poorly documented and a PITA to get working. parseXML() leverages the superb Simple XML lib.

    public synchronized void processRequest(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult, Handler handler, Context context)
    {
        // Helper to construct the query string from the query params passed in the extras Bundle.
        HttpUriRequest request = createHTTPRequest(extras);
        // Helper to perform the HTTP request using org.apache.http.impl.client.DefaultHttpClient.
        InputStream instream = executeRequest(request, syncResult);
    
        /*
         * Process the result.
         */
        if(extras.containsKey(WebAPIRequestHelper.REQUEST_GETBALANCE))
        {
            GetServiceBalanceResponse xmlDoc = parseXML(GetServiceBalanceResponse.class, instream, syncResult);
            Assert.assertNotNull(handler);
            Message m = handler.obtainMessage(WebAPIClient.GET_BALANCE_RESPONSE, xmlDoc);
            m.sendToTarget();
        }
        else if(extras.containsKey(WebAPIRequestHelper.REQUEST_GETACCOUNTINFO))
        {
          ...
        }
        ...
    
    }
    

    You should put some timeouts on the HTTP requests so the app doesn’t wait forever if the mobile data drops out, or it switches from Wifi to 3G. This will cause an exception to be thrown if the timeout occurs.

        // Set the timeout in milliseconds until a connection is established.
        int timeoutConnection = 30000;
        HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
        // Set the default socket timeout (SO_TIMEOUT) in milliseconds which is the timeout for waiting for data.
        int timeoutSocket = 30000;
        HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
        HttpClient client = new DefaultHttpClient(httpParameters);          
    

    So overall, the SyncAdapter and Accounts stuff was a total pain and cost me a lot of time for no gain. The ContentProvider was fairly useful, mainly for the cursor and transaction support. The SQLite database was really good. And the Handler class is awesome. I would use the AsyncTask class now instead of creating your own Threads like I did above to spawn the HTTP requests.

    I hope this rambling explanation helps someone a bit.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I would like my Web page http://www.gmarks.org/math_in_e-mail.txt on my Apache 2.2.14 server to display
I'm not entirely sure how I managed to jack this up. http://pretty-senshi.com If you
I have a .ini file as follows: [playlist] numberofentries=2 File1=http://87.230.82.17:80 Title1=(#1 - 365/1400) Example
I have a string like this: La Torre Eiffel paragonata all&#8217;Everest What PHP function
link Im having trouble converting the html entites into html characters, (&# 8217;) i
I'm parsing an RSS feed that has an &#8217; in it. SimpleXML turns this
I'm trying to decode HTML entries from here NYTimes.com and I cannot figure out
I'm making a simple page using Google Maps API 3. My first. One marker
I'm trying to convert HTML to plain text. I get many &\#8217; &\#8220; etc.
Let's say I'm outputting a post title and in our database, it's Hello Y&#8217;all

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.