Sonntag, 12. Oktober 2014

BARACUS from Scratch - Part 9 - Using interface and implementations & context bootstrap


Table of Contents

In this tutorial I am going to explain You how to use the BARACUS framework to work with alternative Implementations of an Interface plus hot-restarting the context to make use of them. Also, I will demonstrate the afterContextInitialized hook which enables You to perform post-container-startup operations.

Previous Tutorial : Lifecycle support with migr8

You can download the sources of this tutorial here

0 - Basics


Since Version 0.8, Baracus offers the capability to register an implementation to an interface. This can be very useful in combination with the bootstrap feature (reinitialize context), because it allows You to switch between several application varieties using different implementations of the interface. The registration is simply an alternative call on BaracusApplicationContext.registerBeanClass.

For this example, we will define a BankAccountLoadService, which we are going to wire twice to the BankAccountDao, logging each call on it.

1 - Defining the interface


Simply define the interface in the service package :


 
public interface BankAccountLoadService {

    List<BankAccount> loadAllAccountsByCustomerId(Long id);

}



2 - Implement the interface 


Next, we implement the interface :

 
public class BankAccountLoadServiceImpl1 implements BankAccountLoadService {



    @Bean
    BankAccountDao bankAccountDao;

    final Logger logger = new Logger(this.getClass());

    @Override
    public List<BankAccount> loadAllAccountsByCustomerId(Long id) {
        // In this demo, this is the primary implementation
        logger.info("Primary implementation called!");
        return bankAccountDao.getByCustomerId(id);

    }

}


3 - Implement the alternative (dummy here)


Then we implement an alternative; this could be a test class, a webservice or whatever. Interface implementations also can be used to improve testability.

 
/**
 * Created by marcus on 30.07.14.
 */
public class BankAccountLoadServiceImpl2 implements BankAccountLoadService {

    @Bean
    BankAccountDao bankAccountDao;

    final Logger logger = new Logger(this.getClass());

    @Override
    public List<BankAccount> loadAllAccountsByCustomerId(Long id) {
        // In this demo, this is the alternative implementation
        logger.info("Alternative implementation called!");
        return bankAccountDao.getByCustomerId(id);
    }
}


4 - Register interface


The interface now is used to register the implementation

 
public class ApplicationContext extends BaracusApplicationContext {

    static {
        ....

        registerBeanClass(BankAccountLoadService.class, BankAccountLoadServiceImpl1.class);

    }
}


This enables the Baracus DI container to inject the implementation wherever the interface is used.


5 - Use interface for injection


Then we will pimp the RowMapper to use the implementation :

public class CustomerDao extends BaseDao<Customer> {



    @Bean

    BankAccountLoadService bankAccountLoadService;

 

...



