[Huawei Developers] muraliameakula:
​

Introduction

HarmonyOs is a next-generation operating system that empowers interconnection and collaboration between smart devices. It delivers smooth simple interaction that is reliable in all scenarios.

SQLite is an open-source relational database which is used to perform database operations on devices such as storing, manipulating or retrieving persistent data from the database.

HarmonyOs uses SQLite DB for managing local database and called it is as HarmonyOs RDB (relational database).

Takeaways

Integrate HarmonyOs RDB in the application.

Navigate from one Ability Slice to another and sending data while doing it.

Learn to create UI using Directional Layout.

Default and customize Dialog.

Providing background color to buttons or layout programmatically.

HarmonyOs Animation.

Demo

To understand how HarmonyOs works with SQLite DB, I have created a Quiz App and inserted all the questions data using SQLite database as shown below:

Integrating HarmonyOs RDB

Step 1: Create Questions model (POJO) class.

public class Questions {
private int id;
private String topic;
private String question;
private String optionA;
private String optionB;
private String optionC;
private String optionD;
private String answer;

public Questions(String topc, String ques, String opta, String optb, String optc, String optd, String ans) {
topic = topc;
question = ques;
optionA = opta;
optionB = optb;
optionC = optc;
optionD = optd;
answer = ans;
}

public Questions() {
id = 0;
topic = "";
question = "";
optionA = "";
optionB = "";
optionC = "";
optionD = "";
answer = "";
}

public void setId(int id) {
this.id = id;
}

public String getTopic() {
return topic;
}

public void setTopic(String topic) {
this.topic = topic;
}

public String getQuestion() {
return question;
}

public void setQuestion(String question) {
this.question = question;
}

public String getOptionA() {
return optionA;
}

public void setOptionA(String optionA) {
this.optionA = optionA;
}

public String getOptionB() {
return optionB;
}

public void setOptionB(String optionB) {
this.optionB = optionB;
}

public String getOptionC() {
return optionC;
}

public void setOptionC(String optionC) {
this.optionC = optionC;
}

public String getOptionD() {
return optionD;
}

public void setOptionD(String optionD) {
this.optionD = optionD;
}

public String getAnswer() {
return answer;
}

public void setAnswer(String answer) {
this.answer = answer;
}
}

Step 2: Create a class and name it as QuizDatabaseHelper.

Step 3: Extends the class with DatabaseHelper class.

Step 4: After that we need to configure the RDB store. For that we need to use StoreConfig.

StoreConfig config = StoreConfig.newDefaultConfig("QuizMania.db");

Step 5: Use RdbOpenCallback abstract class to create the table and if we need to modify the table, we can use this class to upgrade the version of the Database to avoid crashes.

RdbOpenCallback callback = new RdbOpenCallback() {
@Override
public void onCreate(RdbStore store) {

store.executeSql("CREATE TABLE " + TABLE_NAME + " ( " + ID + " INTEGER PRIMARY KEY AUTOINCREMENT , " + TOPIC + " VARCHAR(255), " + QUESTION + " VARCHAR(255), " + OPTIONA + " VARCHAR(255), " + OPTIONB + " VARCHAR(255), " + OPTIONC + " VARCHAR(255), " + OPTIOND + " VARCHAR(255), " + ANSWER + " VARCHAR(255))");
}
@Override
public void onUpgrade(RdbStore store, int oldVersion, int newVersion) {
}
};

Step 6: Use DatabaseHelper class to obtain the RDB store.

DatabaseHelper helper = new DatabaseHelper(context);
store = helper.getRdbStore(config, 1, callback, null);

Step 7: In order to insert question data we will use ValueBucket of RDB.

private void insertAllQuestions(ArrayList<Questions> allQuestions){
ValuesBucket values = new ValuesBucket();
for(Questions question : allQuestions){
values.putString(TOPIC, question.getTopic());
values.putString(QUESTION, question.getQuestion());
values.putString(OPTIONA, question.getOptionA());
values.putString(OPTIONB, question.getOptionB());
values.putString(OPTIONC, question.getOptionC());
values.putString(OPTIOND, question.getOptionD());
values.putString(ANSWER, question.getAnswer());
long id = store.insert("QUIZMASTER", values);
}
}

Step 8: In order to retrieve all the question data we will use RdbPredicates and ResultSet. RdbPredicates helps us to combine SQL statements simply by calling methods using this class, such as equalTo, notEqualTo, groupBy, orderByAsc, and beginsWith. ResultSet on the other hand helps us to retrieve the data that we have queried.

public List<Questions> getAllListOfQuestions(String topicName) {
List<Questions> questionsList = new ArrayList<>();
String[] columns = new String[] {ID, TOPIC, QUESTION, OPTIONA,OPTIONB,OPTIONC,OPTIOND,ANSWER};
RdbPredicates rdbPredicates = new RdbPredicates(TABLE_NAME).equalTo(TOPIC, topicName);
ResultSet resultSet = store.query(rdbPredicates, columns);
while (resultSet.goToNextRow()){
Questions question = new Questions();
question.setId(resultSet.getInt(0));
question.setTopic(resultSet.getString(1));
question.setQuestion(resultSet.getString(2));
question.setOptionA(resultSet.getString(3));
question.setOptionB(resultSet.getString(4));
question.setOptionC(resultSet.getString(5));
question.setOptionD(resultSet.getString(6));
question.setAnswer(resultSet.getString(7));
questionsList.add(question);
}
return questionsList;
}

Step 9: Let's call the QuizDatabaseHelper class in Ability Slice and get all the question from the stored database.

QuizDatabaseHelper quizDatabaseHelper = new QuizDatabaseHelper(getContext());
quizDatabaseHelper.initDb();

if (quizDatabaseHelper.getAllListOfQuestions(topicName).size() == 0) {
quizDatabaseHelper.listOfAllQuestion();
}
List<Questions> list = quizDatabaseHelper.getAllListOfQuestions(topicName);
Collections.shuffle(list);
Questions questionObj = list.get(questionId);

QuizDatabaseHelper.java

public class QuizDatabaseHelper extends DatabaseHelper {
Context context;
StoreConfig config;
RdbStore store;
private static final String TABLE_NAME = "QUIZMASTER";
private static final String ID = "_ID";
private static final String TOPIC = "TOPIC";
private static final String QUESTION = "QUESTION";
private static final String OPTIONA = "OPTIONA";
private static final String OPTIONB = "OPTIONB";
private static final String OPTIONC = "OPTIONC";
private static final String OPTIOND = "OPTIOND";
private static final String ANSWER = "ANSWER";

public QuizDatabaseHelper(Context context) {
super(context);
this.context = context;

}
public void initDb(){
config = StoreConfig.newDefaultConfig("QuizMania.db");
RdbOpenCallback callback = new RdbOpenCallback() {
@Override
public void onCreate(RdbStore store) {

store.executeSql("CREATE TABLE " + TABLE_NAME + " ( " + ID + " INTEGER PRIMARY KEY AUTOINCREMENT , " + TOPIC + " VARCHAR(255), " + QUESTION + " VARCHAR(255), " + OPTIONA + " VARCHAR(255), " + OPTIONB + " VARCHAR(255), " + OPTIONC + " VARCHAR(255), " + OPTIOND + " VARCHAR(255), " + ANSWER + " VARCHAR(255))");
}
@Override
public void onUpgrade(RdbStore store, int oldVersion, int newVersion) {
}
};
DatabaseHelper helper = new DatabaseHelper(context);
store = helper.getRdbStore(config, 1, callback, null);

}
public void listOfAllQuestion() {
// Generic type is Questions POJO class.
ArrayList<Questions> arraylist = new ArrayList<>();

// General Knowledge Questions...
arraylist.add(new Questions("gk","India has largest deposits of ____ in the world.", "Gold", "Copper", "Mica", "None of the above", "Mica"));

arraylist.add(new Questions("gk","Who was known as Iron man of India ?", "Govind Ballabh Pant", "Jawaharlal Nehru", "Subhash Chandra Bose", "Sardar Vallabhbhai Patel", "Sardar Vallabhbhai Patel"));

arraylist.add(new Questions("gk", "India participated in Olympics Hockey in", "1918", "1928", "1938", "1948", "1928"));

arraylist.add(new Questions("gk","Who is the Flying Sikh of India ?", "Mohinder Singh", "Joginder Singh", "Ajit Pal Singh", "Milkha singh", "Milkha singh"));

arraylist.add(new Questions("gk","How many times has Brazil won the World Cup Football Championship ?", "Four times", "Twice", "Five times", "Once", "Five times"));

// Sports Questions..
arraylist.add(new Questions("sp","Which was the 1st non Test playing country to beat India in an international match ?", "Canada", "Sri Lanka", "Zimbabwe", "East Africa", "Sri Lanka"));

arraylist.add(new Questions("sp","Ricky Ponting is also known as what ?", "The Rickster", "Ponts", "Ponter", "Punter", "Punter"));

arraylist.add(new Questions("sp","India won its first Olympic hockey gold in...?", "1928", "1932", "1936", "1948", "1928"));

arraylist.add(new Questions("sp","The Asian Games were held in Delhi for the first time in...?", "1951", "1963", "1971", "1982", "1951"));

arraylist.add(new Questions("sp","The 'Dronacharya Award' is given to...?", "Sportsmen", "Coaches", "Umpires", "Sports Editors", "Coaches"));

// History Questions...
arraylist.add(new Questions("his","The Battle of Plassey was fought in", "1757", "1782", "1748", "1764", "1757"));

arraylist.add(new Questions("his","The title of 'Viceroy' was added to the office of the Governor-General of India for the first time in", "1848 AD", "1856 AD", "1858 AD", "1862 AD", "1858 AD"));

arraylist.add(new Questions("his","Tipu sultan was the ruler of", "Hyderabad", "Madurai", "Mysore", "Vijayanagar", "Mysore"));

arraylist.add(new Questions("his","The Vedas contain all the truth was interpreted by", "Swami Vivekananda", "Swami Dayananda", "Raja Rammohan Roy", "None of the above", "Swami Dayananda"));

arraylist.add(new Questions("his","The Upanishads are", "A source of Hindu philosophy", "Books of ancient Hindu laws", "Books on social behavior of man", "Prayers to God", "A source of Hindu philosophy"));

// General Science Questions...
arraylist.add(new Questions("gs","Which of the following is a non metal that remains liquid at room temperature ?", "Phosphorous", "Bromine", "Chlorine", "Helium", "Bromine"));

arraylist.add(new Questions("gs","Which of the following is used in pencils?", "Graphite", "Silicon", "Charcoal", "Phosphorous", "Graphite"));

arraylist.add(new Questions("gs","The gas usually filled in the electric bulb is", "Nitrogen", "Hydrogen", "Carbon Dioxide", "Oxygen", "Nitrogen"));

arraylist.add(new Questions("gs","Which of the gas is not known as green house gas ?", "Methane", "Nitrous oxide", "Carbon dioxide", "Hydrogen", "Hydrogen"));

arraylist.add(new Questions("gs","The hardest substance available on earth is", "Gold", "Iron", "Diamond", "Platinum", "Diamond"));

this.insertAllQuestions(arraylist);

}

private void insertAllQuestions(ArrayList<Questions> allQuestions){
ValuesBucket values = new ValuesBucket();
for(Questions question : allQuestions){
values.putString(TOPIC, question.getTopic());
values.putString(QUESTION, question.getQuestion());
values.putString(OPTIONA, question.getOptionA());
values.putString(OPTIONB, question.getOptionB());
values.putString(OPTIONC, question.getOptionC());
values.putString(OPTIOND, question.getOptionD());
values.putString(ANSWER, question.getAnswer());
long id = store.insert("QUIZMASTER", values);
}
}

public List<Questions> getAllListOfQuestions(String topicName) {
List<Questions> questionsList = new ArrayList<>();
String[] columns = new String[] {ID, TOPIC, QUESTION, OPTIONA,OPTIONB,OPTIONC,OPTIOND,ANSWER};
RdbPredicates rdbPredicates = new RdbPredicates(TABLE_NAME).equalTo(TOPIC, topicName);
ResultSet resultSet = store.query(rdbPredicates, columns);
while (resultSet.goToNextRow()){
Questions question = new Questions();
question.setId(resultSet.getInt(0));
question.setTopic(resultSet.getString(1));
question.setQuestion(resultSet.getString(2));
question.setOptionA(resultSet.getString(3));
question.setOptionB(resultSet.getString(4));
question.setOptionC(resultSet.getString(5));
question.setOptionD(resultSet.getString(6));
question.setAnswer(resultSet.getString(7));
questionsList.add(question);
}
return questionsList;
}
}

HarmonyOs Navigation

An Ability Slice represents a single screen and its control logic. In terms of Android, it is like a Fragment and Page Ability is like an Activity in Android. An ability slice's lifecycle is bound to the Page ability that hosts it.

Now, if we need to navigate with data from one Ability Slice to another, we need to use present method of HarmonyOs.

public final void present(AbilitySlice targetSlice, Intent intent) {
throw new RuntimeException("Stub!");
}

GameAbilitySlice.java

private void goToQuizPage(String topic){
Intent intent = new Intent();
intent.setParam("TEST_KEY", topic);
present(new QuizAbilitySlice(), intent);
}

Here the targetSlice is QuizAbilitySlice.

QuizAbilitySlice.java

String topicName = intent.getStringParam("TEST_KEY");

Here we getting the value from the source Ability Slice.

HarmonyOs User Interface

Layouts

There six layouts available in HarmonyOs:

DirectionalLayout

DependentLayout

StackLayout

TableLayout

PositionLayout

AdaptiveBoxLayout

We will be using DirectionalLayout for our UI. In terms of Android, it is like LinearLayout. It has orientation, weight and many more which we will find in LinearLayout as well.

Text and Button Components

Yes you heard it right. Any widget in HarmonyOs is treated as Component. Here Text as well Button are Component of HarmonyOs. As HarmonyOs uses XML for UI, all those XML properties which we see in Android can be use here. The only difference which we will find here is providing the background colour to Buttons or Layout. In order to provide background colour, we need to create a graphic XML file under the graphic folder of resource.

btn_option.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:shape="rectangle">
<corners
ohos:radius="20"/>
<solid
ohos:color="#2c3e50"/>
</shape>

After that we will use button_option.xml file as background colour for buttons using background_element property.

<Button
ohos:id="$+id:btnD"
ohos:height="80fp"
ohos:width="match_parent"
ohos:margin="10fp"
ohos:text_color="#ecf0f1"
ohos:text_size="30fp"
ohos:text="Gold"
ohos:background_element="$graphic:btn_option"/>

ability_quiz.xml

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="vertical">

<DirectionalLayout
ohos:height="match_parent"
ohos:width="match_parent"
ohos:orientation="vertical"
ohos:weight="0.5"
ohos:alignment="center"
ohos:background_element="$graphic:background_question_area">
<Text
ohos:id="$+id:txtQuestion"
ohos:height="match_content"
ohos:width="match_content"
ohos:text_alignment="center"
ohos:multiple_lines="true"
ohos:margin="20fp"
ohos:text_size="40vp"
ohos:text="Question"
/>

</DirectionalLayout>
<DirectionalLayout
ohos:height="match_parent"
ohos:width="match_parent"
ohos:orientation="vertical"
ohos:alignment="center"
ohos:weight="1">
<Button
ohos:id="$+id:btnA"
ohos:height="80fp"
ohos:width="match_parent"
ohos:margin="10fp"
ohos:text_color="#ecf0f1"
ohos:text_size="30fp"
ohos:text="Gold"
ohos:background_element="$graphic:btn_option"
/>
<Button
ohos:id="$+id:btnB"
ohos:height="80fp"
ohos:width="match_parent"
ohos:margin="10fp"
ohos:text_color="#ecf0f1"
ohos:text_size="30fp"
ohos:text="Gold"
ohos:background_element="$graphic:btn_option"
/>
<Button
ohos:id="$+id:btnC"
ohos:height="80fp"
ohos:width="match_parent"
ohos:margin="10fp"
ohos:text_color="#ecf0f1"
ohos:text_size="30fp"
ohos:text="Gold"
ohos:background_element="$graphic:btn_option"
/>
<Button
ohos:id="$+id:btnD"
ohos:height="80fp"
ohos:width="match_parent"
ohos:margin="10fp"
ohos:text_color="#ecf0f1"
ohos:text_size="30fp"
ohos:text="Gold"
ohos:background_element="$graphic:btn_option"
/>

</DirectionalLayout>

</DirectionalLayout>

HarmonyOs Dialogs

There are five Dialog available in HarmonyOs to use:

DisplayDialog

CommonDialog

BaseDialog

PopupDialog

ListDialog

ToastDialog

We will be using CommonDialog to show default as well as customize dialog in our application. Dialog in HarmonyOs is also known as Component. CommonDialog helps us to provide Button like functionality as we see in Android Dialogs.

Default CommonDialog

private void wrongAnsDialog(){
CommonDialog commonDialog = new CommonDialog(getContext());
commonDialog.setTitleText("WRONG ANSWER");
commonDialog.setSize(1000,300);

commonDialog.setButton(1, "OKAY", new IDialog.ClickedListener() {
@Override
public void onClick(IDialog iDialog, int i) {
commonDialog.hide();
present(new GameAbilitySlice(), new Intent());
}
});
commonDialog.show();
}

Customize CommonDialog

private void correctAnsDialog(){

CommonDialog commonDialog = new CommonDialog(getContext());

DependentLayout dependentLayout = new DependentLayout (getContext());
dependentLayout.setWidth(DependentLayout.LayoutConfig.MATCH_PARENT);
dependentLayout.setHeight(DependentLayout.LayoutConfig.MATCH_PARENT);
dependentLayout.setBackground(new ShapeElement(this,ResourceTable.Graphic_correct_dialog));

Text text = new Text(getContext());
text.setText("CORRECT ANSWER");
text.setTextSize(60);
text.setTextColor(Color.WHITE);

DependentLayout.LayoutConfig textConfig = new DependentLayout.LayoutConfig(DependentLayout.LayoutConfig.MATCH_CONTENT,
DependentLayout.LayoutConfig.MATCH_CONTENT);
textConfig.addRule(DependentLayout.LayoutConfig.CENTER_IN_PARENT);
textConfig.addRule(DependentLayout.LayoutConfig.ALIGN_PARENT_TOP);
text.setLayoutConfig(textConfig);

Button btnNext = new Button(getContext());
btnNext.setText("NEXT QUESTION");
btnNext.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
commonDialog.hide();
questionId++;
questionObj = list.get(questionId);
onNextQuestionAndOption();
resetButtonColors();
enableAllButtons();
}
});
btnNext.setBackground(new ShapeElement(this,ResourceTable.Graphic_btn_next));
btnNext.setTextColor(Color.BLACK);
btnNext.setPadding(20,20,20,20);
btnNext.setTextSize(50);

DependentLayout.LayoutConfig btnConfig = new DependentLayout.LayoutConfig(DependentLayout.LayoutConfig.MATCH_PARENT,
DependentLayout.LayoutConfig.MATCH_CONTENT);
btnConfig.addRule(DependentLayout.LayoutConfig.CENTER_IN_PARENT);
btnConfig.addRule(DependentLayout.LayoutConfig.ALIGN_PARENT_BOTTOM);
btnNext.setLayoutConfig(btnConfig);

dependentLayout.addComponent(text);
dependentLayout.addComponent(btnNext);

commonDialog.setContentCustomComponent(dependentLayout);
commonDialog.setSize(1000,300);
commonDialog.show();
}

Programmatically changing color

In order to change color programmatically to buttons or layout we use ShapeElement class.

// For Buttons …
private void resetButtonColors() {
btnA.setBackground(new ShapeElement(this,ResourceTable.Graphic_btn_option));
btnB.setBackground(new ShapeElement(this,ResourceTable.Graphic_btn_option));
btnC.setBackground(new ShapeElement(this,ResourceTable.Graphic_btn_option));
btnD.setBackground(new ShapeElement(this,ResourceTable.Graphic_btn_option));
}

// For Layouts …

DependentLayout dependentLayout = new DependentLayout (getContext());
dependentLayout.setWidth(DependentLayout.LayoutConfig.MATCH_PARENT);
dependentLayout.setHeight(DependentLayout.LayoutConfig.MATCH_PARENT);
dependentLayout.setBackground(new ShapeElement(this,ResourceTable.Graphic_correct_dialog));

Here ResourceTable is treated same as R in Android.

HarmonyOs Animation

HarmonyOs provides three major classes for animation:

FrameAnimationElement

AnimatorValue

AnimatorProperty

AnimatorGroup.

We will be using AnimatorProperty to do our animation in our splash screen.

Step 1: We need to create AnimatorProperty Object.

AnimatorProperty topAnim = logImg.createAnimatorProperty();
topAnim.alphaFrom((float) 0.1).alpha((float) 1.0).moveFromY(0).moveToY(700).setDuration(2000);

Here logImg is an Image.

Step 2: Create animator_property.xml file in resource/base/animation folder.

<?xml version="1.0" encoding="UTF-8" ?>
<animator xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:duration="2000"/>

Step 3: Parse the animator_property.xml file and use its configuration using AnimatorScatter class.

AnimatorScatter scatter = AnimatorScatter.getInstance(getContext());
Animator animator = scatter.parse(ResourceTable.Animation_topanim);
if (animator instanceof AnimatorProperty) {
topAnim = (AnimatorProperty) animator;
topAnim.setTarget(logImg);
topAnim.moveFromY(0).moveToY(700);
}

logImg.setBindStateChangedListener(new Component.BindStateChangedListener() {
@Override
public void onComponentBoundToWindow(Component component) {
topAnim.start();
}

@Override
public void onComponentUnboundFromWindow(Component component) {
topAnim.stop();
}
});

Step 4: Start Animation

topAnim.start();

Tips & Tricks

Kindly follow my article, my entire article is full of tips & tricks. I have also mentioned Android keywords to make android developers familiar with the terminology of HarmonyOs.

Conclusion

In this article, we learn how to integrate SQLite DB in HarmonyOs application. Now you can use this knowledge and create application such as Library Management, School Management, Games etc.

Feel free to comment, share and like the article. Also you can follow me to get awesome article like this every week.

For more reference

https://developer.harmonyos.com/en/docs/documentation/doc-guides/database-relational-overview-0000000000030046

https://developer.harmonyos.com/en/docs/documentation/doc-guides/ui-java-overview-0000000000500404

Original Source