Documentation : Simple sync - Android

This example shows a simple way to share data between multiple users and devices.

Application consists of only one entity, which has one field. Main screen of application contains table with entities. User can add new entity and synchronize with mobeelizer cloud. There are two users on purpose. During runtime one can change users to observe synchronization.

Design Your App

Create new application in App Designer called SimpleSync.

Secondly, create new model called SimpleSyncEntity with text field - title.

For now leave conflict resolving property on overwrite. By default, there is one group - users, device category - mobile and role - users-mobile define. Deploy application to test environment. On test environment create two users with passwords:

  • a - usera
  • b - userb

 Finally, download configured template for Android project. Select installed Andoird SDK in target SDK field.

Use the Mobeelizer SDK

Extract downloaded zip file then open eclipse and import project.

Add resource files

Before we start  implementing our example we will add some resource files into the project:

Prepare main screen

We will start with creating main screen controls, as you read before on main screen there is list of model entities, two buttons to synchronize and add new entity and enother one to switch between users.

main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:layout_marginTop="20dip"
            android:layout_marginLeft="50dip"
            android:textSize="25dip"
            android:id="@+id/currentUser"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:bufferType="spannable"
            android:text="Simple sync" />
                 
        <ImageButton
            android:layout_height="50dip"
            android:layout_width="50dip"
            android:layout_marginLeft="260dip"
            android:layout_marginTop="10dip"
            android:id="@+id/userSwitch"
            android:layout_alignParentLeft="true"/>
    </RelativeLayout>
        <View
        android:id="@+id/titleBarSeparator"
        android:layout_width="fill_parent"
        android:layout_height="2dip"
        android:layout_alignParentLeft="true"
        android:background="#FFB4B4B4" />
    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" >
    </ListView>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dip">
        <Button
            android:enabled="false"
            android:layout_height="wrap_content"
            android:layout_width="100dip"
            android:layout_marginLeft="10dip"
            android:layout_marginTop="10dip"
            android:id="@+id/footerAdd"
            android:layout_alignParentLeft="true"
            android:text="Add" />
        <Button
            android:enabled="false"
            android:layout_height="wrap_content"
            android:layout_width="100dip"
            android:layout_marginLeft="10dip"
            android:layout_marginTop="10dip"
            android:id="@+id/footerSync"
            android:layout_toRightOf="@+id/footerAdd"
            android:text="Sync" />
    </RelativeLayout>
</LinearLayout>

To keep clean in our code we will create an interface to define operations supported by our main screen. First of all there has to be possibility to refresh entities list, than to disable and enable all buttons, and to get or set currenty logged in user.

MainScreen.java
public interface MainScreen {
	
	    void disableButtons();
	     
	    void enableButtons();
	     
	    void refreshList();
	     
	    String getCurrentUser();
	     
	    void setCurrentUser(String user);
}

When interface is ready let's implement it on SimpleSyncActivity. In constructor we will get all created controls in layout definition and store it in class private fields. 

SimpleSyncActivity.java
 public class SimpleSyncActivity extends Activity implements MainScreen{
	
   private ListView mList;
    
   private TextView mCurrentUser;
    
   private Button mAddButton, mSyncButton;

   private ImageButton mSwitchUserButton;
    
   private String currenUser;
	
    /** Called when the activity is first created. */
    @Override


    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        mAddButton = (Button) findViewById(R.id.footerAdd);
        mSyncButton = (Button) findViewById(R.id.footerSync);
        mSwitchUserButton = (ImageButton) findViewById(R.id.userSwitch);
        mCurrentUser = (TextView) findViewById(R.id.currentUser);
        mList = (ListView) findViewById(android.R.id.list);
        
        // TODO: Add listeners to buttons
    }


	public void disableButtons() {
		mAddButton.setEnabled(false);
        mSyncButton.setEnabled(false);
        mSwitchUserButton.setEnabled(false);
	}


	public void enableButtons() {
		mAddButton.setEnabled(true);
        mSyncButton.setEnabled(true);
        mSwitchUserButton.setEnabled(true);
	}


	public void refreshList() {
        // TODO:
	}


	public String getCurrentUser() {
        return currenUser;
	}

	public void setCurrentUser(String user) {
        currenUser = user;
        if(user != null){
        	if(currenUser.equals("a")){
        		mSwitchUserButton.setImageResource(R.drawable.bt_user_a_big);
        	}
        	else if(currenUser.equals("b")){
        		mSwitchUserButton.setImageResource(R.drawable.bt_user_b_big);
        	}
        }
	}
}