    private final RowMapper<Customer> rowMapper = new RowMapper<Customer>() {

        @Override

        public Customer from(Cursor c) {



  ....

  

         result.setAccounts(new LazyCollection<BankAccount>(new LazyCollection.LazyLoader<BankAccount>() {

                @Override

                public List<BankAccount> loadReference() {

                    return bankAccountLoadService.loadAllAccountsByCustomerId(id);

                }

            }));



That's all. Now we are able to use the Interface for DI. But that's not all, right? We want to make use of the ability to switch the implementation. Therefore, we will implement a ApplicationContextInitializer setting the Implementation "by random" - just for demonstration purpose. Since the decision, which implementation shall be used only happens on the boot of the app, we use a small semaphore to avoid permanent reinit. Imagine a basic context, you define and then, by configuration data (e.g. thru built-in configurationDao) you decide wether to build a thin client or a fat client - that is the one of the purposes of this class.

public class AfterContextInitialized implements ApplicationContextInitializer {

    static boolean reinit = true;

    @Override
    public void afterContextIsBuilt() {
        if ((new Date().getTime() % 2 ) == 0) {
            ApplicationContext.registerBeanClass(BankAccountLoadService.class, BankAccountLoadServiceImpl1.class);
        } else {
            ApplicationContext.registerBeanClass(BankAccountLoadService.class, BankAccountLoadServiceImpl2.class);
        }
        if (reinit) {
            reinit = false;
            ApplicationContext.reinitializeContext();;
        }
    }
}


This initializer also is registered in the application config :

public class ApplicationContext extends BaracusApplicationContext {

        static { 
          ....
          setApplicationContextInitializer(new AfterContextInitialized());
        }
}


That's it, now You can check by restarting the app several time, which implementation is used by checking the logs when expanding the customer details:

07-30 14:56:51.531    5316-5316/org.baracustutorial I/TUTORIAL_APP﹕ -BankAccountLoadServiceImpl1 Primary implementation called!

other try :

07-30 15:00:55.639    8815-8815/org.baracustutorial I/TUTORIAL_APP﹕ BankAccountLoadServiceImpl2 Alternative implementation called!


Conclusion :


As You can see, the implementation of alternatives can be used - in combination with configuration information - as a very powerful utility to create varying types of implementations / behaviour within the same codebase. The classic can be a client to be run locally using the local dao as a data service or a thin client pipelining all requests thru json requests on a remote system.

Also, it can be very useful to make the software more testable.

Next Tutorial :Writing custom validators




Montag, 6. Oktober 2014

BARACUS from Scratch - Part 10 - Writing custom validators

Table of Contents

Previous Tutorial :Using interfaces & implementations

You can download the sourcecode for this demo here

In this tutorial I will explain you how create custom validation objects to be used within your application. This enables you to have your application shipped with customized validators to fit your personal needs. This tutorial is basing on the FormValidation-Tutorial I published earlier.

Step 1 - Define validator


We want to add a constraint for defining names to our software. A name must start with a capital one letter and continue with zero or more small caps letters. This can be achieved by matching this java regex pattern [A-Z]+[a-z]*. So at first, we will define the constraint message plus the class:

strings.xml:

    <string name="nameViolation">Bad string format. Must be lowercase with starting capital letter</string>


public class NameValidator extends AbstractValidator<String>{



    static final String pattern = "[A-Z]+[a-z]*"; // Will allow John but neither JOHN nor john



    @Override

    public boolean validate(ConstrainedView<String> view) {

        return view.getCurrentValue().matches(pattern);

    }



    @Override

    public int getMessageId() {

        return R.string.nameViolation;

    }

}



Step 2 - Register validator


You must register the validator by-name in order to be able to use it. The ValidationRegistry internally used in the BARACUS framework is a managed bean which registers the validators in a postConstruct method. But since this validator is a more or less invariant item, we will add it to the context after the context has been built. This is necessary since the ValidationFactory has not been setup in the Context-initialization phase.

In a prior tutorial we have created an after-context-init trigger (AfterContextInitialized). This is the correct place to add the validator to the registry because in the ApplicationContext's init phase the internal ValidationFactory (which is also a bean) still is null.

So we add the validator to the context :

public class AfterContextInitialized implements ApplicationContextInitializer {

    ...

    @Override

    public void afterContextIsBuilt() {

        if (reinit) {

            ...

            ApplicationContext.registerValidator(new NameValidator());



        }

    }

}



Step 3 - Wire the validator


We are almost done. You simply have to wire the validator by-name inside the desired layout xml file. In our case, we want to have this validator added to the existing validator in the customer_editor.xml :

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

              xmlns:app="http://schemas.android.com/apk/res-auto"

              android:orientation="vertical"

              android:layout_width="match_parent"

              android:layout_height="match_parent">

    ...

    <net.mantucon.baracus.ui.ConstrainedEditText android:id="@+id/txtCustomerFirstName"

                                                 android:layout_width="fill_parent"

                                                 android:layout_height="wrap_content"

                                                 app:validatedBy="stringNotEmpty,nameValidator"

            />

    ...

    <net.mantucon.baracus.ui.ConstrainedEditText android:id="@+id/txtCustomerLastName"

                                                 android:layout_width="fill_parent"

                                                 android:layout_height="wrap_content"

                                                 app:validatedBy="stringNotEmpty,nameValidator"

            />

    ...

</LinearLayout>


The validators are applied in the direction you add them to the list.

Conclusion


Writing custom validators is easy. They make the app design more easy and efficient and allow you to have very specific rules beeing applied to user's form data. But that's not all. You even can have more sophisticated constraints; since you can access any bean through your ApplicationContest statically you even can have database driven checks.

Next Tutorial : Advanced Logging (coming up)

Donnerstag, 25. September 2014

BARACUS version 0.8.2 released

Today I am very glad to announce that BARACUS version 0.8.2 has been released.
This minor release includes the introduction of a runtime jar file, which allows you to use BARACUS in multi-module maven projects without having colliding resources (unfortunately Android plugin assembles the framework - if included as apklib - every time it bundles the apk. This will cause multiple problems in multimodule maven projects.

To avoid this problems nowadays, simple use the BARACUS runtime dependency. This enables you to create multi module maven projects using the framework.

To get the framework runtime dependency simply use the dependency

        <dependency>
            <groupId>org.baracus</groupId>
            <artifactId>baracus-framework</artifactId>
            <version>0.8.2</version>
            <type>jar</type>
            <scope>provided</scope>
        </dependency>

All future releases of the framework will contain the runtime dependency lib.

To use the current apklib (in your Android application module), simply use the dependency


        <dependency>
            <groupId>org.baracus</groupId>
            <artifactId>baracus-framework</artifactId>
            <version>0.8.2</version>
            <type>apklib</type>
        </dependency>

... as usual.


Regards,
MNT

Sonntag, 7. September 2014

BARACUS Maven archetype released


Today I am very happy to announce the release of a maven archetype to create Android applications using the BARACUS framework. It can be accessed via maven central and allows you to create application skeletons with the BARACUS framework fully integrated (no additional config needed).

Prerequisites



  • a suitable Java JDK (I still use 1.7.x atm)
  • Apache Maven Version 3 (I tend to use the latest maven distro)
  • Android SDK containing app level 14 minimum (I build my apps against level 18 atm, but that fits), since I am using linux my path is /usr/java/adt-bundle-linux-x86_64/sdk. 

Steps to perform



  • use mvn archetype:generate, ensuring that your internet connectivity is up. Then, you will get a list with 1000+ elements containing various application types. 
  • Enter the term "baracus" and press enter. You now should see one element containing the BARACUS archetype
  • Enter "1" and press enter. 
  • Then you will be prompted for coordinates of your app
  • Finally the maven based baracus application is created and you can open it with your favourite IDE


After creating the application

One parameter MUST be modified : You have to check the pom.xml, where a property android.sdk.path. It must point to your local android sdk. Since I am developing wih Linux, my path is /usr/java/adt-bundle-linux-x86_64/sdk. Simply modify the path your pom.xml to point to your Android SDK. If you want to develop with multiple environments, you can take advantage of maven's profiles feature. Take a look on the Baracus framework pom.xml for an example.

That's it, now you can build and deploy the application on your mobile device.

Features of the archetype app

* context creation (ApplicationContext)
* database initialization (OpenHelper)
* simple data structure plus mapping (Customer+CustomerDao)
* Data initialization (ApplicationInitializer Hook)
* Example form validation

Every release of the Baracus framework bring an update on the archetype in time.

Have fun!

Freitag, 25. Juli 2014

BARACUS Release 0.8.1



Hello, today I am glad to announce that BARACUS version 0.8.1 has been released. It carries several bugfixes and improvements and introduces a small amount of useful helper functions


 It can be included using the coordinates

<dependency>
<groupid>org.baracus</groupid>
<artifactid>baracus-framework</artifactid>
<version>0.8.1</version>
<type>apklib</type>
</dependency>

You also can download the sourcecode from github



VERSION 0.8.1 Changelog

- added DataUtil for simple Collection -> Map transformations
- added list based delete/save functions withing one transaction
- added Popup macro
- added generic BaseDao.arrify function to  to make collections become an array on demand
- added function to create lazy object reference (BaseDao.createLazyReference) by dao and id to application context  (was useful to me for dto-to-model copy constructor)
- added function to create lazy collection references (BaseDao.createLazyCollection) by dao, id and remote field
 (same like above)
- added support for optimistic locking, useful when multiple android clients are writing
  to one android master database.
- created optmistic locking capable entity (via version field)
- created BaseDao.initialFromCursor factory function to make coping with ID and version
  a little bit more flexible.
- added NullReference in ORM to avoid NPE handling on nullified References

- added a locator function BaracusApplicationContext.getBeansOfType to find all instances
  implementing a certain class.

These bugs were fixed :


- bugfixed query-function (double iteration)
- bugfixed ModelBase field list naming
- bugfixed replaceBean method
- bugfixed loss of timestamp info in BaseDao.save()


Mittwoch, 2. Juli 2014

BARACUS Release 0.8


Today I am glad to announce that BARACUS framework version 0.8 has been released.
 It can be included using the coordinates

<dependency>
<groupid>org.baracus</groupid>
<artifactid>baracus-framework</artifactid>
<version>0.8</version>
<type>apklib</type>
</dependency>

You also can download the sourcecode from github

A couple of features have been added:


VERSION 0.8

- added the getIdField function in order to make overriding the id column naming possible
- added the getLoadAllCursor in order to make linking to a data DataBoundAdapter possible
- to be better able to work with persistence interfaces the LazyMorphicCollection has been
  introduced in order to be able to return a List<Type> from a Dao<SpecialType>

- interface registration now possible in order to extend code reuseability
  additional to applicationContainer.registerBeanClass(aClass) you now can
  call registerBeanClass(InterfaceType, BeanClass);

  This is a powerful feature since it makes in-app testing much more easy.

- also : replace bean implementations in the running application and context hot reinit

- bugfix for NullPointerException in Android preview in IntelliJ

- added support for automatic selection of modified entities (BaseDao.getAllItemsModifiedAfter)
  .. simply extend your rowmapper to implement TimestampSupportingRowmapper and return
     the timestamp fields

- added an after-context-init hook to enable application post-construct
- added a function deleteById carrying a Long parameter to the DAOs
- added an constructor based "transient" determination to ModelBase
- added some utils for basic date calculation

- added queryByExample function in order to do QBE :)
- modified DataSetChangeAware interface, now passes the emitted class in order to be able to
  create aggregator-alike DataSetChangeAware components handling multiple entity types



--- DEPRECATION NOTICE ---
- don't inherit AbstractModelBase any more! The "id" column clashes
  with the android convention of carrying an "_id" column, so I added
  a boolean parameter to force You making a review on Your model classes.
  You can either inherit LegacyModelBase (same behaviour like before) or
  - and this is recommended - rebuild Your tables by renaming the "id" column
  to an "_id" column. This restrict impacts when You try to fill view withs
  data using a cursor. So either You must consider using the LegacyBean
  or You should modify Your code.

Regards,
mnt

Android daily pain : class R does not contain the correct constants

Yesterday I started preparing  the release of BARACUS 0.8. Therefore, I started to update all tutorials. By the new Android versions I surely updated my SDK in the meantime. In mind, just to do a version upgrade and use a new plugin version, I started migration.

So what I did was using a newer pom, update plugin and sdk version :

public class ApplicationContext extends BaracusApplicationContext {
 <properties>
        <android.sdk.path>C:/adt-bundle-windows-x86-20130219/sdk</android.sdk.path>
        <android.plugin.version>3.8.2</android.plugin.version>
        <android.sdk.version>18</android.sdk.version>
  <platform.version>4.0.1.2</platform.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <baracus.version>0.8</baracus.version>
 </properties>
... and ..,
public class ApplicationContext extends BaracusApplicationContext {
 <build>
  <finalName>${project.artifactId}</finalName>
  <pluginManagement>
   <plugins>
    <plugin>
     <groupId>com.jayway.maven.plugins.android.generation2</groupId>
     <artifactId>android-maven-plugin</artifactId>
     <version>${android.plugin.version}</version>
     <extensions>true</extensions>
    </plugin>
   </plugins>
  </pluginManagement>
  <plugins>
            <plugin>
                <groupId>com.jayway.maven.plugins.android.generation2</groupId>
                <artifactId>android-maven-plugin</artifactId>
                <version>${android.plugin.version}</version>
                <extensions>true</extensions>
                <configuration>
                    <sdk>
                        <platform>${android.sdk.version}</platform>
                    </sdk>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
            </plugin>


So, basically, I chose the setting mostly equals to the one in the framework. Also, I switched to use the new ModelBase class, since the AbstractModelBase becomes unavailable in this release.

Problem : The android project did not compile any more. But it did with the old plugin!?! WTF?!!

[ERROR] COMPILATION ERROR : 
[INFO] -------------------------------------------------------------
[ERROR] /home/marcus/tutorial-fix/baracus-tutorial/src/main/java/net/mantucon/baracus/HelloAndroidActivity.java:[57,25] cannot find symbol
  symbol:   variable layout
  location: class net.mantucon.baracus.R
[ERROR] /home/marcus/tutorial-fix/baracus-tutorial/src/main/java/net/mantucon/baracus/HelloAndroidActivity.java:[89,57] cannot find symbol
  symbol:   variable menu
  location: class net.mantucon.baracus.R
[INFO] 2 errors 
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.913 s
[INFO] Finished at: 2014-07-02T15:28:54+01:00
[INFO] Final Memory: 27M/336M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project baracus-tutorial: Compilation failure: Compilation failure:
[ERROR] /home/marcus/tutorial-fix/baracus-tutorial/src/main/java/net/mantucon/baracus/HelloAndroidActivity.java:[57,25] cannot find symbol
[ERROR] symbol:   variable layout
[ERROR] location: class net.mantucon.baracus.R
[ERROR] /home/marcus/tutorial-fix/baracus-tutorial/src/main/java/net/mantucon/baracus/HelloAndroidActivity.java:[89,57] cannot find symbol
[ERROR] symbol:   variable menu
[ERROR] location: class net.mantucon.baracus.R
[ERROR] -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

Process finished with exit code 1

After searching a little bit, I found out that the class R exists twice. I imported the BARACUS framework and it shares the package namespace with the tutorial.

Reason: The latest Android SDK and plugin do not allow the Mixup of R's within the same namespace any more.

Solution : I did a refactoring, moving all tutorial classes to the baracustutorial namespace. This fixed the issue. Now the error disappeard. Thanks to IDEA Intellij, this was less than 10mins per project. Annoying was the fact, that every R-access had to be removed by Hand.





Dienstag, 6. Mai 2014

BARACUS from Scratch - Part 8 - Lifecycle support for your app with migr8

Table of Contents

In this tutorial I am going to show You, how to manage the database through the lifecycle of Your application. Managing the persistence model and the underlying database structures is a quite important section in the lifecycle management of every application installed on a device not reacheable by the distributor. migr8 is the proper solution for reducing the pain of this management. It leverages the android and sqlite builtins to make database migration as easy as possible. 

Previous Tutorial : Database hot backup and hot recovery

You can download the sourcecode from here

0 - Basics 


Why is the management of database backends a problem on a mobile application? Because You do not have the guarantee that all clients running an upgrade are on the same version level. So there is a simple strategy necessary to avoid problems: It takes two information elements to make an update to an update and not to a problem : The current version of the database and the designated targert version. All steps transiting from the installed version to the target versions need to be known by Your application. This is a basic feature provided by Android/Sqlite. All You need to do is to find a proper path for this transtions.

And here migr8 enters the game.

When You are dealing with persistence in Your application, the first bean you must register in Your ApplicationContext, is the OpenHelper:

public class ApplicationContext extends BaracusApplicationContext {

    static {
        registerBeanClass(OpenHelper.class);

        registerBeanClass(BankAccountDao.class);
        registerBeanClass(CustomerDao.class);
 ...
The OpenHelper is the core component of all DB Handling. So let us take a look onto it.

1 - The OpenHelper 


In order to make use of Baracus persistence, Your application has to register a customized OpenHelper. When You take a look into the tutorial-application's OpenHelper You are going to find already three model changes registered inside of it :

public class OpenHelper extends BaracusOpenHelper {

    private static final String DATABASE_NAME="tutorial-app.db";
    private static final int TARGET_VERSION=101;

    static {
        addMigrationStep(new ModelVersion100());
        addMigrationStep(new ModelVersion101());
    }

    /**
     * Open Helper for the android database
     *
     * @param mContext              - the android context
     */
    public OpenHelper(Context mContext) {
        super(mContext, DATABASE_NAME, TARGET_VERSION);
    }
}

Now let us check the three relevant sections of the OpenHelper. The first information defined is the target version and the name of the database file. These are passed within the constructor to the super constructor in the bottom of the code.
Any Upgrade to the model (which inflicts new MigrationStep implementations) results in increasing the TARGET_VERSION. Otherwise the steps are not hit and the model remains untouched.

And in the middle, three migration steps are added. A migration step contains all relevant information to run a migration to a certain version.

2 - The migration step 


So let us take a look on the ModelVersion100 Element :

public class ModelVersion100 implements MigrationStep {


    private static final Logger logger = new Logger(ModelVersion100.class);
    @Override
    public void applyVersion(SQLiteDatabase db) {

        String stmt  = "CREATE TABLE " + BankAccount.TABLE_BANK_ACCOUNT
                + "( "+ BankAccount.idCol.fieldName+" INTEGER PRIMARY KEY"
                + ", "+ BankAccount.bankNameCol.fieldName+ " TEXT"
                + ", "+ BankAccount.ibanCol.fieldName+ " TEXT"+
                  ")";
        logger.info(stmt);
        db.execSQL(stmt);

    }

    @Override
    public int getModelVersionNumber() {
        return 100;
    }
 }
In this migration step the BankAccount table is defined using the column metadata of the persistence bean. All You have to do is to define a correct sql creating the table. You remember the OpenHelper? It got an instance of all Your MigrationSteps:

        addMigrationStep(new ModelVersion100());

3 - Add a new migration step 


In order to demostrate the ease of use of migr8, let's modify the BankAccount entity. At first, we add the field, the metadata and the gettersetters for a field named comment to the BankAccount entity:

public class BankAccount extends AbstractModelBase {

    public static final String TABLE_BANK_ACCOUNT = "bank_account";

    ...
    public static final Field commentCol= new Field("comment", columnIndex++);


    static {
        ...
        fieldList.add(commentCol);
    }

    ...

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }
}

Next, we need to extend the BankAccountDao's RowMapper in order to map the new field to the bean:

public class BankAccountDao extends BaseDao<BankAccount> {

    private final RowMapper<BankAccount> rowMapper = new RowMapper<BankAccount>()    {
        @Override
        public BankAccount from(Cursor c) {
            BankAccount result = new BankAccount();
            ...  
            result.setComment(c.getString(commentCol.fieldIndex));

            return result;        
        }

        @Override
        public ContentValues getContentValues(BankAccount account) {
            ContentValues result = new ContentValues();
            ...  
            if (account.getComment() != null) {
                result.put(BankAccount.commentCol.fieldName, account.getComment());
            }

            return result;
        }
    };
}

Finally, in order to make the stuff work, we must alter the database table in order to append these column to it. Therefore we will implement a MigrationStep:

public class ModelVersion102 implements MigrationStep {


    private static final Logger logger = new Logger(ModelVersion102.class);
    @Override
    public void applyVersion(SQLiteDatabase db) {

        String stmt  = "ALTER TABLE " + BankAccount.TABLE_BANK_ACCOUNT
                + " ADD COLUMN "+BankAccount.customerIdCol.fieldName + " INTEGER";
        logger.info(stmt);
        db.execSQL(stmt);

    }

    @Override
    public int getModelVersionNumber() {
        return 102;
    }
}

In order to finish Our masterpiece, we simply have to add it to the list of migrationsteps in the OpenHelper and increase the target version number:

public class OpenHelper extends BaracusOpenHelper {

    private static final String DATABASE_NAME="tutorial-app.db";
    private static final int TARGET_VERSION=102;

    static {
        addMigrationStep(new ModelVersion100());
        addMigrationStep(new ModelVersion101());
        addMigrationStep(new ModelVersion102());
    }
    ...

That's it.

The next time You launch Your app the migration step will run and do the update job on Your data model. 

Best practice hints : Never ever modify an existing migration step once after it has gone to production! You will probably cause disfunctional versions of Your app. Always add a new migration step to Your app.

Conclusion


As You can see there is not much magic behind the migration step concept. But doing model modification in a stream of upgrades enables You to upgrade any version of the model of Your app without having any pain.

Follow Up : Writing Custom Validators



Donnerstag, 3. April 2014

BARACUS from Scratch - Part 7 - Android SQLite HotBackup and HotRecovery

Table of Contents

In this tutorial I am going to show You, how to hot-backup the SQLite Database of Your Application. 
If You rely on Baracus' migr8, even old Databases can be restored automatically and updated to the latest level. This offers You a flexible mechanism to deal backup and upgrade issues.

Previous Tutorial : Automatic Form Validation

You can download the sourcecode from here

Note : I found a pitfall; to log the last start/end date I added an onDestroy() listener to the configuration service in order to update the regarding table. This runs into an error, if the database is shutdown for restoring, so I simply caught the exception. Baracus has no mechanism atm which allows You to ask for the lifecycle state of the container. This issue will be solved soon. Current development version is 0.8-SNAPSHOT, so expect this issue to be solved somehow in 0.8+.

Baracus relies on the effect, that Android keeps an open file handle to the database. This behaviour
could be verified on all Samsung Devices I own (S3 mini, S4, Google Nexus 10), so if anybody faces a
misbehaviour on a certain device, any email notification about this issue would be pretty welcome

Before all : Prerequisites 


In order to perform android database backups You must add the WRITE_EXTERNAL_STORAGE privilege to the android manifest

<manifest>
...
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>

Once You have added this privileges, Your app is allowed to write to the device's external storage (phone : internal phone storage).

Here we go!

Step 1 : Define a button in order to fire the backup procedure

Yes, a button. Simple and easy to implement, huh? We need it to start the backup ;-)

android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Perform Backup"
android:id="@+id/btnPerformBackup" android:layout_alignRight="@+id/buttonBackup" android:layout_alignParentTop="true"
android:layout_marginTop="39dp"
android:onClick="onButtonBackupClicked"/>

Now we have to wire that button

Step 2 : Call the built-in Backup function

Next step is to define the callback function in the HelloAndroidActivity :

public class HelloAndroidActivity extends Activity {
...
static String backupName;
...
public void onButtonBackupClicked(View view) {
        DBBackup.BackupResult result = DBBackup.performDatabaseBackup();
        if (result.isSuccessful()) {
            showPopup(this, "Successfully backed up "+result.getSize()+" to file "+result.getBackupDbName());
     backupName = result.getBackupDbName();
        } else {
            showPopup(this, "Backup failed :( Reason :"+result.getReason());
        }
    }

That's it. Database has been backup. I have no clue yet, if the backup file itself is portable to some other device type, but at the moment
 I doubt it, relying on the misportability of native structured storage between two platforms. If I get some other device type I'll give  a try. The name of the backup file is held in the static variable backupName. At the moment Baracus defines it own name built from timestamp, databasename and a .tac ending (truely assorted content).

A Backup is completely useless if You cannot perform any recovery with it, so here we go...

Step 3 : Implement ... another button

This button adds a new Customer to the table named Jane Doe. We need it, to show the impatient nonbelievers, that the current database truely has been modified.

<Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Modify Data"
        android:id="@+id/btnPerformDataModification" android:layout_alignRight="@+id/buttonModifiy" android:layout_alignParentTop="true"
        android:layout_marginTop="39dp"
        android:onClick="onButtonModifyClicked"/>

and here comes the callback :

public class HelloAndroidActivity extends Activity {
...
public void onButtonModifyClicked(View view) {
        Customer janeDoe = new Customer();
        janeDoe.setFirstName("Jane");
        janeDoe.setLastName("Doe");
        customerDao.save(janeDoe);
        showPopup(this, "Added Jane Doe");
    }

So when this callback is fired, a customer entity is created and written into the database. Basically this has got nothing to do with database backup, but it is better to see the the database modification within the customer subdialog.

Step 4 : Implement the recovery button

OK, now let's implement the recovery button. The impatient already checked if the data really has been modified by the button, right?

<Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Backup Database"
                android:id="@+id/btnRestorDatabase" android:layout_alignRight="@+id/buttonRestore" android:layout_alignParentTop="true"
                android:layout_marginTop="39dp"
                android:onClick="onBtnRestoreClicked"/>

Step 5 : Recovery

Recovery is a little bit more complicated because it requires the application context to shut down.
So if You did not break any rules like static dangling of objects and so on You should be able to shutdown, restore and relaunch the application without noticing it - if you are messing around with persistence calls in the destroy() lifecycle like me, You have to clean up Your backyard first. The restore util takes care of the shutdown, restore and relaunch process.

This looks like this :

 public void onBtnRestoreClicked(View view) {
        DBBackup.BackupResult result = DBBackup.restore(backupName);
        if (result.isSuccessful()) {
            showPopup(this, "Restore completed successfully.");
        } else {
            showPopup(this, "Restore failed due to reason :" + result.getReason());
        }
    }


Normally, You now can verify, that Jane Doe is not in Our database any more. Simply verify it by checking the table.

Conclusion

As You can see, Hotbackupping Your database is not complicated at all. At the moment I am quite confident that backups can be performed on each android device, but with the emerging device fragmentation problem this is not absulutely clear.

Upcoming tutorial : Managing the database with migr8

Montag, 10. Februar 2014

BARACUS from Scratch - Part 6 - Automatic Form Validation (Chapter Two of Two)

Table of Contents

In this tutorial, we are going to apply the newly learned knowledge and start creating a form including validation. This tutorial is based on the part one of the automatic form validation chapter. So You should check out that, first.


Previous Tutorial : Automatic Form Validation (Chapter one of two)

Download the sourcecode for this tutorial from github

Step 1 : We need a form!

To validate a form, we first need a form. Therefore, we are going to add a customer_editor.xml to the res/layout files. For the beginning, we only place a horizontal layout and the labels and the save button to the xml :


<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/customerFirstName"
            android:id="@+id/customerFirstNameLabel" android:layout_gravity="center"/>

    <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/customerLastName"
            android:id="@+id/customerNameLabel" android:layout_gravity="center"/>

    <Button
            android:id="@+id/btnSave"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/saveCustomer"
            android:onClick="btnSaveClicked"
            />

</LinearLayout>

Do not forget to add the labels to the strings.xml :

...
    <string name="customerFirstName">First Name</string>
    <string name="customerLastName">Last Name</string>
    <string name="saveCustomer">save customer</string>
...

So far, so good. Now let's add the Text Edit Fields.

Step 2 : Adding the fields

In order to validate fields, we learned, that we need to add vaildateable fields. These are brought in by the framework. Please notice, that the app:validatedBy denotes the named constraint which is applied to the field:

<net.mantucon.baracus.ui.ConstrainedEditText android:id="@+id/txtCustomerFirstName"
                                                 android:layout_width="fill_parent"
                                                 android:layout_height="wrap_content"
                                                 app:validatedBy="stringNotEmpty"
            />

and
<net.mantucon.baracus.ui.ConstrainedEditText android:id="@+id/txtCustomerLastName"
              android:layout_width="fill_parent"
              android:layout_height="wrap_content"
              app:validatedBy="stringNotEmpty"  />

The stringNotEmpty-Constraint is a framework built-in. Later, we are going to build Our own custom validator.

Step 3 : Form Class

After we have added the fields, we need to create the java class for this form. I chose an Activity for this, but You also can use a Fragment. In order to have luxury goods like automatic form validation, dependency injection and so on, BARACUS introduces the ManagedFragment and the ManagedActivity class. Notice, ManagedFragment also is needed, if Your application supports device rotation (internally, the device calls the constructor of the Fragment class and this causes all injected by BARACUS to be nullified; this problem is solved by the ManagedFragment).

There is the form class :

package net.mantucon.baracus;

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.TextView;
import net.mantucon.baracus.annotations.Bean;
import net.mantucon.baracus.application.ApplicationContext;
import net.mantucon.baracus.context.ManagedActivity;
import net.mantucon.baracus.dao.CustomerDao;
import net.mantucon.baracus.model.Customer;
import net.mantucon.baracus.validation.ValidationFactory;

/**
 * Created by marcus on 03.02.14.
 */
public class CustomerEditorActivity extends ManagedActivity {

    TextView lastName; // sic.
    TextView firstName;
    Customer customer;

    @Bean
    CustomerDao customerDao;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.customer_editor);
        enableFocusChangeBasedValidation();

        lastName = (TextView) findViewById(R.id.txtCustomerLastName);
        firstName = (TextView) findViewById(R.id.txtCustomerFirstName);


        // If we edit an existing customer, load the customer data
        Bundle extras = getIntent().getExtras();
        if (extras != null) {
            Long customerId = extras.getLong("customerId");
            customer = customerDao.getById(customerId);
            lastName.setText(customer.getLastName());
            firstName.setText(customer.getFirstName());
        } else {
            customer = new Customer();
        }

    }

    public void btnSaveClicked(View v) {
        if (validate()) { // re-validate, is it ok?
            customer.setFirstName(firstName.getText().toString());  // ok : take data, write it back into DB.
            customer.setLastName(lastName.getText().toString());
            customerDao.save(customer);
            dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK)); // go back to caller
            finish();
        } else {
            Toast.makeText(this, R.string.insufficientData, Toast.LENGTH_LONG).show();
        }
    }
}

Pretty easy, huh? So this is all we need. If You violate one of the declared constraint an automatic notification happens to the form - the constraint violating form components become highlighted and a toast is displayed.

Step 4 : Wiring the dialogs


OK, now let's wire this activity to the caller Activity. I want a Customer -> BankAccount expandable List, wiring the long touch on the customer as the open action for the customer editor activity.

To dangle the stuff, at first we modify the main XML. We add  the ExpandableListView to Our main :


...
<expandablelistview android:groupindicator="@null" android:id="@+id/expandableListView" android:layout_height="match_parent" android:layout_width="match_parent"/>
...

Next, we need the layout description for the group and the child item.
entry_list_group_item.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="55dip"
              android:orientation="vertical" >


    <TextView
            android:id="@+id/tvGroup"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>


</LinearLayout>

and entries_list_child_item
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="55dip"
              android:orientation="horizontal"  android:selectAllOnFocus="true" >

    <TextView
            android:id="@+id/entryName"
            android:layout_width="150dip"
            android:layout_height="wrap_content"
            android:textSize="14dip"/>

    <TextView
            android:id="@+id/entryAccount"
            android:layout_width="175dip"
            android:layout_height="wrap_content"
            android:textSize="14dip"/>


</LinearLayout>

To manage an ExpandableList View, we are going to need a suitable Adapter. This adapter is derived from BaseExpandableListAdapter :
package net.mantucon.baracus;

import android.app.Activity;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;
import net.mantucon.baracus.application.ApplicationContext;
import net.mantucon.baracus.model.BankAccount;
import net.mantucon.baracus.model.Customer;
import net.mantucon.baracus.signalling.DataChangeAwareComponent;

import java.util.ArrayList;
import java.util.List;

/**
 * List Adapter Class for displaying accounts
 */
public class AccountExpandListAdapter extends BaseExpandableListAdapter {

    private Activity context;       // we need this one to inflate the detail rows
    private List<Customer> groups;  // customer master rows

    public AccountExpandListAdapter(Activity context, List<Customer> groups) {
        this.context = context;
        this.groups = groups;
    }

    /**
     * @param groupPosition - the customer row index
     * @param childPosition - the account row index
     * @return child object from group x, child y
     */
    public Object getChild(int groupPosition, int childPosition) {
        List<BankAccount> entries = groups.get(groupPosition).getAccounts();
        ArrayList<BankAccount> chList = new ArrayList<BankAccount>(entries);
        return chList.get(childPosition);
    }

    /**
     * @param groupPosition
     * @param childPosition
     * @return child Id which is equal to our position
     */
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    /**
     * create the child view for a child on a certain position
     *
     * @param groupPosition - the customer row index
     * @param childPosition - the account row index
     * @param isLastChild
     * @param view - the view (the child view, can be null)
     * @param parent - the parent view (the customer)
     * @return the view
     */
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View view,
                             ViewGroup parent) {

        final BankAccount child = (BankAccount) getChild(groupPosition, childPosition);

        if (view == null) {
            LayoutInflater infalInflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
            view = infalInflater.inflate(R.layout.entries_list_child_item, null);
        }
        final TextView entryName = (TextView) view.findViewById(R.id.entryName);
        entryName.setText(child.getBankName().toString());


        final TextView entryValue = (TextView) view.findViewById(R.id.entryAccount);
        entryValue.setText(child.getIban());

        return view;
    }

    public int getChildrenCount(int groupPosition) {
        ArrayList<BankAccount> chList = new ArrayList<BankAccount>(groups.get(groupPosition).getAccounts());

        return chList.size();

    }

    public Object getGroup(int groupPosition) {
        return groups.get(groupPosition);
    }

    public int getGroupCount() {
        return groups.size();
    }

    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    /**
     * creat the customer view
     * @param groupPosition
     * @param isLastChild
     * @param view
     * @param parent
     * @return the customer view
     */
    public View getGroupView(int groupPosition, boolean isLastChild, View view,
                             ViewGroup parent) {
        Customer group = (Customer) getGroup(groupPosition);
        if (view == null) {
            LayoutInflater inf = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
            view = inf.inflate(R.layout.entries_list_group_item, null);
        }
        TextView tv = (TextView) view.findViewById(R.id.tvGroup);
        tv.setText(group.getLastName()+", "+group.getFirstName());
        return view;
    }

    public boolean hasStableIds() {
        return true;
    }

    public boolean isChildSelectable(int arg0, int arg1) {
        return true;
    }

}

Finally, we dangle the stuff into the HelloAndroidActivity. So the onCreate() method is extended like this :


...
     expandableListView = (ExpandableListView) findViewById(R.id.expandableListView);

     fillTable();
...

/**
     * fill the data trable
     */
    private void fillTable() {

        final List<Customer> customers = customerDao.loadAll();
        AccountExpandListAdapter adapter = new AccountExpandListAdapter(this, new ArrayList<Customer>(customers));

        expandableListView.setAdapter(adapter);

        expandableListView.setLongClickable(true);

        expandableListView.setClickable(true);
        // Handle the long click; hold the customer long to open the CustomerEditor Activity
        expandableListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                Intent intent = new Intent(HelloAndroidActivity.this, CustomerEditorActivity.class);
                ArrayList<Customer> chList = new ArrayList<Customer>(customers);
                Customer c = chList.get(position);

                intent.putExtra("customerId", c.getId()); // pass the customer ID as parameter to the activity
                HelloAndroidActivity.this.startActivity(intent);
                return false;
            }
        });
    }
