Tuesday, October 8, 2013

Dynamically Fragment Replacement Android

Hi there! Today i'm gonna show how to insert(add) fragments dynamically. How to replace it thru other fragments with totally diferent layouts. This is a very common task while developing scalable, reusable and good looking apps.

I'm trying to do it in a very practical way from developer to developer. Less words and more code (complete code, and not only fragments...) to be sure you'll not run away and enjoy the sample. ;-)

There are some restrictions you must know, while handling with fragments.

First: You can only replace fragments which has been added dynamically. Burn this in your mind! ;-) I will be helpful! Believe me!
Second: You must define a "placeholder" layout, which will be your point to insert(add) and replace fragments with.

Ok lets put hands on. ;-)  The result at the end will be something like this:



Create a new Android Project with a blank template. 

Call it FragmentReplacement. Ensure that you have defined the "minsdkversion=11".

Controlling your AndroidManifest.xml 

Open it and be sure you have something similar to this:



    

    
        
            
                

                
            
        
    


Activity_main.xml (Layout) 

In the main activity layout, create a layout structure like this bellow:



    
    

    

Creating a Fragment 

In the folder "layout" create a new layout, name it "fragment_horizontal.xml" and copy/paste the code bellow in it. Save it. Done! Lets move ahead. ;-) (Don't worry about the details right now. Let's first create a simple structure before explaning everything.)



    

        


Create the next Fragment 

The main difference here is that the layout will change it here from horizontal to vertical. This because we wanna see the beautiful effect from having and using Fragments. Name it "fragment_vertical.xml" and again copy/paste the next code section in it.



    

        


Creating the class responsible for the First Fragment 

Create a new class and name it "FragmentHorizontal". While creating a new class, be sure you extend it from Fragment when using the "New Class Wizard". Or just copy the code into your new created class. That's a very simple class. It is only responsible for creating a new Fragment from the given layout we have just defined in the sections above.

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

public class FragmentHorizontal extends Fragment {
 
 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  View view = inflater.inflate(R.layout.fragment_horizontal, null);
  Button button = (Button) view.findViewById(R.id.hbutton1);
  button.setText("horizontal");
  return view;
 }

}

Creating the next Fragment with vertical layout 

Do it analogue the section above. Create a new class and name it "FragmentVertical". Copy/Paste the code and go to the next step. ;-)

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

public class FragmentVertical extends Fragment {
 
 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  View view = inflater.inflate(R.layout.fragment_vertical, null);
  Button button = (Button) view.findViewById(R.id.vbutton1);
  button.setText("vertical");
  return view;
 }

}

We are almost done! 

The main activity. Place the codefragment bellow into it. After that press the button in the middle to replace it as many times as you want. Press Run>Android Application

import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

 private boolean flip = false;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  FragmentVertical fv = new FragmentVertical();
  FragmentManager fm = getFragmentManager();
  FragmentTransaction ft = fm.beginTransaction();
  ft.add(R.id.layoutToReplace, fv);
  ft.commit();

  Button b = (Button) findViewById(R.id.button1);
  b.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    if (!flip) {
     FragmentHorizontal fh = new FragmentHorizontal();
     FragmentManager fm = getFragmentManager();
     FragmentTransaction ft = fm.beginTransaction();
     ft.replace(R.id.layoutToReplace, fh);
     ft.commit();
     flip = true;
    } else {
     FragmentVertical fv = new FragmentVertical();
     FragmentManager fm = getFragmentManager();
     FragmentTransaction ft = fm.beginTransaction();
     ft.replace(R.id.layoutToReplace, fv);
     ft.commit();
     flip = false;
    }
   }
  });
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

}
If everything went well, you should see something like that.



So that's all. I hope you like it. Have fun! ;-)

😱👇 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘‡

Be sure to read, it will change your life!
Show your work by Austin Kleon: https://amzn.to/34NVmwx

This book is a must read - it will put you in another level! (Expert)
Agile Software Development, Principles, Patterns, and Practices: https://amzn.to/30WQSm2

Write cleaner code and stand out!
Clean Code - A Handbook of Agile Software Craftsmanship: https://amzn.to/33RvaSv