Switch beetwen users

Before we implement refreshing entities list we have to create switching user things. We will create separated class for that called "SwichUserOperations", this class will implement OnClickListener interface, so an object of this class can be set as onClickListener in 'Switch' button. This class will also implement MobeelizerOperationCallback interface and we will use it as a login method callback. 

SwitchUserOperations.java
public class SwitchUserOperations implements OnClickListener , MobeelizerOperationCallback{
    
   private static final String USER_A_LOGIN = "a";
    
   private static final String USER_B_LOGIN = "b";
    
   private static final String USER_A_PASS = "usera";
    
   private static final String USER_B_PASS = "userb";
   private String userToLoggIn;
   private String password;
    
   private MainScreen page;
    
   public SwitchUserOperations(MainScreen page){
       this.page= page;
   }
    
   public void onClick(View v) {
       page.disableButtons();
       if(page.getCurrentUser() == USER_A_LOGIN){
           userToLoggIn = USER_B_LOGIN;
           password = USER_B_PASS;
       }
       else {
           userToLoggIn = USER_A_LOGIN;
           password = USER_A_PASS; 
       }
       Mobeelizer.login(userToLoggIn, password, this);
   }
   public void onFailure(MobeelizerOperationError arg0) {
       page.setCurrentUser(null);
       page.refreshList();
       page.enableButtons();
   }
   public void onSuccess() {
       page.setCurrentUser(userToLoggIn);
       page.refreshList();
       page.enableButtons();
   }
}

It is easy, right? When user click on switch button, we will check which user was logged in recently and then we will login other one. We have to also disable all buttons before login. When the login finish with success we will set current user value into MainScreen and then enable all buttons. 

Last thing to do in switching users is setting object of just created class to button as a onclick listener.

SimpleSyncActivity.java
	@Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        SwitchUserOperations switchOperations = new SwitchUserOperations(this);
        mSwitchUserButton.setOnClickListener(switchOperations);
        switchOperations.onClick(null);
		...
    }

Get current user entities

Ok we can switch between users now and it is time to create refreshing entity list code. To show our entities on list we have to create addapter for that, and list item layout template.

Add  list_item.xml file to layout folder, add implement it like this:

list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:minHeight="50dp"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/listItemTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"/>
    <ImageView
        android:id="@+id/listItemUser"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="10dp"/>
</RelativeLayout>

When template is ready it is time to create adapter. Create new class ListAdapter which extends ArrayAdapter<FileSyncEntity> and override getView method. 

ListAdapter.java
public class ListAdapter extends ArrayAdapter<SimpleSyncEntity> {
	private int resourceId = 0;
	
    private LayoutInflater inflater;
    
    public ListAdapter(Context context, int resource,
            List<SimpleSyncEntity> objects) {
        super(context, 0, objects);
        this.resourceId = resource;
        this.inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }
    