...
Notice, there is currently no refresh done automatically. Therefore, we modify the onClick method by simply adding the fillTable() call :


    public void onButtonTestClicked(View v) {
        ...
        // refill the data table
        fillTable();
    }

Ok, to add customers, we will have to add a "new" button at last. Therefore we extend the main_layout.xml and insert a button (Do not forget to add a label in the strings.xml!)
<Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="New"
                android:id="@+id/btnNew" android:layout_alignRight="@+id/button" android:layout_alignParentTop="true"
                android:layout_marginTop="39dp"
                android:onClick="onButtonNewClicked"/>

To finish the dialog, simply add the onClick event handler to the activity :
public void onButtonNewClicked(View view) {
        Intent intent = new Intent(HelloAndroidActivity.this, CustomerEditorActivity.class);
        HelloAndroidActivity.this.startActivity(intent);
    }

Conclusion

Using the BARACUS framework built-in form validation technique, message routing and error handling becomes really easy. You have learned how to wire validators to UI components and how to perform pre-saving validation. Because we used the ManagedActivity's focusChangeBasedValidation, the components are validated every time we change the widget.

-

Mittwoch, 22. Januar 2014

BARACUS from Scratch - Part 6 - Automatic Form Validation (Chapter one of Two)

Table of Contents

Previous Tutorial : Advanced Persistence Mapping

In this tutorial I am going to explain You the benefits of automated form validation. This feature is essiential to me to have valid data in a form in order to edit or add database content in my applications. Basically, I adopted the concept of form validation from jsf. You can register named validators (a variety of validators already is defined) and declare them to be applied on Your component. Because all data is held in TextViews, there currently only exists a ConstrainedEditText component but it is easy to extend this system.


The Basics I - Validators and the ValidationFactory

Imagine You have a pool of validators registered in Your application. Each validator is capable to determine that a information passed to it is valid or not. Additionally, each validator has a unique name which makes it identifiable within the container. A validator is passed to the ValidationFactory using either a name or not; if You don't supply a name, the name will be the class simple name with a small capital first character (FooValidator -> fooValidator). Because You can pass fully instantiated class instances to the registry, You also use Beans (and all the luxuries of a managed bean) for validation tasks.

The ValidatorFactory has a second task. It is able to perform an explicit validation on a view. It does this by recursively iterating the form and looking for instances of the ConstrainedView interface. When it finds a constrained view implementation, it takes the validators named in the app:validatedBy field and tries to validate the information.

Anything implementing the ConstrainedView interface can be used to validate a form.

There are already a set of predefined validators ready-to-use :
  • DateFromNow
  • NumberMustBeGreaterThanZero
  • StringIsNumericDouble
  • StringIsNumericInteger
  • StringNotEmpty
There will be more validators in future soon. These validators perform basic (atomic) validations of a single attribute and are ready to use.

Every validator needs to know about the error message to route. This is a text information placed in the strings.xml. The built in validators have only english texts at the moment (any extension help welcome :)).

The Basics II - Declaring the use of a validator

Now this is easy. The org.baracus.ui.ConstrainedEditText commponent carries an attribute named app:validatedBy. This attribute carries a comma seperated list of all validator names to be applied. The order of the validators in the string is the order the validation is done. So in order to check the component not to have empty text, the xml declaration looks like this : 

<org.baracus.ui.ConstrainedEditText android:id="@+id/txtFirstName"
              android:layout_width="fill_parent"
              android:layout_height="wrap_content"
              app:validatedBy="stringNotEmpty"
            />

That's it. Because the validation is runtime-evaluated, You have to manually check that validation works at least once; the validation factory will produce an exception if an unidentifiable validator is used. The validators are seperated by using a comma.

The Basics III - choosing the validation strategy

There are three strategies for automated form validation: validating explicitly (routing the errors manually placing your validation code into the controller), implicitely using the ApplicationContext's or, third way,  focusChangedBasedValidation automatic validation using a ManagedFragment or a ManagedActivity.

The Application context offers a number of methods for validation (depending on the strategy You choose).

Explicit, controller based validation without validator beans

The first solution enters the game, if you want to validate e.g. on button click having complex validation logics in Your controller. This strategy does not need any controller bean; your controller does all the validation logics

Then You can define the explicit validation in Your controller:

public void btnSaveClicked(View v){

        // clear all error notifications, we are going to validate here
        ApplicationContext.resetErrors(underlyingView);

        // explicit form validation
        if (accountNumber.getText() == null || accountNumber.getText().toString().trim().length() ==0) {
            ApplicationContext.addErrorToView(underlyingView, R.id.txtAccountNumber, R.string.notNullAccountNumber, ErrorSeverity.ERROR);
            // ... here could be more validations
            // ... and here we route them to the form :
            ApplicationContext.applyErrorsOnView(underlyingView);
        } else {
            currentAccount.setAccountNumber(accountNumber.getText().toString());
            currentAccount.setAccountName(accoutName.getText().toString());
            accountDao.save(currentAccount); // This will fire the DataChanged Event on the MainActivity
            onBackPressed();
        }
    }

As You can see, every errors are routed explicitly to form fields. Finally, You can order the context to apply the errors to the fields.

Implicit, controller based validation

Instead of relying on controller logics, you can attach - like shown in basics I - named validators to the component and let the ApplicationContext do the controller logics.

public void btnSaveClicked(View v){

        // clear all error notifications, we are going to validate here
        ApplicationContext.resetErrors(underlyingView);

        /* implicit form validation
         * The validation wiring is done on the validatedBy-Property inside of
         * the xml-declaration of the components
         * The routing is determined by the use of special error views (case 1)
         * or a mappeable component (TextViews are processed by @see TextEditErrorHandlers) */
        ApplicationContext.validateView(underlyingView);

        if (!ApplicationContext.viewHasErrors(underlyingView)) {
            currentCustomer.setFirstName(firstName.getText().toString());
            currentCustomer.setLastName(lastName.getText().toString());
            customerDao.save(currentCustomer);
            onBackPressed();
        }

    }


So all the dirty work of routing error messages is done by calling validateView for the form view. Before doing this, all existing errors should be removed. The validation itself is done via the above mentioned validators. These itchy little helpers get applied to the form and are used to decide, whether an error message has to be routed to the component or not.

Fully automatic validation

You also can use fully automatic validation. Therefore, Your Activity must be inheriting the baracus' ManagedActivity - or if fragments are used - the ManagedFragment. Both components offer the enableFocusChangeBasedValidation function in order to manage a validation, when a ui component focus changes.

This will enable You to have automatic validation and error routing to all your constrained components whenever a focus changes (this also includes the removal of errors from corrected input fields).

Any further - more or less complex - validation must be implemented by hand.

The Basics IV - Message routing

If you simply attach the validator to Your input field, baracus will make use of the standard android error handling function. But there is another trick You might use for handling complex error output. Therefore You can define a custom error view, baracus will use instead of the standard error handling. A custom error handler is defined like this :

    <org.baracus.ui.ErrorView android:id="@+id/customerFirstMsg"
                                       app:displayMessageFor="@id/txtCustomerFirstName"
                                       app:highlightTarget="true"
                                       android:layout_width="wrap_content"
                                       android:layout_height="wrap_content"
                                       android:layout_marginLeft="10dp"
                                       android:editable="true"
                                       android:textColor="#FF0000"
                                       android:lines="1"
                                       android:text=""/>

with the displayMessageFor-information You tell baracus, that this specific fields is responsible for the error handling of @id/txtCustomerFirstName.

with the highlightTarget-informatrion You tell baracus to highlight the error source field when a message is displayed.

This technique is useful e.g. if You want to display an error image instead of textual information.

Conclusion

With the three mechanisms of error handling, field validation and error routing, You get a powerful tools to make form-based android development more comfortable - no more writing of in-controller boilerplate validation code. You can make benefit of the use of named validators and the possibility to reuse validation code.

Best practice : I found for myself making ManagedBeans out of all my fragments has proven to be a good choice to make development more comfortable. You get the luxury of dependency injection inside of Your fragments, and You can make use of all container functions baracus offers. Therefore, You MUST used ManagedFragments (It is an android malice to make internal re-instantiation of fragments on device rotation); otherwise all injected fields are nulled!

COMING SOON : In the next tutorial I am going to show You, how to implement these validation techniques in the demo app.