This book is very practical, straightforward and to the point! Worth every penny!
Kotlin for Android App Development (Developer's Library): https://amzn.to/33VZ6gp

Needless to say, these are top right?
Apple AirPods Pro: https://amzn.to/2GOICxy

😱👆 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘†

Thursday, October 3, 2013

Drawing and mixing colors with Canvas / View in Android

Hi there! Today i'm gonna share something very cool with you. It took me a lot of days "scanning" the web for a solution, trying by myself, debugging and so on. unfortunately i didn't find i solution that fits my needs. Solving problems using canvas can be very exciting, but it can also quickly become very depressing if you do not have the perseverance necessary or basic understanding of how things work at this level. 

To prevent you from getting discouraged, I'll share my solution with you. Here's the challange: Draw arbitrary shapes (splashes) in different colors in a view.(using canvas, drawing methods, paints etc.) Be able to drag and drop it around the view. If the splashes intersects, the intersection should be colored according to the color mixture of the two parts. Then i should be able to read the pixel of the new color to use it the way i want. (Ohhhh my god...!!!!) That's a challange right? ;-) 

So i did it!!! ;-) There is a lot of fragments out there, but nothing complete and because i know this is a very common task desired by many developers, i took the time to do it as clean and reusable as i could.  The result will be something like this:









ShapeTypes

Let's define the shape types we wanna use it first. For sure you could enhance it by adding new types if you need.




public enum ShapeType {
    CIRCLE, RECTANBLE, ARBITRARY_SHAPE
}


ShapeFactory

Then let's define a class that is responsible for creating the shapes. In our cases the splashes. The empty cases can be enhenced by you by adding new shapes to it.




public class ShapeFactory {

    public static void createShape(Path path, float shapeSizeFactor, final int randomShapeId) {

        switch (randomShapeId) {
        case 1:
            path.moveTo(379 * shapeSizeFactor, 616 * shapeSizeFactor);
            int[] shapeCoordinates;
            shapeCoordinates = new int[] { 379, 616, 379, 614, 379, 613, 379, 612, 379, 610, 379, 609, 379, 607, 381, 600, 383, 593, 384, 585, 381, 565, 375, 555, 361, 530, 354, 517,
                    345, 503, 337, 489, 315, 457, 303, 441, 292, 425, 283, 412, 274, 398, 266, 384, 261, 373, 256, 363, 253, 354, 252, 334, 253, 322, 255, 309, 258, 298, 262, 288,
                    266, 280, 270, 272, 276, 265, 283, 256, 294, 249, 304, 244, 314, 239, 322, 236, 329, 235, 336, 235, 355, 237, 373, 242, 380, 245, 390, 251, 393, 254, 402, 263,
                    408, 269, 416, 278, 422, 289, 430, 300, 437, 313, 450, 340, 453, 355, 456, 369, 458, 381, 461, 402, 462, 412, 464, 421, 465, 430, 466, 438, 467, 446, 470, 453,
                    476, 465, 481, 470, 490, 474, 499, 476, 510, 478, 520, 477, 529, 475, 538, 472, 545, 468, 553, 462, 559, 455, 565, 446, 570, 435, 578, 414, 581, 402, 588, 374,
                    595, 347, 599, 333, 610, 300, 616, 287, 622, 275, 630, 265, 639, 256, 648, 247, 656, 239, 665, 232, 672, 226, 681, 222, 692, 217, 704, 215, 713, 213, 728, 213,
                    734, 213, 740, 214, 747, 215, 753, 218, 759, 221, 765, 226, 771, 231, 777, 237, 781, 245, 785, 252, 786, 259, 788, 267, 788, 276, 788, 285, 787, 294, 784, 303,
                    783, 312, 780, 320, 776, 328, 771, 336, 767, 345, 762, 354, 752, 374, 748, 385, 744, 394, 741, 403, 735, 414, 729, 427, 721, 440, 715, 452, 708, 463, 702, 474,
                    694, 486, 690, 499, 685, 511, 678, 534, 677, 542, 676, 553, 677, 558, 684, 563, 693, 563, 705, 560, 718, 554, 730, 547, 747, 539, 785, 520, 800, 512, 835, 496,
                    850, 490, 871, 481, 880, 478, 888, 477, 894, 476, 900, 476, 906, 477, 910, 478, 915, 481, 918, 484, 927, 492, 931, 500, 933, 507, 935, 515, 936, 522, 937, 537,
                    933, 552, 930, 561, 919, 575, 912, 581, 904, 588, 896, 594, 888, 599, 879, 603, 855, 611, 839, 614, 827, 616, 818, 620, 801, 630, 793, 637, 782, 653, 780, 661,
                    780, 670, 782, 678, 789, 689, 797, 703, 806, 718, 829, 750, 842, 768, 853, 787, 861, 802, 869, 819, 879, 857, 882, 874, 885, 892, 887, 913, 888, 930, 887, 947,
                    885, 966, 880, 986, 873, 1002, 863, 1019, 849, 1035, 832, 1049, 795, 1064, 771, 1062, 757, 1051, 744, 1037, 730, 1018, 719, 996, 712, 975, 708, 954, 706, 907, 706,
                    888, 704, 868, 701, 853, 695, 839, 688, 828, 663, 813, 637, 813, 616, 817, 600, 826, 567, 863, 558, 883, 554, 908, 554, 933, 570, 982, 581, 1006, 590, 1029, 598,
                    1055, 602, 1104, 597, 1133, 588, 1161, 573, 1191, 533, 1244, 505, 1268, 477, 1286, 402, 1315, 364, 1324, 339, 1326, 286, 1316, 271, 1306, 253, 1291, 236, 1269,
                    219, 1227, 219, 1205, 222, 1188, 228, 1172, 256, 1137, 275, 1116, 300, 1094, 321, 1074, 356, 1032, 373, 1011, 385, 991, 394, 961, 393, 947, 388, 934, 368, 915,
                    352, 907, 314, 892, 305, 886, 309, 866, 332, 831, 344, 814, 363, 782, 367, 764, 365, 759, 354, 750, 344, 748, 330, 747, 310, 747, 278, 754, 243, 769, 195, 799,
                    160, 810, 142, 809, 136, 805, 124, 789, 119, 774, 116, 760, 115, 743, 117, 710, 121, 695, 126, 681, 140, 652, 151, 641, 168, 629, 192, 619, 204, 619, 218, 619,
                    231, 620, 253, 626, 261, 629, 269, 633, 278, 636, 306, 637, 318, 634, 330, 631, 342, 627, 370, 615, 373, 614, 373, 614 };
            for (int i = 0; i < shapeCoordinates.length - 2; i += 2) {
                path.lineTo(shapeCoordinates[i] * shapeSizeFactor, shapeCoordinates[i + 1] * shapeSizeFactor);
            }
            path.close();
            break;
        case 2:

            break;
        case 3:

            break;
        default:
            break;
        }
   
    }

}


ObjectView

That's the class responsible for drawing the shapes.




import java.util.Random;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelXorXfermode;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class ObjectView extends View {

    private Paint paint;
    private boolean isTouched;
    private ShapeType shapeType;
    private float shapeSizeFactor;

    public ObjectView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}
    public ObjectView(Context context, AttributeSet attrs) {super(context, attrs);}

    public ObjectView(Context context, int shapeColor, int initialPositionX, int initialPositionY, ShapeType type) {
        super(context);
        setBackgroundColor(Color.TRANSPARENT);
        paint = new Paint();
        paint.setColor(shapeColor);
        paint.setXfermode(new PorterDuffXfermode(Mode.ADD));
        // paint.setXfermode(new PixelXorXfermode(0xFFFFFFFF));
        shapeType = type;
        setTranslationX(initialPositionX);
        setTranslationY(initialPositionY);
    }

    public ObjectView(Context context, int shapeColor, int initialPositionX, int initialPositionY, ShapeType type, float shapeSizeFactor) {
        this(context, shapeColor, initialPositionX, initialPositionY, type);
        this.shapeSizeFactor = shapeSizeFactor;
    }

    public void onDrawEx(Canvas canvas) {
        switch (shapeType) {
        case CIRCLE:
            int circleXCoordinate = getWidth() / 2;
            int circleYCoordinate = getHeight() / 2;
            int circleRadius = getWidth() / 2;
            canvas.drawCircle(circleXCoordinate, circleYCoordinate, circleRadius, paint);
            break;
        case RECTANBLE:
            float left = 0;
            float top = 0;
            float right = getWidth();
            float bottom = getHeight();
            canvas.drawRect(left, top, right, bottom, paint);
            break;
        case ARBITRARY_SHAPE:
            Path path = new Path();
            path.addPath(path, new Matrix());
            int min = 1;
            int max = 10;
            Random randomShapeIdGenerator = new Random();
            int randomShapeId = randomShapeIdGenerator.nextInt(max - min + 1) + min;
            ShapeFactory.createShape(path, this.shapeSizeFactor, /*randomShapeId*/1);
            canvas.drawPath(path, paint);
            break;
        }
    }

    public boolean isTouched() {return isTouched;}
    public void setTouched(boolean touched) {isTouched = touched;}

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        isTouched = true;
        return super.onTouchEvent(event);
    }
}


ObjectViewLayout

thats the main layout that holds all views and it is responsible for moving the shapes around and find out the intersection's color, if the shapes are mixed in the middle of the screen.




import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;

public class ObjectViewLayout extends FrameLayout {

    public ObjectViewLayout(Context context) {
        super(context);
    }

    public ObjectViewLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ObjectViewLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getActionMasked()) {
        case MotionEvent.ACTION_UP:
            for (int i = 0; i < getChildCount() - 1; i++) {
                ObjectView objectView = (ObjectView) getChildAt(i);
                objectView.setTouched(false);
            }
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_MOVE:

            for (int i = 0; i < getChildCount() - 1; i++) {
                ObjectView objectView = (ObjectView) getChildAt(i);
                if (objectView.isTouched()) {
                    objectView.setTranslationX(event.getX() - objectView.getWidth() / 2);
                    objectView.setTranslationY(event.getY() - objectView.getHeight() / 2);

                    break;
                }
            }
        }
        // THE NEXT LINE REPRESENTS/CALLS THE OVERLAYVIEW
        getChildAt(getChildCount() - 1).invalidate();
        // THIS LINE SETS/CHECKS MIXED COLORS TO USE THE WAY YOU MAY WANT
        new Colorize().setColorToPen(getColorFromMiddleOfThisObject());
        return true;
    }

    public int getColorFromMiddleOfThisObject() {
        Bitmap returnedBitmap = getBitmapFromView(this);
        int pixel = returnedBitmap.getPixel(this.getWidth()/2, this.getHeight()/2);
        Log.i("TEST", "Pixel value ObjectViewLayout: "+pixel);
        return pixel;
    }
   
    private Bitmap getBitmapFromView(View view) {
        Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(returnedBitmap);
        Drawable backgroundDrawable = view.getBackground();
        if (backgroundDrawable != null)
            backgroundDrawable.draw(canvas);
        else
            // does not have background drawable, then draw dark grey background
            // on the canvas to be able to detect it.
            canvas.drawColor(Color.DKGRAY);
        view.draw(canvas);
        return returnedBitmap;
    }

}


OverlayView

That's the view responsible for triggering the repaint/redrawing process.




import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

@SuppressLint("DrawAllocation")
public class OverlayView extends View {

    public OverlayView(Context context) {
        super(context);
    }

    public OverlayView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public OverlayView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888);
        Canvas canvasBitmap = new Canvas(bitmap);
        ViewGroup viewGroup = (ViewGroup) getParent();
        for (int i = 0; i < viewGroup.getChildCount() - 1; i++) {

            ObjectView objectView = (ObjectView) viewGroup.getChildAt(i);
            canvasBitmap.save();
            canvasBitmap.translate(objectView.getTranslationX(), objectView.getTranslationY());
            objectView.onDrawEx(canvasBitmap);
            canvasBitmap.restore();
        }
        float left = 0;
        float top = 0;
        canvas.drawBitmap(bitmap, left, top, new Paint());

    }

}


Colorize

This is the class that interprets the mixed pixel color. Here you could do / set what ever you want.




import android.graphics.Color;
import android.util.Log;

public class Colorize {
   