    public static class ViewHolder {
        public ImageView author;
        public TextView title;
    }
    
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = convertView;
        ViewHolder holder;
        if (view == null) {
            view = inflater.inflate(resourceId, parent, false);
            holder = new ViewHolder();
            holder.author = (ImageView) view.findViewById(R.id.listItemUser);
            holder.title = (TextView) view.findViewById(R.id.listItemTitle);
            view.setTag(holder);
        } else {
            holder = (ViewHolder) view.getTag();
        }
        SimpleSyncEntity item = (SimpleSyncEntity) getItem(position);
        // Add owner name to author label
        if(item.getOwner().equals("a")){
            holder.author.setImageResource(R.drawable.bt_user_a_small);	
        }
        else if(item.getOwner().equals("b")){
        	holder.author.setImageResource(R.drawable.bt_user_b_small);
        }
        // Add created bitmap to ImageView
        holder.title.setText(item.getTitle());
        return view;
    }
}

This code is pretty simple. In constructor we are getting resource of item template definition and list of items. In overridden method we have to convert our SimpleSyncEntity class object to View object. We are getting TextView and ImageView control for title and owner fields from template and then fill them content with specified values. On the end of this method we are returning View object. 

When adapter is ready it is time to come back to refreshList method in SimpleSyncActivity class.

SimpleSyncActivity.java
...
	public void refreshList() {
		List<SimpleSyncEntity> entities = Mobeelizer.getDatabase().list(SimpleSyncEntity.class);
        ListAdapter adapter = new ListAdapter(this, R.layout.list_item, entities);
        mList.setAdapter(adapter);
	}
...

We are getting list of all entities from database, creating new adapter and then setting created object into list control.

Add entity into database

It is time now to implement adding new entities to database. As in switch user code we will also creates seperated class for that which will implement OnClickListener. We will get movie titiles from predefined xml file. We have already added it into project resources at the beging of this example. Create new class AddOperations.

AddOperation.java
public class AddOperation implements OnClickListener {
	
	private MainScreen mView;
	
	String[] mTitles;
	
    private static Random mRand;
    
    static {
        mRand = new Random(System.nanoTime());
    }
    public AddOperation(MainScreen view, Resources res){
        this.mView = view;
        mTitles = res.getStringArray(R.array.movieTitles);
    }
    
	public void onClick(View arg0) {
		SimpleSyncEntity entity = new SimpleSyncEntity();
		int index = mRand.nextInt(mTitles.length);
		entity.setTitle(mTitles[index]);
		Mobeelizer.getDatabase().save(entity);
		this.mView.refreshList();
	}
}

In constructor, we are loading list of movie titles from resources and creating object to generate random numbers. When user click on button, we will create new object set it values and save into database, on the end we will refresh entities list displayed on main screen.

Remember to set object of this class as add button onclick listener. 

SimpleSyncActivity.java
    @Override
    public void onCreate(Bundle savedInstanceState) {
		...
        mAddButton.setOnClickListener(new AddOperation(this, this.getResources()));
    }

Synchronize with mobeelizer

Great! our example is almost ready, last thing to do is synchronization, but don't be afraid. It will be as easy as other operations. We will create new class for that again, and we will implements OnClickListener and MobeelizerOperationCallback interfaces in it.

SyncOperations.java
public class SyncOperations implements OnClickListener , MobeelizerOperationCallback {
     
    private MainScreen view;
    public SyncOperations(MainScreen view){
        this.view = view;
    }
    public void onFailure(MobeelizerOperationError arg0) {
        view.refreshList();
        view.enableButtons();
    }
    public void onSuccess() {
        view.refreshList();
        view.enableButtons();
    }
    public void onClick(View arg0) {
        view.disableButtons();
        if(Mobeelizer.isLoggedIn()){
            Mobeelizer.sync(this);
        }
    }
}

It is actually just calling Mobeelizer sync method. When synchronization finished without any errors given entities list is refreshed, and that is all.

And remember to add created operation classes as buttons onClick listeners.

SimpleSyncActivity.java
    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        mSyncButton.setOnClickListener(new SyncOperations(this));
    }

Congratulations our example is completed. You can test it now on as many devices as you can find.

Conclusion

To conclude, this is the simplest example of using synchronization with Mobeelizer. Our model consists of only one field. We can create sample records and synchronize with Mobeelizer cloud.

Attachments: