Documentation : Conflicts - Android

This example presents conflicts arise when two users modify the same data.

Application consists of only one model, which has two fields. In order to show conflicts, one of the field will be modified by both users and then synchronized. Records, which are conflicted, will be marked with red background color. Main screen of application contains list of model entities and two buttons. User can add new entity, edit it's value and synchronize with mobeelizer cloud. There are two users in the system and there's a possibility to switch them on application life time.

Design Your App

First thing we have to do is create new application in Mobeelizer App Designer, called 'Conflicts'.


This example is focused on conflicts so set conflict resolving to 'manual' mode.


Next we will configure model. We have to go to 'Models' section, create new one and call it 'ConflictsEntity'.


Last thing to finish this step is to create two fields. Fields properties are specified in table below. Note that you shoud use default model credentials (CRUD operations avaliable for everyone).

NameRequired propertyTypeDefault value propertyAdditional propertiesCredentials
titleyestext--default
scoreyesinteger1min: 1, max: 5default

Next section to configure is 'Groups & Roles', by default there is one group called 'users' and one device category 'mobile' and this two together create role 'users-mobile'. This default configuration is perfect for our example and you don't have to change it. 
When everything is done in Create mode, deploy our application to test environment, and create two users with passwords:

  • a - usera
  • b - userb

Last thing to do in App Designer is download configured template for android. 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:

  • bt_user_a_big.png - user a big icon, add it into drawable-hdpi resource directory.
  • bt_user_b_big.png - user b big icon, add it into drawable-hdpi resource directory.
  • bt_user_a_small.png - user a small icon, add it into drawable-hdpi resource directory.
  • bt_user_b_small.png - user b small icon, add it into drawable-hdpi resource directory.
  • ic_star_big.png -star icon used to movie rating visualisation, add it into drawable-hdpi resource directory.
  • movies.xml - contains movies list - add it into values direcotry.
  • colors.xml - colors used to entity state visualisation. Put it in values directory.

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="Conflicts" />
                  
        <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 we have to have possibility to refresh entities list, there shoud be also posibility 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 ConflictsActivity . In constructor we will get all created controls in layout definition and store it in class private fields. 

ConflictsActivity.java
public class ConflictsActivity extends Activity implements MainScreen{
    
	private ListView mList;
       
	private Button mAddButton, mSyncButton;
	   
	private ImageButton mSwitchUserButton;
	   
	private String currenUser;
	
    @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);
        mList = (ListView) findViewById(android.R.id.list);
        
		// TODO: add onClick listeners into 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 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 login will finish with success we will set current user value on 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.

ConflictsActivity.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" >
    <View
        android:id="@+id/listItemOverlay"
        android:layout_width="match_parent"
        android:layout_height="50dip"
        android:layout_marginBottom="0dip"
        android:layout_marginTop="0dip" />
    
    <TextView
        android:id="@+id/listItemTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dip"/>
    <TextView
        android:id="@+id/listItemScore"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="25dip"
        android:layout_marginLeft="20dip"/>
    <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 called ListAdapter which extends ArrayAdapter<FileSyncEntity> and override getView method. 

ListAdapter.java
public class ListAdapter extends ArrayAdapter<ConflictsEntity> {
	private int resourceId = 0;
	
    private LayoutInflater inflater;
    
    public ListAdapter(Context context, int resource,
            List<ConflictsEntity> 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();
        }
        ConflictsEntity item = (ConflictsEntity) 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 ConflictsEntity class object to View object. We are getting TextViews and ImageView controls for title, score and owner fields from template and then fill them content with specified values. We are also setting item background color according to entity state. 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 ConflictsActivity class.

ConflictsActivity.java
...
	public void refreshList() {
		 List<ConflictsEntity> entities = Mobeelizer.getDatabase().list(ConflictsEntity.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 already added it into project resources at the beging of this example. Create new class AddOperation.

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) {
		ConflictsEntity entity = new ConflictsEntity();
		int index = mRand.nextInt(mTitles.length);
		entity.setTitle(mTitles[index]);
		entity.setScore(mRand.nextInt(5)+1);
		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. 

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

Edit entities

Ok if we can add new entity it is time to edit it value. We will edit only score value of each entity. We will use seperated activity for that. Create new activity called ConflictsDetailsActivity. Open activity layout definition and replace it with: 

activity_conflicts_details.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
        <TextView
        android:id="@+id/titleText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Title" />
		<RadioGroup
            android:id="@+id/detailsRadioGroup"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <TableLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent" >
                <TableRow
                    android:id="@+id/detailsStar1"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center_vertical" >
                    <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:gravity="center_horizontal" >
                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:src="@drawable/ic_star_big" />
                    </LinearLayout>
                    <RadioButton
                        android:id="@+id/detailsRStar1"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:clickable="false" />
                </TableRow>
                <TableRow
                    android:id="@+id/detailsStar2"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center_vertical" >
                    <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:gravity="center_horizontal" >
                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:src="@drawable/ic_star_big" />
                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:src="@drawable/ic_star_big" />
                    </LinearLayout>
                    <RadioButton
                        android:id="@+id/detailsRStar2"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:clickable="false" />
                </TableRow>
                <TableRow
                    android:id="@+id/detailsStar3"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center_vertical" >
                    <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:gravity="center_horizontal" >
                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:src="@drawable/ic_star_big" />
                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:src="@drawable/ic_star_big" />
                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:src="@drawable/ic_star_big" />
                    </LinearLayout>
                    <RadioButton
                        android:id="@+id/detailsRStar3"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:clickable="false" />
                </TableRow>
                <TableRow
                    android:id="@+id/detailsStar4"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center_vertical" >
                    <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:gravity="center_horizontal" >
                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:src="@drawable/ic_star_big" />
                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:src="@drawable/ic_star_big" />
                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:src="@drawable/ic_star_big" />
                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:src="@drawable/ic_star_big" />
                    </LinearLayout>
                    <RadioButton
                        android:id="@+id/detailsRStar4"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:clickable="false" />
                </TableRow>
                <TableRow
                    android:id="@+id/detailsStar5"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center_vertical" >
                    <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:gravity="center_horizontal" >
                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:src="@drawable/ic_star_big" />
                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:src="@drawable/ic_star_big" />
                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:src="@drawable/ic_star_big" />
                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:src="@drawable/ic_star_big" />
                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:src="@drawable/ic_star_big" />
                    </LinearLayout>
                    <RadioButton
                        android:id="@+id/detailsRStar5"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:clickable="false" />
                </TableRow>
            </TableLayout>
        </RadioGroup>
</LinearLayout>

There is a radio buttons list with available score values. 

When definition is ready let's implement activity class. On create time we will get title and current score values from intent and then set them into radio button list.  When user click on any score value, onClick metod will be invoked and then we return new score value and close activity. 

ConflictsDetailsActivity.java
public class ConflictsDetailsActivity extends Activity implements OnClickListener {
    
	public static final String RATING = "rating";
	public static final String TITLE = "title";
	
	public static final String POSITION = "position";
    private TextView mTitle;
	
	private RadioGroup mRadioGroup;
    private TableRow[] mStarChooser;
    private int[] mRadioIds;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_conflicts_details);
        mTitle = (TextView) findViewById(R.id.titleText);
        mRadioGroup = (RadioGroup) findViewById(R.id.detailsRadioGroup);
        mStarChooser = new TableRow[] { (TableRow) findViewById(R.id.detailsStar1), (TableRow) findViewById(R.id.detailsStar2),
                (TableRow) findViewById(R.id.detailsStar3), (TableRow) findViewById(R.id.detailsStar4),
                (TableRow) findViewById(R.id.detailsStar5) };
        mRadioIds = new int[] { R.id.detailsRStar1, R.id.detailsRStar2, R.id.detailsRStar3, R.id.detailsRStar4,
                R.id.detailsRStar5 };
        
        for (TableRow tr : mStarChooser) {
            tr.setOnClickListener(this);
        }
        String title = getIntent().getStringExtra(TITLE);
        int rating = getIntent().getIntExtra(RATING, -1);
        if (rating == -1) {
            rating = 1;
        }
        mTitle.setText(title);
        mRadioGroup.check(mRadioIds[rating - 1]);
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_conflicts_details, menu);
        return true;
    }
	public void onClick(View v) {
		  int newRating = -1;
	        switch (v.getId()) {
	            case R.id.detailsStar1:
	                mRadioGroup.check(R.id.detailsRStar1);
	                newRating = 1;
	                break;
	            case R.id.detailsStar2:
	                mRadioGroup.check(R.id.detailsRStar2);
	                newRating = 2;
	                break;
	            case R.id.detailsStar3:
	                mRadioGroup.check(R.id.detailsRStar3);
	                newRating = 3;
	                break;
	            case R.id.detailsStar4:
	                mRadioGroup.check(R.id.detailsRStar4);
	                newRating = 4;
	                break;
	            case R.id.detailsStar5:
	                mRadioGroup.check(R.id.detailsRStar5);
	                newRating = 5;
	                break;
	        }
	        if (newRating != -1) {
	            Intent i = getIntent();
	            i.putExtra(RATING, newRating);
	            setResult(Activity.RESULT_OK, i);
	        } else {
	            setResult(Activity.RESULT_CANCELED);
	        }
	        finish();
	}
}

Our new activity is ready. Come back to ConflictsActivity and open just created one when user click on item on the list. To do it we need to implement OnItemClickListener interface on our activity class, and set this listener into list. 

ConflictsActivity.java
public class ConflictsActivity extends Activity implements MainScreen, OnItemClickListener {

    private static final int CHANGE_RATING = 0x400;
    ...

    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        mList.setOnItemClickListener(this);
        ...
    }


    ...
 
	public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
		ConflictsEntity entity = (ConflictsEntity)mList.getAdapter().getItem(position);
        Intent i = new Intent(ConflictsActivity.this, ConflictsDetailsActivity.class);
        i.putExtra(ConflictsDetailsActivity.POSITION, position);
        i.putExtra(ConflictsDetailsActivity.TITLE, entity.getTitle());
        i.putExtra(ConflictsDetailsActivity.RATING, entity.getScore());
        startActivityForResult(i, CHANGE_RATING);
	}
}

Last thing to do in this section is overwriting onActivityResult method, to handle result of selecting new score value.

ConflictsActivity.java
     ...
	 @Override
	 protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
		 if(requestCode == CHANGE_RATING && resultCode == RESULT_OK){
			    int position = data.getIntExtra(ConflictsDetailsActivity.POSITION, -1);
	            int rating = data.getIntExtra(ConflictsDetailsActivity.RATING, -1);
	            if (position != -1 && rating != -1) {
	                // edit entity object with the new rating and save it to database
	                ConflictsEntity ce = (ConflictsEntity)mList.getAdapter().getItem(position);
	                ce.setScore(rating);
	                Mobeelizer.getDatabase().save(ce);
	                ((ArrayAdapter<ConflictsEntity>) mList.getAdapter()).notifyDataSetChanged();
	            }
		 }
	 }
     ...

Synchronize with mobeelizer

Greate, our example is almost ready, last thing to do is synchronization, but not 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.

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

Conflicts example is ready, you can test it now on as many devices as you can find. The easiest scenario is:

  • Add entity, sync, switch user and syc again
  • Choose one movie title that all users have. Now change score and synchronize updated data.
  • Switch user but do not sync yet.
  • Modify the same movie with another user and then synchronize.

Try other scenarios to understand how mobeeliser conflicts works. You can change conflicts resolving properties to see differences between them. You can also browse your data in App Designer using Data Browser tool.

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.