    public void setColorToPen(int pixelColor) {
       

        if (pixelColor == Color.MAGENTA) {
            Log.i("TEST", "It is MAGENTA");
        }
        if (pixelColor == Color.RED) {
            Log.i("TEST", "It is RED");
        }
        if (pixelColor == Color.BLUE) {
            Log.i("TEST", "It is BLUE");
        }
        if (pixelColor == Color.GREEN) {
            Log.i("TEST", "It is GREEN");
        }
        if (pixelColor == Color.YELLOW) {
            Log.i("TEST", "It is YELLOW");
        }
        if (pixelColor == Color.CYAN) {
            Log.i("TEST", "It is CYAN");
        }
        if (pixelColor == Color.BLACK) {
            Log.i("TEST", "It is BLACK");
        }
        if (pixelColor == Color.TRANSPARENT) {
            Log.i("TEST", "It is TRANSPARENT");
        }
        if (pixelColor == Color.WHITE) {
            Log.i("TEST", "It is WHITE");
        }
        if (pixelColor == Color.GRAY) {
            Log.i("TEST", "It is GREY");
        }
    }

}


MainActivity

Finally let's take a look at the main activity class.




import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Menu;
import android.widget.FrameLayout;

public class MainActivity extends Activity {

    private OverlayView overlayView;
    private ObjectViewLayout objectViewLayout;
    private ObjectView shape1;
    private ObjectView shape2;
    private ObjectView shape3;
    private int initialPositionX = 70;
    private int initialPositionY = 70;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        float sizeFactor = 0.1f;
        objectViewLayout = new ObjectViewLayout(this);

        initialPositionX = 70;
        initialPositionY = 70;
        shape1 = new ObjectView(this, Color.RED, initialPositionX, initialPositionY, ShapeType.ARBITRARY_SHAPE, sizeFactor);
        objectViewLayout.addView(shape1, new FrameLayout.LayoutParams(150, 150));

        initialPositionX = 140;
        initialPositionY = 140;
        shape2 = new ObjectView(this, Color.BLUE, initialPositionX, initialPositionY, ShapeType.ARBITRARY_SHAPE, sizeFactor);
        objectViewLayout.addView(shape2, new FrameLayout.LayoutParams(150, 150));

        int initialPositionX = 210;
        int initialPositionY = 210;
        shape3 = new ObjectView(this, Color.GREEN, initialPositionX, initialPositionY, ShapeType.ARBITRARY_SHAPE, sizeFactor);
        objectViewLayout.addView(shape3, new FrameLayout.LayoutParams(150, 150));

        overlayView = new OverlayView(this);
        objectViewLayout.addView(overlayView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));

        setContentView(objectViewLayout);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}


Thats all. Hope you like it. :)  If you run this project now, you should get the result i showed to you at the beginning of this post.

😱👇 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘‡

Be sure to read, it will change your life!
Show your work by Austin Kleon: https://amzn.to/34NVmwx

This book is a must read - it will put you in another level! (Expert)
Agile Software Development, Principles, Patterns, and Practices: https://amzn.to/30WQSm2

Write cleaner code and stand out!
Clean Code - A Handbook of Agile Software Craftsmanship: https://amzn.to/33RvaSv

This book is very practical, straightforward and to the point! Worth every penny!
Kotlin for Android App Development (Developer's Library): https://amzn.to/33VZ6gp

Needless to say, these are top right?
Apple AirPods Pro: https://amzn.to/2GOICxy

😱👆 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘†

Tuesday, June 11, 2013

How to use ORMLite, save complex objects into SQLite and autogenerate DAO's in your Android App

Hi there! Today i'm gonna show you something really really nice if you are writing android apps using a SQLite model and are still creating entities by hand and embbeding SQLite commands in your code.

ORMLite is a lite version of an ORM tool to manipulate database access. It provides DAO's and SQL commands and you don't need to program it by yourself. It saves a lot of time. I was really surprised how easy it was to implement it. Because i think this a really nice tool, i want to share my expirience with you. I also solved the problem of saving complex objects with it. The example bellow is a little proof of concept i did. I use ORMLite to manage Entities, generate DTO's automatically and to facilitate communication between SQLite (database) and Application. The following link describes the use ORMLite: http://ormlite.com/javadoc/ormlite-core/doc-files/ormlite_4.html#Use-With-Android

Installation of ORMLite:

1. Download libraries ormlite-core.jar and ormlite-android.jar
2. Copy the libraries into folder libs of your android project. (Android will auto-reference it)
3. Create the desired entities and annotate them appropriately as in the following example: (make sure that the default-constructors were defined as ORMLite requires them to their proper operation.)




import java.util.Date;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;

@DatabaseTable(tableName = "contato")
public class ContatoEntity {

        // generatedId set to false, because we will get it from the server!
        @DatabaseField(id = true, generatedId = false) public int id;
        @DatabaseField public String descricao;
        @DatabaseField public String ddi;
        @DatabaseField public String ddd;
        @DatabaseField public Date timestamp;
        public ContatoEntity() {/*OrmLite need a default constructor*/}
}

import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;

@DatabaseTable(tableName = "pessoa")
public class PessoaEntity {

        @DatabaseField(id = true, generatedId = false) public int id;
        @DatabaseField public String nome;
        @DatabaseField(canBeNull = false, foreign = true) public TipoPessoaEntity tpPessoa;
        public PessoaEntity() {/*OrmLite need a default constructor*/}
//Atention: Take a special look at the annotation of tpPessoa bellow! we will discuss it later!
}

import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;

@DatabaseTable(tableName = "pessoa")
public class PessoaEntity {
        @DatabaseField(id = true, generatedId = false) public int id;
        @DatabaseField public String nome;
        @DatabaseField(canBeNull = false, foreign = true,foreignAutoCreate = true,foreignAutoRefresh = true)
        public TipoPessoaEntity tpPessoa;
        public PessoaEntity() {/*OrmLite need a default constructor*/}


Create a proper DatabaseOpenHelper

You helper must extend from OrmLiteSqliteOpenHelper as in the following example:



public class DatabaseHelper extends OrmLiteSqliteOpenHelper {

        private static final String DATABASE_NAME = "db_mobtur.db";
        private static final int DATABASE_VERSION = 1;

        public DatabaseHelper(Context context) {
                super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) {
                try {
                        Log.i(DatabaseHelper.class.getName(), "onCreate");
                        TableUtils.createTable(connectionSource, ContatoEntity.class);
                        TableUtils.createTable(connectionSource, PessoaEntity.class);
                        TableUtils.createTable(connectionSource, TipoPessoaEntity.class);
                } catch (SQLException e) {
                        Log.e(DatabaseHelper.class.getName(), "Can't create database", e);
                        throw new RuntimeException(e);
                }
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int oldVersion, int newVersion) {
                try {
                        Log.i(DatabaseHelper.class.getName(), "onUpgrade");
                        TableUtils.dropTable(connectionSource, ContatoEntity.class, true);
                        TableUtils.dropTable(connectionSource, PessoaEntity.class, true);
                        TableUtils.dropTable(connectionSource, TipoPessoaEntity.class, true);
                        onCreate(db, connectionSource);
                } catch (SQLException e) {
                        Log.e(DatabaseHelper.class.getName(), "Can't drop databases", e);
                        throw new RuntimeException(e);
                }
        }

        @Override
        public void close() {
                super.close();
        }
}


Create a class DaoFactory 

The DaoFactory is responsible for creating all DAO's we will need as in the following example:



public class DtoFactory extends Application {

        private SharedPreferences preferences;
        private DatabaseHelper databaseHelper = null;

        private Dao<ContatoEntity, Integer> contatoDAO = null;
        private Dao<PessoaEntity, Integer> pessoaDAO = null;
        private Dao<TipoPessoaEntity, Integer> tpContatoDAO = null;

        @Override
        public void onCreate() {
                super.onCreate();
                preferences = PreferenceManager.getDefaultSharedPreferences(this);
                databaseHelper = new DatabaseHelper(this);
        }

        public File getVideosDir() {return videos_dir;}
        public SharedPreferences getPreferences() {return preferences;}

        public Dao<ContatoEntity, Integer> getContatoDao() throws SQLException {
                if (contatoDAO == null) {
                        contatoDAO = databaseHelper.getDao(ContatoEntity.class);
                }
                return contatoDAO;
        }

        public Dao<PessoaEntity, Integer> getPessoaDao() throws SQLException {
                if (pessoaDAO == null) {
                        pessoaDAO = databaseHelper.getDao(PessoaEntity.class);
                }
                return pessoaDAO;
        }

        public Dao<TipoPessoaEntity, Integer> getTpPessoaDao() throws SQLException {
                if (tpContatoDAO == null) {
                        tpContatoDAO = databaseHelper.getDao(TipoPessoaEntity.class);
                }
                return tpContatoDAO;
        }

        @Override
        public void onTerminate() {
                super.onTerminate();
                if (databaseHelper != null) {
                        OpenHelperManager.releaseHelper();
                        databaseHelper = null;
                }
        }
} 

Using the entities in your Activity as desired. 

Warning: The ORMLite framework does not offer a mechanism for insertion of complex objects (classes that contains within itself another class as property). For that we must always keep in mind, that we have to first save the child class and then the parent class, and then combines them. The example below illustrates this problem with a solution. Note: If the class is composed of several hierarchias of composite properties, the only solution i found is to do a recursive method that dives into it and runs backwards inserting and linking the children to its parents. The followed annotation must be used be used by all child classes: (remember the annotation of pessoaEntitiy above? if not look at it now! ;-)


@DatabaseField(foreign = true,foreignAutoCreate = true,foreignAutoRefresh = true) 

This annotation ensures that the complex type (childs) are really saved in the database and not only updated. See the example bellow:



public class MainActivity extends Activity {

        private String LOG_TAG = MainActivity.class.getSimpleName();
        private DtoFactory dtoFactory;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                dtoFactory = (DtoFactory) getApplication();
        }

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
                getMenuInflater().inflate(R.menu.main, menu);
                return true;
        }

        public void onclick(View view) throws SQLException {
                try {
                       
                        Dao<PessoaEntity, Integer> pDao = dtoFactory.getPessoaDao();
                        Dao<TipoPessoaEntity, Integer> tpDao = dtoFactory.getTpPessoaDao();

                        switch (view.getId()) {
                       
                        case R.id.btnInsert:
                               System.out.println("insert");
                               TipoPessoaEntity tpessoa = new TipoPessoaEntity();
                               tpessoa.id = new Random().nextInt(100);
                               tpessoa.descricao = "descricao_" + System.currentTimeMillis();
                               tpDao.create(tpessoa);
                              
                               PessoaEntity pe1 = new PessoaEntity();
                               pe1.id = new Random().nextInt(100);
                               pe1.nome = "TestName";
                               pe1.tpPessoa = tpessoa;
                               pDao.create(pe1);
                               break;
                              
                        case R.id.btnUpdate:
                               System.out.println("update");
                               break;
                              

                        case R.id.btnSelect:
                               System.out.println("select: " + pDao.countOf());
                               for (PessoaEntity entity : pDao.queryForAll()) {
                                       System.out.println(String.format("Id: %d, Nome: %s, Tp: %s", entity.id, entity.nome, entity.tpPessoa.descricao));
                                       Log.d(LOG_TAG, String.format("Id: %d, Nome: %s, Tp: %s", entity.id, entity.nome, entity.tpPessoa.descricao));
                               }
                               break;
                              
                        case R.id.btnDelete:
                               System.out.println("delete");
                               break;
                              
                        default:
                               break;
                        }
                } catch (Exception e) {
                        System.out.println();
                }
        }

        @Override
        protected void onDestroy() {
                super.onDestroy();
        }
}



1  Proof of Concept

Copy this xml code into your MainActivity: 



<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/btnInsert"
        android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="onclick" android:text="Insert"/>

    <Button
        android:id="@+id/btnUpdate"
        android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:onClick="onclick" android:text="Update"/>

    <Button
        android:id="@+id/btnSelect"
        android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:onClick="onclick" android:text="Select"/>

    <Button
        android:id="@+id/btnDelete"
        android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:onClick="onclick" android:text="Delete"/>

</LinearLayout>

Testing on the Emulator 

If everything goes right you should have something like this at this point of the post:


Result


😱👇 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘‡

Be sure to read, it will change your life!
Show your work by Austin Kleon: https://amzn.to/34NVmwx

This book is a must read - it will put you in another level! (Expert)
Agile Software Development, Principles, Patterns, and Practices: https://amzn.to/30WQSm2

Write cleaner code and stand out!
Clean Code - A Handbook of Agile Software Craftsmanship: https://amzn.to/33RvaSv

This book is very practical, straightforward and to the point! Worth every penny!
Kotlin for Android App Development (Developer's Library): https://amzn.to/33VZ6gp

Needless to say, these are top right?
Apple AirPods Pro: https://amzn.to/2GOICxy

😱👆 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘†