Synchronize Android client and REST server

2019-01-26 13:03发布

问题:

REST Server

I created a Rails server that contains :users and associated :comments. It is used as a backend API for an Android client. The exchange format to load and store data at the server is JSON. Here are the relevant migrations.

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :name
      t.timestamps
    end
  end
end

...

class CreateComments < ActiveRecord::Migration
  def change
    create_table :comments do |t|
      t.references :users
      t.string :subject
      t.text :message
      t.timestamps
    end
  end
end

All users have already been imported. Therefore, only read access is configured for the :users resource. Thus, for :comments it should be possible to add new entries. Here are the available routes.

   user_comments GET   /users/:user_id/comments(.:format)      comments#index
                 POST  /users/:user_id/comments(.:format)      comments#create
new_user_comment GET   /users/:user_id/comments/new(.:format)  comments#new
    user_comment GET   /users/:user_id/comments/:id(.:format)  comments#show
           users GET   /users(.:format)                        users#index
            user GET   /users/:id(.:format)                    users#show

Android client

On the client side I use a Service with AsyncTasks to download, parse and store users into a local SQLite database. A ContentProvider delivers cached users to the UI. The user object downloaded from the server contains the unique id of the users table. This should be useful when a new comment gets created on the client.

Scenario 1: Read comments

  • Users are displayed in a list view on the Android client.
  • A user item gets selected.
  • The list activity creates an Intent which contains the user specific URI, e.g. content://com.example.myapp.provider/users/23.
  • A user activity displays detail information about the user and associated comments.
  • Cached comments get loaded via a CursorLoader. (1)
  • A synchronization process loads comments from the remote server. (2)

Scenario 2: Write comments

  • A comment can be created from the user activity.
  • The comment gets stored into the local database. (3)
  • Stored comments are sychronized with the remote server. (2)

Headache questions

I marked the scenario steps that are associated with the following questions.

  1. How do I create a content URI for the comments being used with a CursorLoader in the user activity? Please mind, I only know the user URI at this point.
  2. Can someone describe how I create a synchronization process? I am not sure if a SyncAdapter works here (never used it). Is the the synchronization process just a Service that on the one hand starts tasks to download, parse and store comments on the client and on the other hand loads, encodes and sends out comments to the server?
  3. How does the content URI for a new comment look like? Is the ContentProvider for comments the same as for users? Is there only one SQLiteOpenHelper in the application?

The main problem I am struggling with is how to design the application? If you know of a better solution on how I should synchronize the users and their associated comments, you are very welcome.

Answers

Answers to question 1. and 3.
I extended the REST model as follows: The JSON hash returned for a comment now includes the id of the associated user. The same id is also included in the JSON hash for the user. Both objects are stored into the local database on the Android device. This allows me request comments for a specific user. I simply pass the server user id as WHERE clause. The content URI for comments is not cascaded as I implied with my question. It is similar to the user content URI:

content://com.example.myapp.provider.commentsprovider/comments

Note, that I changed the authority part of the string. I decided to create separate content provider for users and comments.

回答1:

One simple architecture is to always update things in the server first, sending posted comments to the server right away and from there pushing a notification through GCM to users that should request the updated comments list. The flow would look like:

  • When the app is open send GCM registration id to your push notification server (say uniqush-push, or your own server using a gem to handle the GCM logic), this way you can use it to send push notifications to the user telling the app to update the comments from the server
  • Build your initial cache as you want it
  • Whenever a user posts a comment, send it to the server and make the server respond with the data for the created comment, so the app can use that and already cache it if it wants, using the returned id and whatever else
  • On the server, when a comment is posted, loop through all the concerned users and using the GCM registration id send it a push notification, it could be as simple as having just "update_comments": "1"
  • On the app when the push notification is tapped by the user, update the comments cache with a request to the server