Integration of Huawei Remote Configuration in Quiz Android app (Kotlin) – Part 3 - Huawei Developers

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Introduction
In this article, we can learn how to fetch the quiz questions and answers to sports from the server using Huawei Remote Configuration. Suppose you want to add any extra questions or delete any questions on the application, this Remote configuration helps to change the content without changing the code. Users can just change the content in the JSON format so that it will display the same in the app. So, I will provide a series of articles on this Quiz App, in upcoming articles.
If you are new to this application, follow my previous articles.
https://forums.developer.huawei.com/forumPortal/en/topic/0202877278014350004
https://forums.developer.huawei.com/forumPortal/en/topic/0201884103719030016?fid=0101187876626530001
What is Huawei Remote Configuration?
Huawei Remote Configuration is a cloud service. It changes the behavior and appearance of your app without publishing an app update on App Gallery for all active users. Basically, Remote Configuration allows you to maintain parameters on the cloud, based on these parameters we control the behavior and appearance of your app. In the festival scenario, we can define parameters with the text, color, and images for a theme which can be fetched using Remote Configuration.
Configuration in AGC
1. Sign in to AppGallery Connect and select My apps.
2. Select the app in which you want to integrate Huawei Remote configuration Service.
3. Navigate to Grow > Remote configuration and click Use now.
4. Click New parameter.
5. Enter the Parameter name, json format content in Default value, Description, and then click Save.
Note: Once you add or edit the JSON format content in Default value, it will take 12 hours to return in the app.
Requirements
1. Any operating system (MacOS, Linux, and Windows).
2. Must have a Huawei phone with HMS 4.0.0.300 or later.
3. Must have a laptop or desktop with Android Studio, Jdk 1.8, SDK platform 26 and Gradle 4.6 and above installed.
4. Minimum API Level 24 is required.
5. Required EMUI 9.0.0 and later version devices.
How to integrate HMS Dependencies
1. First register as Huawei developer and complete identity verification on the Huawei developers website, refer to register a Huawei ID.
2. Create a project in android studio, refer Creating an Android Studio Project.
3. Generate a SHA-256 certificate fingerprint.
4. To generate SHA-256 certificate fingerprint. On right-upper corner of android project click Gradle, choose Project Name > Tasks > android, and then click signingReport, as follows.
Note: Project Name depends on the user created name.
5. Create an App in AppGallery Connect.
6. Download the agconnect-services.json file from App information, copy and paste in android Project under app directory, as follows.
7. Enter SHA-256 certificate fingerprint and click Save button, as follows.
Note: Above steps from Step 1 to 7 is common for all Huawei Kits.
8. Click Manage APIs tab and enable Remote Configuration and HUAWEI Analytics.
9. Add the below maven URL in build.gradle(Project) file under the repositories of buildscript, dependencies and allprojects, refer Add Configuration.
Java:
maven { url 'http://developer.huawei.com/repo/' }
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
10. Add the below plugin and dependencies in build.gradle(Module) file.
Java:
apply plugin: id 'com.huawei.agconnect'
// Huawei AGC
implementation 'com.huawei.agconnect:agconnect-core:1.6.0.300'
// Huawei Analytics Kit
implementation 'com.huawei.hms:hianalytics:6.4.0.300'
// Remote Config
implementation 'com.huawei.agconnect:agconnect-remoteconfig:1.6.5.300'
11. Now Sync the gradle.
12. Add the required permission to the AndroidManifest.xml file.
Java:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
Let us move to development
I have created a project on Android studio with empty activity let us start coding.
In the SportsActivity.kt we can find the business logic for android questions.
Java:
class SportsActivity : AppCompatActivity(), View.OnClickListener {
private var pCurrentPosition: Int = 1
private var pQuestionsList: ArrayList<SportQuestions>? = null
private var pSelectedOptionPosition: Int = 0
private var pCorrectAnswers: Int = 0
private var layout: LinearLayout? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sports)
layout = findViewById(R.id.Layout_container)
layout!!.visibility = View.GONE
txt_option1_spt.setOnClickListener(this)
txt_option2_spt.setOnClickListener(this)
txt_option3_spt.setOnClickListener(this)
txt_option4_spt.setOnClickListener(this)
btn_spt_submit.setOnClickListener(this)
pQuestionsList = ArrayList<SportQuestions>()
// Remote Configuration Fetching
val config : AGConnectConfig= AGConnectConfig.getInstance()
config.fetch(0).addOnSuccessListener {
config.apply(it)
val value = config.getValueAsString("remoteconfig_ques")
parseQuestion(value)
setQuestion()
}.addOnFailureListener {
}
}
// Parse the questions in array format
private fun parseQuestion(value : String) {
val jsonObject : JSONObject = JSONObject(value)
val questions : JSONArray = jsonObject.getJSONArray("questions")
for (i in 0 until questions.length()) {
val q: JSONObject = questions.getJSONObject(i)
val question = q.getString("question")
val option1 = q.getString("option1")
val option2 = q.getString("option2")
val option3 = q.getString("option3")
val option4 = q.getString("option4")
val answer = q.getString("answer")
val id = q.getString("id")
val sportQuestions = SportQuestions(id.toInt(),question, option1,option2,option3,option4,answer.last().digitToInt() )
pQuestionsList?.add(sportQuestions)
layout!!.visibility = View.VISIBLE
}
}
private fun setQuestion() {
val question = pQuestionsList!![pCurrentPosition -1]
defaultOptionsView()
if(pCurrentPosition == pQuestionsList!!.size){
btn_spt_submit.text = "FINISH"
} else {
btn_spt_submit.text = "SUBMIT"
}
progressBar_spt.progress = pCurrentPosition
txt_progress_spt.text = "$pCurrentPosition" + "/" + progressBar_spt.max
txt_sptquestion.text = question!!.spt_questions
txt_option1_spt.text = question.spt_option1
txt_option2_spt.text = question.spt_option2
txt_option3_spt.text = question.spt_option3
txt_option4_spt.text = question.spt_option4
}
private fun defaultOptionsView() {
val options = ArrayList<TextView>()
options.add(0, txt_option1_spt)
options.add(1, txt_option2_spt)
options.add(2, txt_option3_spt)
options.add(3, txt_option4_spt)
for(option in options){
option.setTextColor(Color.parseColor("#7A8089"))
option.typeface = Typeface.DEFAULT
option.background = ContextCompat.getDrawable(this, R.drawable.border_bg)
}
}
override fun onClick(v: View?) {
when(v?.id){
R.id.txt_option1_spt -> {
selectedOptionView(txt_option1_spt, 1)
}
R.id.txt_option2_spt -> {
selectedOptionView(txt_option2_spt, 2)
}
R.id.txt_option3_spt -> {
selectedOptionView(txt_option3_spt, 3)
}
R.id.txt_option4_spt -> {
selectedOptionView(txt_option4_spt, 4)
}
R.id.btn_spt_submit -> {
if(pSelectedOptionPosition == 0){
pCurrentPosition++
when{
pCurrentPosition <= pQuestionsList!!.size -> {
setQuestion()
} else -> {
val intent = Intent(this, SportsResultActivity::class.java)
intent.putExtra(SportConstants.TOTAL_SPT_QUESTIONS, pCorrectAnswers)
intent.putExtra(SportConstants.CORRECT_SPT_ANSWERS, pQuestionsList!!.size)
startActivity(intent)
}
}
} else {
val question = pQuestionsList?.get(pCurrentPosition -1)
if(question!!.spt_correctAnswer != pSelectedOptionPosition){
answerView(pSelectedOptionPosition, R.drawable.wrong_bg)
} else {
pCorrectAnswers ++
}
answerView(question!!.spt_correctAnswer, R.drawable.correct_bg)
if(pCurrentPosition == pQuestionsList!!.size){
btn_spt_submit.text = "FINISH"
} else {
btn_spt_submit.text = "Next Question"
}
pSelectedOptionPosition = 0
}
}
}
}
private fun answerView(answer:Int, drawableView:Int){
when(answer) {
1 -> {
txt_option1_spt.background = ContextCompat.getDrawable(this, drawableView)
}
2 -> {
txt_option2_spt.background = ContextCompat.getDrawable(this, drawableView)
}
3 -> {
txt_option3_spt.background = ContextCompat.getDrawable(this, drawableView)
}
4 -> {
txt_option4_spt.background = ContextCompat.getDrawable(this, drawableView)
}
}
}
private fun selectedOptionView(tv: TextView, selectedOptionNum: Int){
defaultOptionsView()
pSelectedOptionPosition = selectedOptionNum
tv.setTextColor(Color.parseColor("#363A43"))
tv.setTypeface(tv.typeface, Typeface.BOLD)
tv.background = ContextCompat.getDrawable(this, R.drawable.select_bg)
}
}
In the SportsResultActivity.kt we can find the business logic for android result view.
Java:
class SportsResultActivity : AppCompatActivity() {
val TOTAL_SPT_QUESTIONS: String = "total_questions"
val CORRECT_SPT_ANSWERS: String = "correct_answers"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sports_result)
val totalQuestions = intent.getIntExtra(TOTAL_SPT_QUESTIONS, 0)
val correctAnswers = intent.getIntExtra(CORRECT_SPT_ANSWERS, 0)
txt_sptscore.text = "Your Score is $totalQuestions out of $correctAnswers"
btn_sptfinish.setOnClickListener {
startActivity(Intent(this, Home::class.java))
}
}
}
Create a data class SportQuestions.kt to access variables.
Java:
data class SportQuestions (
val id:Int,
val spt_questions:String,
val spt_option1:String,
val spt_option2:String,
val spt_option3:String,
val spt_option4:String,
val spt_correctAnswer:Int
)
In the activity_sports.xml we can create the UI screen for questions.
XML:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
tools:context=".sports.SportsActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/Layout_container"
android:visibility="gone"
android:orientation="vertical"
android:padding="16dp"
android:gravity="center" >
<TextView
android:id="@+id/txt_sptquestion"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:gravity="center"
android:text="Which is the national sport of Latvia?"
android:textColor="#363A43"
android:textSize="18sp">
</TextView>
<LinearLayout
android:id="@+id/progress_details_spt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginTop="16dp" >
<ProgressBar
android:id="@+id/progressBar_spt"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:minHeight="50dp"
android:progress="0"
android:indeterminate="false"
android:max="10">
</ProgressBar>
<TextView
android:id="@+id/txt_progress_spt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="15dp"
android:gravity="center"
android:textColorHint="#7A8089"
android:textSize="14sp"
tools:text="1/10">
</TextView>
</LinearLayout>
<TextView
android:id="@+id/txt_option1_spt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/border_bg"
android:padding="15dp"
android:gravity="center"
android:textColor="#7A8089"
android:textSize="18sp"
tools:text="Ice Hockey">
</TextView>
<TextView
android:id="@+id/txt_option2_spt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/border_bg"
android:padding="15dp"
android:gravity="center"
android:textColor="#7A8089"
android:textSize="18sp"
tools:text="Basketball">
</TextView>
<TextView
android:id="@+id/txt_option3_spt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/border_bg"
android:padding="15dp"
android:gravity="center"
android:textColor="#7A8089"
android:textSize="18sp"
tools:text="Football">
</TextView>
<TextView
android:id="@+id/txt_option4_spt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/border_bg"
android:padding="15dp"
android:gravity="center"
android:textColor="#7A8089"
android:textSize="18sp"
tools:text="Volleyball">
</TextView>
<Button
android:id="@+id/btn_spt_submit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@color/design_default_color_primary"
android:text="Submit"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
</ScrollView>
In the activity_sports_result.xml we can create the UI screen for result.
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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="@drawable/sportsresult_bg"
android:padding="20dp"
tools:context=".sports.SportsResultActivity">
<TextView
android:id="@+id/txt_sptresult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="25dp"
android:text="Result"
android:textColor="@android:color/white"
android:textStyle="bold"
android:textSize="22sp">
</TextView>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:src="@drawable/women_spray"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Wow Completed Sports Quiz!!"
android:textColor="@android:color/white"
android:textStyle="bold"
android:textSize="21sp">
</TextView>
<TextView
android:id="@+id/txt_sptscore"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="Your Score is 4 out of 10"
android:textColor="@color/design_default_color_error"
android:textSize="20sp">
</TextView>
<Button
android:id="@+id/btn_sptfinish"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:background="@android:color/white"
android:text="Finish"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
Demo
Tips and Tricks
1. Make sure you are already registered as Huawei developer.
2. Set minSDK version to 24 or later, otherwise you will get AndriodManifest merge issue.
3. Make sure you have added the agconnect-services.json file to app folder.
4. Make sure you have added SHA-256 fingerprint without fail.
5. Make sure all the dependencies are added properly.
Conclusion
In this article, we have learned how to fetch the quiz questions and answers to sports from the server using Huawei Remote Configuration. Suppose you want to add any extra questions or delete any questions on the application, this Remote configuration helps to change the content without changing the code. Users can just change the content in the JSON format so that it will display the same in the app. So, I will provide a series of articles on this Quiz App, in upcoming articles.
I hope you have read this article. If you found it helpful, please provide likes and comments.
Reference
Remote Configuration - Document
Remote Configuration - Training Video

Related

How to Use Game Service with MVVM / Part 1 — Login

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Hello everyone,
In this article, I will give information about Game Service, which offered by Huawei to developers, and explain how to use it in the your mobile game app with the MVVM structure.
What Is Game Service?
HMS Game Service is a kind of Huawei service offered to mobile developers that meets all the needs of a mobile game application. Owing to Game Service, you can easily create a leaderboard in the game, create events, prepare achievements and let the users for save their games. Since you do all these operations through a ready-made service, you can create your game project reliably with a short and organized code structure.
With HUAWEI Game Service, you will have access to a range of development capabilities, to help you develop your games more efficiently:
HUAWEI ID sign-in
Game addiction prevention
Floating window
Achievements
Events
Leaderboards
Saved games
Player statistics
Access to basic game information
Requirements
Android Studio 3.X or later
JDK 1.8 or later
SDK:
— minSdkVersion: 17
— targetSdkVersion: 29
— compileSdkVersion: 29
Test device:
Development Process
1. Integration
First, a developer account must be created and HMS Core must be integrated into the project to use HMS. You can access the article about that steps from Huawei offical pages.
2. Adding Dependencies
After HMS Core is integrated into the project and the Game Service is activated through the console, the required library should added to the build.gradle file in the app directory as follows.
XML:
dependencies {
implementation 'com.huawei.hms:base: 5.0.5.300'
implementation 'com.huawei.hms:hwid:4.0.1.300'
implementation 'com.huawei.hms:iap:5.0.1.300'
implementation 'com.huawei.hms:game: 5.0.4.302'
}
3. Create Application Class
An Application class is required to launch the Game Service when starting the application. Game Service is launched in this class and it is provided to start with the project. After the BaseApplication class is created, it must be defined in the Manifest file.
Java:
class BaseApplication : Application(){
companion object{
lateinit var instance: BaseApplication
private set
}
override fun onCreate() {
super.onCreate()
instance = this
HuaweiMobileServicesUtil.setApplication(this)
HwAds.init(this)
}
}
4. Create Login Page Design
After all of the permissions and libraries have been added to the project, you can start to coding with sign-in for develop a game. For this, I used Huawei Auth Service. Thanks to Auth Service, you can see all of the users on the console. Also Auth Service provides many kind of login method. (With Facebook, Twitter, Google, Email, Phone Number or Huawei ID) I will share a general screen design. And I will give an example of login with Huawei ID.
XML:
<androidx.constraintlayout.motion.widget.MotionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
app:layoutDescription="@xml/motion_scene_splash"
android:id="@+id/id_09"
android:layout_height="match_parent">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="@drawable/background"
android:alpha="0.7"
android:id="@+id/id_11"/>
<ImageView
android:id="@+id/imgView_logo"
android:layout_width="130dp"
android:layout_height="130dp"
android:layout_marginTop="80dp"
android:scaleType="centerInside"
android:src="@drawable/vs_logo"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/imgView_logo_rays"
android:layout_width="130dp"
android:layout_height="130dp"
android:layout_marginTop="80dp"
android:scaleType="centerInside"
android:src="@drawable/vs_logo"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/imgView_cloudLeft"
android:layout_width="130dp"
android:layout_height="130dp"
android:layout_marginTop="16dp"
android:scaleType="centerInside"
android:src="@drawable/cloud"
android:translationX="-20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="#9E9E9E" />
<ImageView
android:id="@+id/imgView_cloudRight"
android:layout_width="130dp"
android:layout_height="130dp"
android:layout_marginTop="120dp"
android:scaleType="centerInside"
android:src="@drawable/cloud"
android:translationX="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="#607D8B" />
<LinearLayout
android:id="@+id/linlay_inputs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:alpha="1"
android:layout_marginLeft="30dp"
android:layout_marginEnd="30dp"
android:layout_marginRight="30dp"
android:gravity="center"
android:layout_marginTop="10dp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imgView_cloudRight">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/muli_regular"
android:text="Welcome Back"
android:textColor="#000000"
android:textSize="20sp"
android:id="@+id/id_12" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/muli_regular"
android:text="Sign in to continue"
android:textColor="#000000"
android:textSize="14sp"
android:id="@+id/id_13" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:background="@drawable/et_background"
android:drawableStart="@drawable/ic_baseline_email_24"
android:drawableLeft="@drawable/ic_baseline_email_24"
android:drawablePadding="16dp"
android:hint="Email"
android:inputType="textEmailAddress"
android:padding="16dp"
android:textSize="14sp"
android:textColor="#000000"
android:fontFamily="@font/muli_regular"
android:id="@+id/id_14"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:background="@drawable/et_background"
android:drawableStart="@drawable/ic_baseline_lock_24"
android:drawableLeft="@drawable/ic_baseline_lock_24"
android:drawableEnd="@drawable/ic_baseline_visibility_24"
android:drawableRight="@drawable/ic_baseline_visibility_24"
android:drawablePadding="16dp"
android:hint="Password"
android:inputType="textPassword"
android:padding="16dp"
android:textSize="14sp"
android:textColor="#000000"
android:fontFamily="@font/muli_regular"
android:id="@+id/id_15"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:background="@drawable/button_one"
android:text="@string/signInButton"
android:textAllCaps="false"
android:fontFamily="@font/muli_regular"
android:textColor="#7E675E"
android:id="@+id/id_16"/>
</LinearLayout>
<TextView
android:id="@+id/tv_forgotPassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginEnd="30dp"
android:alpha="1"
android:layout_marginRight="30dp"
android:text="Forgot Password?"
android:textColor="#7E675E"
android:textSize="13sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/linlay_inputs" />
<ImageView
android:id="@+id/safads"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:src="@drawable/color_logo"
app:tint="#9E9E9E"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/linlay_inputs"
android:visibility="invisible"/>
</androidx.constraintlayout.motion.widget.MotionLayout>
Secondly, we have to logout. The purpose of this is to terminate if there is a session in the application that was open before. After logout, we have to create login method. And firstly, call the logout method in there. Finally we should add startActivityForResult method and override it on the View class.
LoginViewModel class should be as follows.
Java:
class LoginViewModel(private val context: Context): ViewModel(){
private lateinit var mClient: HuaweiIdAuthService
fun login(fragment: Fragment){
logout()
val huaweiIdAuthParamsHelper =HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM)
val scopeList: MutableList<Scope> = ArrayList()
scopeList.add(Scope(HwIDConstant.SCOPE.ACCOUNT_BASEPROFILE))
huaweiIdAuthParamsHelper.setScopeList(scopeList)
val authParams = huaweiIdAuthParamsHelper.setAccessToken().createParams()
mClient = HuaweiIdAuthManager.getService(context, authParams)
fragment.startActivityForResult(mClient.signInIntent, 1002)
}
fun logout(){
Log.i(Constants.LOGIN_VIEWMODEL_TAG, "In LogOut Fun.")
val auth = AGConnectAuth.getInstance()
auth.signOut()
}
}
5. Create LoginViewModel Class
LoginViewModel class will receive data from View class, processes data and send again to View class. So, all of the login operations will be done in this class.
Firstly, create a client from HuaweiIdAuthService object.
Java:
private lateinit var mClient: HuaweiIdAuthService
6. Create LoginViewModelFactory Class
Create a view model factory class and set context as parameter. This class should be return ViewModel class.
Java:
class LoginViewModelFactory(private val context: Context): ViewModelProvider.NewInstanceFactory(){
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return LoginViewModel(context) as T
}
}
7. Create LoginFragment
Firstly, ViewModel dependencies should be added on Xml file. We will use it as binding object. For this, open again your Xml file and add variable name as “viewmodel” and add type as your ViewModel class directory like that.
XML:
<data>
<variable
name="viewmodel"
type="com.xxx.xxx.viewmodel.LoginViewModel"/>
</data>
Turn back LoginFragment and add factory class, viewmodel class and binding.
Java:
private lateinit var binding: FragmentLoginBinding
private lateinit var viewModel: LoginViewModel
private lateinit var viewModelFactory: LoginViewModelFactory
Secondly, define these objects on the onCreateView method.
Java:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.activity_splash_login, container,false) as ActivitySplashLoginBinding
viewModelFactory =LoginViewModelFactory(requireContext() )
viewModel = ViewModelProviders.of(this, viewModelFactory).get(LoginViewModel::class.java)
return binding.root
}
Create a click listener for login, and call the login method from ViewModel class.
Java:
var gameLoginButton = binding.id16.findViewById<View>(R.id.id_16)
gameLoginButton.setOnClickListener {
showProgressDialog()
viewModel.login(this)
}
Finally, create onActivityResult method and check login results. If login is successful, you can see some user informations in there. (User name, ID, Country, Age etc.) Auth Service provide to you so many user info. You can use it all of the app.
Java:
override fun onActivityResult(
requestCode: Int,
resultCode: Int,
@Nullable data: Intent?
) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 1002) {
val signInHuaweiIdTask = HuaweiIdAuthManager.parseAuthResultFromIntent(data)
if (signInHuaweiIdTask.isSuccessful) {
val huaweiAccount = signInHuaweiIdTask.result
val accessToken = huaweiAccount.accessToken
Log.w(Constants.LOGIN_FRAGMENT_TAG, "accessToken: $accessToken")
val credential = HwIdAuthProvider.credentialWithToken(accessToken)
val provider_now = credential.provider
Log.w(Constants.LOGIN_FRAGMENT_TAG, "provider_now: $provider_now")
AGConnectAuth.getInstance().signIn(credential)
.addOnSuccessListener { signInResult ->
val user = AGConnectAuth.getInstance().currentUser
Log.w(Constants.LOGIN_FRAGMENT_TAG, "Login Success. User Display Name : " + user.displayName)
userName = user.displayName
//Start another fragment here.
(activity as MainActivity?)!!.setSelectedTab(Constants.TAB_LOGIN,Constants.TAB_HOME,false)
dismisProgressDialog()
}.addOnFailureListener { e: Exception ->
Toast.makeText(context, R.string.authenticationError, Toast.LENGTH_SHORT).show()
Log.w(Constants.LOGIN_FRAGMENT_TAG, "sign in for agc failed: " + e.message)
dismisProgressDialog()
}
} else {
Toast.makeText(context, R.string.sıgnInError, Toast.LENGTH_SHORT).show()
Log.e(Constants.LOGIN_FRAGMENT_TAG,"sign in failed : " + (signInHuaweiIdTask.exception as ApiException).statusCode)
dismisProgressDialog()
}
}
}
Result
Thanks to this article, you can create login operations on your game app. We’ve used Auth Service. Because Auth Service provides so many user info to developers. And you can all of the users on the developer console.
In the next article, I will explain Achievements and give an example. Please follow second article for develop your game app with clean architecture.
Thanks alot

Manage the Budget using Room Database in Money Management Android app (Kotlin) – Part 3

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Introduction
In this article, we can learn how to manage your money using this Money Management app. User can add Income and Expenses in this app, so the data will be saved in room database, it can access in offline also. User can easily track their daily spending's and can take the preventive actions on the unnecessary expenses, so that they can save money and can invest in profitable return ways. In this app, user can add, update, delete and fetch operations.
So, I will provide the series of articles on this Money Management App, in upcoming articles I will integrate other Huawei Kits.
If you are new to this application, follow my previous articles.
Beginner: Find the introduction Sliders and Huawei Account Kit Integration in Money Management Android app (Kotlin) - Part 1
Beginner: Integration of Huawei Ads Kit and Analytics Kit in Money Management Android app (Kotlin) – Part 2
Components of Room DB
1. Entity
2. Dao
3. Database
1. Entity
Represents a table within the database. Room creates a table for each class that has @entity annotation, the fields in the class correspond to columns in the table. Therefore, the entity classes tend to be small model classes that does not contain any logic.
2. Dao
DAOs(Data Access Objects) are responsible for defining the methods that access the database. In the initial SQLite, we use the Cursor objects. With Room, we do not need all the Cursor related code and can simply define our queries using annotations in the Dao class.
3. Database
Contains the database holder and serves as the main access point for the underlying connection to your app's persisted, relational data.
To create a database, we need to define an abstract class that extends RoomDatabase. This class is annotated with @database, lists the entities contained in the database, and the DAOs which access them.
Requirements
1. Any operating system (MacOS, Linux and Windows).
2. Must have a Huawei phone with HMS 4.0.0.300 or later.
3. Must have a laptop or desktop with Android Studio, Jdk 1.8, SDK platform 26 and Gradle 4.6 and above installed.
4. Minimum API Level 24 is required.
5. Required EMUI 9.0.0 and later version devices.
How to integrate HMS Dependencies
1. First register as Huawei developer and complete identity verification in Huawei developers website, refer to register a Huawei ID.
2. Create a project in android studio, refer Creating an Android Studio Project.
3. Generate a SHA-256 certificate fingerprint.
4. To generate SHA-256 certificate fingerprint. On right-upper corner of android project click Gradle, choose Project Name > Tasks > android, and then click signingReport, as follows.
Note: Project Name depends on the user created name.
5. Create an App in AppGallery Connect.
6. Download the agconnect-services.json file from App information, copy and paste in android Project under app directory, as follows.
7. Enter SHA-256 certificate fingerprint and click Save button, as follows.
Note: Above steps from Step 1 to 7 is common for all Huawei Kits.
8. Add the below maven URL in build.gradle(Project) file under the repositories of buildscript, dependencies and allprojects, refer Add Configuration.
Java:
maven { url 'http://developer.huawei.com/repo/' }
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
9. Add the below plugin and dependencies in build.gradle(Module) file.
Java:
apply plugin: id 'com.huawei.agconnect'
apply plugin: id 'kotlin-kapt'
// Huawei AGC
implementation 'com.huawei.agconnect:agconnect-core:1.6.0.300'
// Room Database
implementation "androidx.room:room-runtime:2.4.2"
kapt "androidx.room:room-compiler:2.4.2"
implementation "androidx.room:room-ktx:2.4.2"
androidTestImplementation "androidx.room:room-testing:2.4.2"
// Lifecycle components
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1"
// Recyclerview
implementation 'androidx.recyclerview:recyclerview:1.2.1'
10. Now Sync the gradle.
Let us move to development
I have created a project on Android studio with empty activity let us start coding.
Create a Transaction.kt class annotated with @entity to create a table for each class.
Java:
@Entity(tableName = "transactions")
data class Transaction(
@PrimaryKey(autoGenerate = true)
val id: Int,
val label: String,
val amount: Double,
val description: String): Serializable{}
Create a TransactionDao o.kt interface class annotated with @dao and responsible for defining the methods that access the database.
Java:
@Dao
interface TransactionDao {
@Query("SELECT * from transactions")
fun getAll(): List<Transaction>
@Insert
fun insertAll(vararg transaction: Transaction)
@Delete
fun delete(vararg transaction: Transaction)
@Update
fun update(vararg transaction: Transaction)
}
Create a AppDatabase.kt abstract class that extends RoomDatabase annotated with @database to lists the entities contained in the database, and the DAOs which access them.
Java:
@Database(entities = [Transaction::class], version = 2)
abstract class AppDatabase : RoomDatabase() {
abstract fun transactionDao(): TransactionDao
}
In the TransactionActivity.kt activity to find the business logic for entire dashboard.
Java:
class TransactionActivity : AppCompatActivity() {
private lateinit var deletedTransaction: Transaction
private lateinit var oldtransactions: List<Transaction>
private lateinit var transactions: List<Transaction>
private lateinit var transactionAdapter: TransactionAdapter
private lateinit var linearLayoutManager: LinearLayoutManager
private lateinit var db: AppDatabase
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_transcation)
transactions = arrayListOf()
transactionAdapter = TransactionAdapter(transactions)
linearLayoutManager = LinearLayoutManager(this)
trans_recycler_view.apply {
adapter = transactionAdapter
layoutManager = linearLayoutManager
}
// Swipe to remove
val itemTouchHelper = object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT){
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
deleteTransaction(transactions[viewHolder.adapterPosition])
}
}
val swipeHelper = ItemTouchHelper(itemTouchHelper)
swipeHelper.attachToRecyclerView(trans_recycler_view)
btn_float.setOnClickListener {
val intent = Intent(this, AddTransactionActivity::class.java)
startActivity(intent)
}
// Room database
db = Room.databaseBuilder(this,AppDatabase::class.java,"transactions").build()
}
@SuppressLint("SetTextI18n")
private fun updateAmount(){
val totalAmount: Double = transactions.map {it.amount}.sum()
val budgetAmount: Double = transactions.filter {it.amount > 0}.map {it.amount}.sum()
val expenseAmount: Double = totalAmount - budgetAmount
balance.text = "RS %.2f".format(totalAmount)
budget.text = "RS %.2f".format(budgetAmount)
expense.text = "RS %.2f".format(expenseAmount)
}
// Fetch Transactions form Room Database
private fun fetchAll(){
GlobalScope.launch {
transactions = db.transactionDao().getAll()
runOnUiThread {
updateAmount()
transactionAdapter.setData(transactions)
}
}
}
private fun deleteTransaction(transaction: Transaction){
deletedTransaction = transaction
oldtransactions = transactions
GlobalScope.launch {
db.transactionDao().delete(transaction)
transactions = transactions.filter {it.id != transaction.id}
runOnUiThread {
updateAmount()
transactionAdapter.setData(transactions)
}
}
Toast.makeText(this, "Item Deleted", Toast.LENGTH_SHORT).show()
}
override fun onResume() {
super.onResume()
fetchAll()
}
}
Create a TransactionAdapter.kt adapter class to hold the list.
Java:
class TransactionAdapter(private var transactions: List<Transaction>):
RecyclerView.Adapter<TransactionAdapter.TransactionViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransactionViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.transcation_list, parent, false)
return TransactionViewHolder(itemView)
}
override fun onBindViewHolder(holder: TransactionViewHolder, position: Int) {
val transaction: Transaction = transactions[position]
val context: Context = holder.amount.context
if(transaction.amount >= 0){
holder.amount.text = " RS %.2f".format(transaction.amount)
holder.amount.setTextColor(ContextCompat.getColor(context,R.color.Green))
} else {
holder.amount.text = " RS %.2f".format(transaction.amount)
holder.amount.setTextColor(ContextCompat.getColor(context,R.color.Red))
}
holder.label.text = transaction.label
holder.itemView.setOnClickListener {
val intent = Intent(context, DetailedActivity::class.java)
intent.putExtra("transaction", transaction)
context.startActivity(intent)
}
}
override fun getItemCount(): Int {
return transactions.size
}
inner class TransactionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val label: TextView = itemView.findViewById(R.id.txt_label)
val amount: TextView = itemView.findViewById(R.id.txt_amount)
}
fun setData(transactions: List<Transaction>){
this.transactions = transactions
notifyDataSetChanged()
}
}
In the AddTransactionActivity.kt activity to find the business logic to add items.
Java:
class AddTransactionActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_add_transaction)
btn_add.setOnClickListener {
val label = edt_label.text.toString()
val amount = edt_amount.text.toString().toDoubleOrNull()
val description = edt_desc.text.toString()
if(label.isBlank()) {
Toast.makeText(this, "Enter the label", Toast.LENGTH_SHORT).show()
}
else if(amount == null) {
Toast.makeText(this, "Enter the valid amount", Toast.LENGTH_SHORT).show()
}
else {
val transaction = Transaction(0, label, amount, description)
insert(transaction)
Toast.makeText(this, "Saved Content", Toast.LENGTH_SHORT).show()
}
}
}
private fun insert(transaction: Transaction) {
val db: AppDatabase = Room.databaseBuilder(this,AppDatabase::class.java,"transactions").build()
GlobalScope.launch {
db.transactionDao().insertAll(transaction)
finish()
}
}
}
In the DetailedActivity.kt activity to find the business logic for updating the items.
Java:
class DetailedActivity : AppCompatActivity() {
private lateinit var transaction: Transaction
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detailed)
transaction = intent.getSerializableExtra("transaction") as Transaction
update_label.setText(transaction.label)
update_amount.setText(transaction.amount.toString())
btn_update.setOnClickListener {
val label = update_label.text.toString()
val amount = update_amount.text.toString().toDoubleOrNull()
val description = update_desc.text.toString()
if(label.isBlank()) {
Toast.makeText(this, "Enter the label", Toast.LENGTH_SHORT).show()
}
else if(amount == null) {
Toast.makeText(this, "Enter the valid amount", Toast.LENGTH_SHORT).show()
}
else {
val transaction = Transaction(transaction.id, label, amount, description)
update(transaction)
Toast.makeText(this, "Saved Content", Toast.LENGTH_SHORT).show()
}
}
}
private fun update(transaction: Transaction) {
val db: AppDatabase = Room.databaseBuilder(this,AppDatabase::class.java,"transactions").build()
GlobalScope.launch {
db.transactionDao().update(transaction)
finish()
}
}
}
In the activity_transcation.xml we can create the UI screen for Dashboard.
XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".room.TransactionActivity">
<LinearLayout
android:id="@+id/balance_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:layout_marginStart="10dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Total Balance:"
android:textAllCaps="false"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="@+id/balance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RS.xx"
android:textColor="@color/black"
android:textSize="20sp"
android:textStyle="bold" />
</LinearLayout>
<com.google.android.material.card.MaterialCardView
android:id="@+id/cardview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
app:cardCornerRadius="12dp"
android:layout_below="@+id/balance_layout">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="0.5"
android:layout_gravity="center">
<TextView
android:id="@+id/budget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RS.xx"
android:textAllCaps="false"
android:textSize="24sp"
android:textColor="@color/Green"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Budget "
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center"
android:layout_weight="0.5">
<TextView
android:id="@+id/expense"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RS.xx"
android:textColor="@color/Red"
android:textAllCaps="false"
android:textSize="24sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Expense "
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Transcations"
android:textAllCaps="false"
android:textSize="18sp"
android:layout_marginTop="14dp"
android:layout_marginStart="10dp"
android:layout_below="@+id/cardview"
android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/trans_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/title"
android:layout_marginTop="10dp"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/btn_float"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
android:layout_marginBottom="10dp"
android:backgroundTint="@color/Red"
android:clickable="true"
android:contentDescription="TODO"
app:borderWidth="0dp"
app:srcCompat="@android:drawable/ic_input_add" />
</RelativeLayout>
In the activity_add_transaction.xml we can create the UI screen for adding items.
XML:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".room.AddTransactionActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:ignore="MissingConstraints">
<EditText
android:id="@+id/edt_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:hint="Label "
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/edt_amount"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Amount: "
android:inputType="numberSigned"
app:layout_constraintTop_toBottomOf="@id/edt_label" />
<EditText
android:id="@+id/edt_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Description: "
app:layout_constraintTop_toBottomOf="@id/edt_amount" />
<Button
android:id="@+id/btn_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:textSize="18sp"
android:layout_gravity="center"
android:text="Add"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/edt_desc" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
In the activity_detailed.xml we can create the UI screen for updating items.
XML:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".room.DetailedActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:ignore="MissingConstraints">
<EditText
android:id="@+id/update_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:hint="Label "
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/update_amount"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Amount: "
android:inputType="numberSigned"
app:layout_constraintTop_toBottomOf="@id/edt_label" />
<EditText
android:id="@+id/update_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Description: "
app:layout_constraintTop_toBottomOf="@id/edt_amount" />
<Button
android:id="@+id/btn_update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:textSize="18sp"
android:layout_gravity="center"
android:text="Update"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/edt_desc" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
In the transcation_list.xml we can create the UI screen for customized items.
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="40dp"
android:layout_gravity="center_vertical">
<TextView
android:id="@+id/txt_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Food"
android:textAllCaps="false"
android:layout_marginStart="6dp"
android:textSize="20sp"
android:layout_weight="1"/>
<TextView
android:id="@+id/txt_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RS.12"
android:layout_marginEnd="12dp"
android:textSize="20sp"/>
</LinearLayout>
Demo
Tips and Tricks
1. Make sure you are already registered as Huawei developer.
2. Set minSDK version to 24 or later, otherwise you will get AndriodManifest merge issue.
3. Make sure you have added the agconnect-services.json file to app folder.
4. Make sure you have added SHA-256 fingerprint without fail.
5. Make sure all the dependencies are added properly.
Conclusion
In this article, we have learned the integration of Room database.
We, have learnt about the room database and its components such as DAO, Entity and Database. How to create, read, update and delete the content in room database and which helps the user to access the data when they are in offline.
I hope you have read this article. If you found it is helpful, please provide likes and comments.
Reference
Room Database
Find the Original document - https://forums.developer.huawei.com/forumPortal/en/topic/0202860048259200218?fid=0101187876626530001

Find the basic Android and HMS questions in Quiz Android app (Kotlin) – Part 2

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Introduction
In this article, we can learn about the basic questions on Android and HMS of Quiz application. The purpose of conducting quizzes within the business is more fun and educative to understand how the business is running straight away, test the knowledge of the user and helps to form a businessman or woman a far better person in terms of the business process. So, I will provide the series of articles on this Quiz App, in upcoming articles.
If you are new to this application, follow my previous article.
https://forums.developer.huawei.com/forumPortal/en/topic/0202877278014350004
Requirements
1. Any operating system (MacOS, Linux and Windows).
2. Must have a Huawei phone with HMS 4.0.0.300 or later.
3. Must have a laptop or desktop with Android Studio, Jdk 1.8, SDK platform 26 and Gradle 4.6 and above installed.
4. Minimum API Level 24 is required.
5. Required EMUI 9.0.0 and later version devices.
How to integrate HMS Dependencies
1. First register as Huawei developer and complete identity verification in Huawei developers website, refer to register a Huawei ID.
2. Create a project in android studio, refer Creating an Android Studio Project.
3. Generate a SHA-256 certificate fingerprint.
4. To generate SHA-256 certificate fingerprint. On right-upper corner of android project click Gradle, choose Project Name > Tasks > android, and then click signingReport, as follows.
Note: Project Name depends on the user created name.
5. Create an App in AppGallery Connect.
6. Download the agconnect-services.json file from App information, copy and paste in android Project under app directory, as follows.
7. Enter SHA-256 certificate fingerprint and click Save button, as follows.
Note: Above steps from Step 1 to 7 is common for all Huawei Kits.
8. Add the below maven URL in build.gradle(Project) file under the repositories of buildscript, dependencies and allprojects, refer Add Configuration.
Java:
maven { url 'http://developer.huawei.com/repo/' }
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
9. Add the below plugin and dependencies in build.gradle(Module) file.
Java:
apply plugin: id 'com.huawei.agconnect'
// Huawei AGC
implementation 'com.huawei.agconnect:agconnect-core:1.6.0.300'
10. Now Sync the gradle.
Let us move to development
I have created a project on Android studio with empty activity let us start coding.
In the AndroidActivity.kt we can find the business logic for android questions.
Java:
class AndroidActivity : AppCompatActivity(), View.OnClickListener {
private var mCurrentPosition: Int = 1
private var mQuestionsList: ArrayList<AndroidQuestions>? = null
private var mSelectedOptionPosition: Int = 0
private var mCorrectAnswers: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_android)
mQuestionsList = AndroidConstants.getQuestions()
setQuestion()
txt_option1.setOnClickListener(this)
txt_option2.setOnClickListener(this)
txt_option3.setOnClickListener(this)
txt_option4.setOnClickListener(this)
btn_ardsubmit.setOnClickListener(this)
}
private fun setQuestion() {
val question = mQuestionsList!![mCurrentPosition -1]
defaultOptionsView()
if(mCurrentPosition == mQuestionsList!!.size){
btn_ardsubmit.text = "FINISH"
} else {
btn_ardsubmit.text = "SUBMIT"
}
progressBar_ard.progress = mCurrentPosition
txt_progress_ard.text = "$mCurrentPosition" + "/" + progressBar_ard.max
txt_ardquestion.text = question!!.questions
// iv_image.setImageResource(question.image)
txt_option1.text = question.option1
txt_option2.text = question.option2
txt_option3.text = question.option3
txt_option4.text = question.option4
}
private fun defaultOptionsView() {
val options = ArrayList<TextView>()
options.add(0, txt_option1)
options.add(1, txt_option2)
options.add(2, txt_option3)
options.add(3, txt_option4)
for(option in options){
option.setTextColor(Color.parseColor("#7A8089"))
option.typeface = Typeface.DEFAULT
option.background = ContextCompat.getDrawable(this, R.drawable.border_bg)
}
}
override fun onClick(v: View?) {
when(v?.id){
R.id.txt_option1 -> {
selectedOptionView(txt_option1, 1)
}
R.id.txt_option2 -> {
selectedOptionView(txt_option2, 2)
}
R.id.txt_option3 -> {
selectedOptionView(txt_option3, 3)
}
R.id.txt_option4 -> {
selectedOptionView(txt_option4, 4)
}
R.id.btn_ardsubmit -> {
if(mSelectedOptionPosition == 0){
mCurrentPosition++
when{
mCurrentPosition <= mQuestionsList!!.size -> {
setQuestion()
} else -> {
val intent = Intent(this, AndroidResultActivity::class.java)
intent.putExtra(AndroidConstants.TOTAL_ARD_QUESTIONS, mCorrectAnswers)
intent.putExtra(AndroidConstants.CORRECT_ARD_ANSWERS, mQuestionsList!!.size)
startActivity(intent)
}
}
} else {
val question = mQuestionsList?.get(mCurrentPosition -1)
if(question!!.correctAnswer != mSelectedOptionPosition){
answerView(mSelectedOptionPosition, R.drawable.wrong_bg)
} else {
mCorrectAnswers ++
}
answerView(question!!.correctAnswer, R.drawable.correct_bg)
if(mCurrentPosition == mQuestionsList!!.size){
btn_ardsubmit.text = "FINISH"
} else {
btn_ardsubmit.text = "Next Question"
}
mSelectedOptionPosition = 0
}
}
}
}
private fun answerView(answer:Int, drawableView:Int){
when(answer) {
1 -> {
txt_option1.background = ContextCompat.getDrawable(this, drawableView)
}
2 -> {
txt_option2.background = ContextCompat.getDrawable(this, drawableView)
}
3 -> {
txt_option3.background = ContextCompat.getDrawable(this, drawableView)
}
4 -> {
txt_option4.background = ContextCompat.getDrawable(this, drawableView)
}
}
}
private fun selectedOptionView(tv: TextView, selectedOptionNum: Int){
defaultOptionsView()
mSelectedOptionPosition = selectedOptionNum
tv.setTextColor(Color.parseColor("#363A43"))
tv.setTypeface(tv.typeface, Typeface.BOLD)
tv.background = ContextCompat.getDrawable(this, R.drawable.select_bg)
}
}
In the AndroidResultActivity.kt we can find the business logic for android result view.
Java:
class AndroidResultActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_android_result)
val totalQuestions = intent.getIntExtra(AndroidConstants.TOTAL_ARD_QUESTIONS, 0)
val correctAnswers = intent.getIntExtra(AndroidConstants.CORRECT_ARD_ANSWERS, 0)
// txt_ardscore.text = "Your Score is $correctAnswers out of $totalQuestions"
txt_ardscore.text = "Your Score is $totalQuestions out of $correctAnswers"
btn_ardfinish.setOnClickListener {
startActivity(Intent(this, Home::class.java))
}
}
}
Create a data class AndroidQuestions.kt to access variables.
Code:
data class AndroidQuestions(
val id:Int,
val questions:String,
val option1:String,
val option2:String,
val option3:String,
val option4:String,
val correctAnswer:Int
)
Create object class AndroidConstants.kt to show questions.
Code:
object AndroidConstants {
const val TOTAL_ARD_QUESTIONS: String = "total_questions"
const val CORRECT_ARD_ANSWERS: String = "correct_answers"
fun getQuestions():ArrayList<AndroidQuestions>{
val questionsList = ArrayList<AndroidQuestions>()
// 1
val ques1 = AndroidQuestions(1, "On which thread broadcast receivers will work in android?",
"Worker Thread","Main Thread", "Activity Thread", "None of the above", 2)
questionsList.add(ques1)
// 2
val ques2 = AndroidQuestions(2, "What was the first phone released that ran the Android OS?",
"Google gPhone","HTC Hero", "Motorola Droid", "T-Mobile G1", 4)
questionsList.add(ques2)
// 3
val ques3 = AndroidQuestions(3, "During an Activity life-cycle, what is the first callback method invoked by the system?",
"onCreate()", "onStart()", "onStop()", "onDestroy()", 1)
questionsList.add(ques3)
// 4
val ques4 = AndroidQuestions(4, "What is mean by ADB?",
"Application Debug Bridge", "Android Debug Bridge", "Application data bridge", "Android data bridge", 2)
questionsList.add(ques4)
// 5
val ques5 = AndroidQuestions(5, "If you want to increase the whitespace between widgets, you will need to use the ___ property",
"Android:digits", "Android:capitalize", "Android:padding", "Android:autoText", 3)
questionsList.add(ques5)
// 6
val ques6 = AndroidQuestions(6, "What is ANR responding time in android?",
"10 seconds", "5 seconds", "1 minute", "45 seconds", 2)
questionsList.add(ques6)
// 7
val ques7 = AndroidQuestions(7, "Choose the layout, that is deprecated",
"Absolute Layout", "Frame Layout", "Relative Layout", "Linear Layout", 2)
questionsList.add(ques7)
// 8
val ques8 = AndroidQuestions(8, "Which method can access a view element of a layout resource in activity",
"onCreate()", "findViewById()", "setContentView()", "None", 2)
questionsList.add(ques8)
// 9
val ques9 = AndroidQuestions(9, "In Which Directory XML Layout files are stored",
"/assets", "/src", "/res/values", "/res/layout", 4)
questionsList.add(ques9)
// 10
val ques10 = AndroidQuestions(10, "What are the functionalities in AsyncTask in Android?",
"onPreExecution()", "onPostExecution()", "DoInBackground()", "onProgressUpdate()", 2)
questionsList.add(ques10)
return questionsList
}
}
In the HMSActivity.kt we can find the business logic for android questions.
Java:
class HMSActivity : AppCompatActivity(),View.OnClickListener {
private var kCurrentPosition: Int = 1
private var kQuestionsList: ArrayList<HMSQuestions>? = null
private var kSelectedOptionPosition: Int = 0
private var kCorrectAnswers: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_hmsactivity)
kQuestionsList = HMSConstants.getQuestions()
setQuestion()
txt_option1_hms.setOnClickListener(this)
txt_option2_hms.setOnClickListener(this)
txt_option3_hms.setOnClickListener(this)
txt_option4_hms.setOnClickListener(this)
btn_hms_submit.setOnClickListener(this)
}
private fun setQuestion() {
val question = kQuestionsList!![kCurrentPosition -1]
defaultOptionsView()
if(kCurrentPosition == kQuestionsList!!.size){
btn_hms_submit.text = "FINISH"
} else {
btn_hms_submit.text = "SUBMIT"
}
progressBar_hms.progress = kCurrentPosition
txt_progress_hms.text = "$kCurrentPosition" + "/" + progressBar_hms.max
txt_hmsquestion.text = question!!.hms_questions
// iv_image.setImageResource(question.image)
txt_option1_hms.text = question.hms_option1
txt_option2_hms.text = question.hms_option2
txt_option3_hms.text = question.hms_option3
txt_option4_hms.text = question.hms_option4
}
private fun defaultOptionsView() {
val options = ArrayList<TextView>()
options.add(0, txt_option1_hms)
options.add(1, txt_option2_hms)
options.add(2, txt_option3_hms)
options.add(3, txt_option4_hms)
for(option in options){
option.setTextColor(Color.parseColor("#7A8089"))
option.typeface = Typeface.DEFAULT
option.background = ContextCompat.getDrawable(this, R.drawable.border_bg)
}
}
override fun onClick(v: View?) {
when(v?.id){
R.id.txt_option1_hms -> {
selectedOptionView(txt_option1_hms, 1)
}
R.id.txt_option2_hms -> {
selectedOptionView(txt_option2_hms, 2)
}
R.id.txt_option3_hms -> {
selectedOptionView(txt_option3_hms, 3)
}
R.id.txt_option4_hms -> {
selectedOptionView(txt_option4_hms, 4)
}
R.id.btn_hms_submit -> {
if(kSelectedOptionPosition == 0){
kCurrentPosition++
when{
kCurrentPosition <= kQuestionsList!!.size -> {
setQuestion()
} else -> {
val intent = Intent(this, HMSResultActivity::class.java)
intent.putExtra(HMSConstants.TOTAL_HMS_QUESTIONS, kCorrectAnswers)
intent.putExtra(HMSConstants.CORRECT_HMS_ANSWERS, kQuestionsList!!.size)
startActivity(intent)
}
}
} else {
val question = kQuestionsList?.get(kCurrentPosition -1)
if(question!!.hms_correctAnswer != kSelectedOptionPosition){
answerView(kSelectedOptionPosition, R.drawable.wrong_bg)
} else {
kCorrectAnswers ++
}
answerView(question!!.hms_correctAnswer, R.drawable.correct_bg)
if(kCurrentPosition == kQuestionsList!!.size){
btn_hms_submit.text = "FINISH"
} else {
btn_hms_submit.text = "Next Question"
}
kSelectedOptionPosition = 0
}
}
}
}
private fun answerView(answer:Int, drawableView:Int){
when(answer) {
1 -> {
txt_option1_hms.background = ContextCompat.getDrawable(this, drawableView)
}
2 -> {
txt_option2_hms.background = ContextCompat.getDrawable(this, drawableView)
}
3 -> {
txt_option3_hms.background = ContextCompat.getDrawable(this, drawableView)
}
4 -> {
txt_option4_hms.background = ContextCompat.getDrawable(this, drawableView)
}
}
}
private fun selectedOptionView(tv: TextView, selectedOptionNum: Int){
defaultOptionsView()
kSelectedOptionPosition = selectedOptionNum
tv.setTextColor(Color.parseColor("#363A43"))
tv.setTypeface(tv.typeface, Typeface.BOLD)
tv.background = ContextCompat.getDrawable(this, R.drawable.select_bg)
}
}
In the HMSResultActivity.kt we can find the business logic for android result view.
Code:
class HMSResultActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_hmsresult)
val totalQuestions = intent.getIntExtra(HMSConstants.TOTAL_HMS_QUESTIONS, 0)
val correctAnswers = intent.getIntExtra(HMSConstants.CORRECT_HMS_ANSWERS, 0)
txt_hmsscore.text = "Your Score is $totalQuestions out of $correctAnswers"
btn_hmsfinish.setOnClickListener {
startActivity(Intent(this, Home::class.java))
}
}
}
Create a data class HMSQuestions.kt to access variables.
Code:
data class HMSQuestions(
val id:Int,
val hms_questions:String,
val hms_option1:String,
val hms_option2:String,
val hms_option3:String,
val hms_option4:String,
val hms_correctAnswer:Int
)
Create object class HMSConstants.kt to show questions.
Code:
object HMSConstants {
const val TOTAL_HMS_QUESTIONS: String = "total_questions"
const val CORRECT_HMS_ANSWERS: String = "correct_answers"
fun getQuestions():ArrayList<HMSQuestions>{
val hmsquestionsList = ArrayList<HMSQuestions>()
// 1
val hques1 = HMSQuestions(1, "What is HMS?",
"Huawei Medical Services","Huawei Mobile Services", "Huawei Mission Services", "Huawei Military Services", 2)
hmsquestionsList.add(hques1)
// 2
val hques2 = HMSQuestions(2, "Which Kit provides a secure login authorization function of users?",
"Map Kit","Account Kit", "Location Kit", "Scan Kit", 2)
hmsquestionsList.add(hques2)
// 3
val hques3 = HMSQuestions(3, "Scan Kit supports -- formats for most business scenarios.",
"12", "14", "15", "13", 4)
hmsquestionsList.add(hques3)
// 4
val hques4 = HMSQuestions(4, "How many landmark names can be recognized by ML Kit?",
"300", "3000+", "500", "5000+", 4)
hmsquestionsList.add(hques4)
// 5
val hques5 = HMSQuestions(5, "What is the full form of OAID?",
"Open Advertising Identifier", "Open Adverse Identity", "Open Amendment Information", "Open All Identity", 1)
hmsquestionsList.add(hques5)
// 6
val hques6 = HMSQuestions(6, "How many user addresses are allowed by Huawei Kit for user?",
"5", "8", "15", "10", 4)
hmsquestionsList.add(hques6)
// 7
val hques7 = HMSQuestions(7, "Which type of format supports Panorama Kit?",
"JPG", "JPEG", "PNG", "All of the above", 4)
hmsquestionsList.add(hques7)
// 8
val hques8 = HMSQuestions(8, "Which method is used to obtain the last requested available location.",
"getLastLocation()", "onLocationAvailability()", "onLocationResult", "None", 1)
hmsquestionsList.add(hques8)
// 9
val hques9 = HMSQuestions(9, "How many languages does the Video Editor Kit supports?",
"100", "48", "55", "78", 4)
hmsquestionsList.add(hques9)
// 10
val hques10 = HMSQuestions(10, "What are the formats supported by Audio Editor Kit?",
"MP3", "WAV and AAC", "M4A", "All of the above", 4)
hmsquestionsList.add(hques10)
return hmsquestionsList
}
}
In the activity_android.xml we can create the UI screen for questions.
XML:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
tools:context=".android.AndroidActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"
android:gravity="center" >
<TextView
android:id="@+id/txt_ardquestion"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:gravity="center"
android:text="What is Android?"
android:textColor="#363A43"
android:textSize="18sp">
</TextView>
<LinearLayout
android:id="@+id/progress_details_android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginTop="16dp" >
<ProgressBar
android:id="@+id/progressBar_ard"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:minHeight="50dp"
android:progress="0"
android:indeterminate="false"
android:max="10">
</ProgressBar>
<TextView
android:id="@+id/txt_progress_ard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="15dp"
android:gravity="center"
android:textColorHint="#7A8089"
android:textSize="14sp"
tools:text="0/10">
</TextView>
</LinearLayout>
<TextView
android:id="@+id/txt_option1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/border_bg"
android:padding="15dp"
android:gravity="center"
android:textColor="#7A8089"
android:textSize="18sp"
tools:text="Apple">
</TextView>
<TextView
android:id="@+id/txt_option2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/border_bg"
android:padding="15dp"
android:gravity="center"
android:textColor="#7A8089"
android:textSize="18sp"
tools:text="Google">
</TextView>
<TextView
android:id="@+id/txt_option3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/border_bg"
android:padding="15dp"
android:gravity="center"
android:textColor="#7A8089"
android:textSize="18sp"
tools:text="iOS">
</TextView>
<TextView
android:id="@+id/txt_option4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/border_bg"
android:padding="15dp"
android:gravity="center"
android:textColor="#7A8089"
android:textSize="18sp"
tools:text="Huawei">
</TextView>
<Button
android:id="@+id/btn_ardsubmit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@color/design_default_color_primary"
android:text="Submit"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
</ScrollView>
In the activity_android_result.xml we can create the UI screen for result.
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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="@drawable/ardresult_bg"
android:padding="20dp"
tools:context=".android.AndroidResultActivity">
<TextView
android:id="@+id/txt_ardresult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="25dp"
android:text="Result"
android:textColor="@android:color/white"
android:textStyle="bold"
android:textSize="22sp">
</TextView>
<ImageView
android:id="@+id/img_ardtrophy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:src="@drawable/trophy"/>
<TextView
android:id="@+id/txt_ardcongratulations"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Hi, Congratulations!!"
android:textColor="@android:color/white"
android:textStyle="bold"
android:textSize="25sp">
</TextView>
<TextView
android:id="@+id/txt_ardscore"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="Your Score is 5 out of 10"
android:textColor="@color/hwid_auth_button_color_red"
android:textSize="20sp">
</TextView>
<Button
android:id="@+id/btn_ardfinish"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:background="@android:color/white"
android:text="Finish"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
In the activity_hmsactivity.xml we can create the UI screen for questions.
XML:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
tools:context=".hms.HMSActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"
android:gravity="center" >
<TextView
android:id="@+id/txt_hmsquestion"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:gravity="center"
android:text="What is hms?"
android:textColor="#363A43"
android:textSize="18sp">
</TextView>
<LinearLayout
android:id="@+id/progress_details_hms"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginTop="16dp" >
<ProgressBar
android:id="@+id/progressBar_hms"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:minHeight="50dp"
android:progress="0"
android:indeterminate="false"
android:max="10">
</ProgressBar>
<TextView
android:id="@+id/txt_progress_hms"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="15dp"
android:gravity="center"
android:textColorHint="#7A8089"
android:textSize="14sp"
tools:text="0/10">
</TextView>
</LinearLayout>
<TextView
android:id="@+id/txt_option1_hms"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/border_bg"
android:padding="15dp"
android:gravity="center"
android:textColor="#7A8089"
android:textSize="18sp"
tools:text="Apple">
</TextView>
<TextView
android:id="@+id/txt_option2_hms"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/border_bg"
android:padding="15dp"
android:gravity="center"
android:textColor="#7A8089"
android:textSize="18sp"
tools:text="Google">
</TextView>
<TextView
android:id="@+id/txt_option3_hms"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/border_bg"
android:padding="15dp"
android:gravity="center"
android:textColor="#7A8089"
android:textSize="18sp"
tools:text="iOS">
</TextView>
<TextView
android:id="@+id/txt_option4_hms"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/border_bg"
android:padding="15dp"
android:gravity="center"
android:textColor="#7A8089"
android:textSize="18sp"
tools:text="Huawei">
</TextView>
<Button
android:id="@+id/btn_hms_submit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@color/design_default_color_primary"
android:text="Submit"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
</ScrollView>
In the activity_hmsresult.xml we can create the UI screen for result.
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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="@drawable/hmsresult_bg"
android:padding="20dp"
tools:context=".hms.HMSResultActivity">
<TextView
android:id="@+id/txt_hmsresult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="25dp"
android:text="Result"
android:textColor="@android:color/white"
android:textStyle="bold"
android:textSize="22sp">
</TextView>
<ImageView
android:id="@+id/img_hmstrophy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:src="@drawable/victory"/>
<TextView
android:id="@+id/txt_hmscongratulations"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Congrats done HMS Quiz!!"
android:textColor="@android:color/white"
android:textStyle="bold"
android:textSize="25sp">
</TextView>
<TextView
android:id="@+id/txt_hmsscore"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="Your Score is 6 out of 10"
android:textColor="@color/black"
android:textSize="20sp">
</TextView>
<Button
android:id="@+id/btn_hmsfinish"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:background="@android:color/white"
android:text="Finish"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
Demo
Tips and Tricks
1. Make sure you are already registered as Huawei developer.
2. Set minSDK version to 24 or later, otherwise you will get AndriodManifest merge issue.
3. Make sure you have added the agconnect-services.json file to app folder.
4. Make sure you have added SHA-256 fingerprint without fail.
5. Make sure all the dependencies are added properly.
Conclusion
In this article, we have learned about the basic questions on Android and HMS of Quiz application. The purpose of conducting quizzes within the business is more fun and educative to understand how the business is running straight away, test the knowledge of the user and helps to form a businessman or woman a far better person in terms of the business process. So, I will provide the series of articles on this Quiz App, in upcoming articles
I hope you have read this article. If you found it is helpful, please provide likes and comments.
Reference
Click the URL - https://www.geeksforgeeks.org/how-to-create-a-quiz-app-in-android/

Integration of Huawei Crash Service in Quiz Android app (Kotlin) – Part 5

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Introduction
In this article, we can learn about the basic questions on different country flags of Quiz application. Also, we can learn to integrate Huawei Crash service of AppGallery Connect in Quiz application.
If you are new to this application, follow my previous articles.
https://forums.developer.huawei.com/forumPortal/en/topic/0202877278014350004
https://forums.developer.huawei.com/forumPortal/en/topic/0201884103719030016?fid=0101187876626530001
https://forums.developer.huawei.com/forumPortal/en/topic/0202890333711770040
https://forums.developer.huawei.com/forumPortal/en/topic/0201892776213940037
What is Crash service?
The AppGallery Connect Crash service provides a powerful lightweight solution to app crash problems. With the service, you can quickly detect, locate, and resolve app crashes (unexpected exits of apps), and have access to highly readable crash reports in real-time, without the need to write any code.
Huawei Crash is a real-time crash reporting tool that helps in tracking, prioritizing, and fixing stability issues that compromise the quality of your app.
To ensure stable running of your app and prevent user experience deterioration caused by crashes, you are advised to monitor the running status of your app on each device, which is the key. The Crash service provides real-time reports, revealing any crash of your app on any device. In addition, the Crash service can intelligently aggregate crashes, providing context data when a crash occurs, such as environment information and stack, for you to prioritize the crash easily for rapid resolution.
Requirements
1. Any operating system (MacOS, Linux, and Windows).
2. Must have a Huawei phone with HMS 4.0.0.300 or later.
3. Must have a laptop or desktop with Android Studio, JDK 1.8, SDK platform 26, and Gradle 4.6 and above installed.
4. Minimum API Level 24 is required.
5. Required EMUI 9.0.0 and later version devices.
How to integrate HMS Dependencies
1. First register as Huawei developer and complete identity verification on the Huawei developers website, refer to register a Huawei ID.
2. Create a project in android studio, refer Creating an Android Studio Project.
3. Generate a SHA-256 certificate fingerprint.
4. To generate SHA-256 certificate fingerprint. On the right-upper corner of the android project click Gradle, choose Project Name > Tasks > android, and then click signingReport, as follows.
Note: Project Name depends on the user created name.
5. Create an App in AppGallery Connect.
6. Download the agconnect-services.json file from App information, copy and paste in android Project under app directory, as follows.
7. Enter SHA-256 certificate fingerprint and click Save button, as follows.
Note: Above steps from Step 1 to 7 is common for all Huawei Kits.
8. Click Manage APIs tab and enable HUAWEI Analytics.
9. Add the below maven URL in build.gradle(Project) file under the repositories of buildscript, dependencies and allprojects, refer Add Configuration.
Java:
maven { url 'http://developer.huawei.com/repo/' }
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
10. Add the below plugin and dependencies in build.gradle(Module) file.
Java:
apply plugin: id 'com.huawei.agconnect'
// Huawei AGC
implementation 'com.huawei.agconnect:agconnect-core:1.6.0.300'
// Huawei Analytics Kit
implementation 'com.huawei.hms:hianalytics:6.4.0.300'
// Huawei Crash Service
implementation 'com.huawei.agconnect:agconnect-crash:1.6.0.300'
11. Now Sync the gradle.
12. Add the required permission to the AndroidManifest.xml file.
Java:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
Configuration in AppGallery Connect
Find the Crash using AppGallery connect dashboard.
Choose My Projects > Quality > Crash, and click Enable now.
Let us move to development
I have created a project on Android studio with empty activity let us start coding.
1. Initialize an AGConnectCrash before other methods and Enable crash.
Java:
AGConnectCrash.getInstance().enableCrashCollection(true)
2. Test the below method in your code.
Code:
AGConnectCrash.getInstance().testIt([email protected])
3. Customizing User IDs: Analyzing crashes by a user to resolve crashes using User ID. The user can be uniquely identified after a crash occurs.
Code:
AGConnectCrash.getInstance().setUserId("123456789")
4. Recording Custom Logs: we can record custom logs, Recorded logs will be reported together with the crash data.
Java:
AGConnectCrash.getInstance().log("catch exception")
5. Adding a Custom key-value pair: we can add a custom key-value pair to record the status. The recorded status will be reported together with the crash data.
Java:
AGConnectCrash.getInstance().setCustomKey("keyInt", 1)
In the Home.kt we can find the business logic for crash service.
Java:
class Home : AppCompatActivity(), HomeAdapter.ItemListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
// Crash Service
AGConnectCrash.getInstance().enableCrashCollection(true)
// Record Custom Status
AGConnectCrash.getInstance().setCustomKey("keyInt", 1)
// Set the user ID
AGConnectCrash.getInstance().setUserId("123456789")
try {
throw NullPointerException()
} catch (ex: NullPointerException) {
AGConnectCrash.getInstance().log("catch exception")
// Record non-fatal exception
AGConnectCrash.getInstance().recordException(ex)
}
}
override fun onItemClick(item: Int) {
when(item ) {
0 -> {val intent = Intent([email protected], AndroidActivity::class.java)
startActivity(intent)
}
1 -> {val intent = Intent([email protected], HMSActivity::class.java)
startActivity(intent)
}
2 -> {val intent = Intent([email protected], SportsActivity::class.java)
startActivity(intent)
}
3 -> {val intent = Intent([email protected], QuizActivity::class.java)
startActivity(intent)
// Test
AGConnectCrash.getInstance().testIt([email protected])
}
}
}
}
In the QuizActivity.kt we can find the business logic for country flags questions.
Java:
class QuizActivity : AppCompatActivity(), View.OnClickListener {
private var nCurrentPosition: Int = 1
private var nQuestionsList: ArrayList<Question>? = null
private var nSelectedOptionPosition: Int = 0
private var nCorrectAnswers: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_quiz)
nQuestionsList = Constants.getQuestions()
setQuestion()
txt_option_one.setOnClickListener(this)
txt_option_two.setOnClickListener(this)
txt_option_three.setOnClickListener(this)
txt_option_four.setOnClickListener(this)
btn_submit.setOnClickListener(this)
}
private fun setQuestion() {
val question = nQuestionsList!![nCurrentPosition -1]
defaultOptionsView()
if(nCurrentPosition == nQuestionsList!!.size){
btn_submit.text = "FINISH"
} else {
btn_submit.text = "SUBMIT"
}
progressBar.progress = nCurrentPosition
txt_progress.text = "$nCurrentPosition" + "/" + progressBar.max
txt_question.text = question!!.question
iv_image.setImageResource(question.image)
txt_option_one.text = question.optionOne
txt_option_two.text = question.optionTwo
txt_option_three.text = question.optionThree
txt_option_four.text = question.optionFour
}
private fun defaultOptionsView() {
val options = ArrayList<TextView>()
options.add(0, txt_option_one)
options.add(1, txt_option_two)
options.add(2, txt_option_three)
options.add(3, txt_option_four)
for(option in options){
option.setTextColor(Color.parseColor("#7A8089"))
option.typeface = Typeface.DEFAULT
option.background = ContextCompat.getDrawable(this, R.drawable.border_bg)
}
}
override fun onClick(v: View?) {
when(v?.id){
R.id.txt_option_one -> {
selectedOptionView(txt_option_one, 1)
}
R.id.txt_option_two -> {
selectedOptionView(txt_option_two, 2)
}
R.id.txt_option_three -> {
selectedOptionView(txt_option_three, 3)
}
R.id.txt_option_four -> {
selectedOptionView(txt_option_four, 4)
}
R.id.btn_submit -> {
if(nSelectedOptionPosition == 0){
nCurrentPosition++
when{
nCurrentPosition <= nQuestionsList!!.size -> {
setQuestion()
} else -> {
val intent = Intent(this, ResultActivity::class.java)
intent.putExtra(Constants.CORRECT_ANSWERS, nCorrectAnswers)
intent.putExtra(Constants.TOTAL_QUESTIONS, nQuestionsList!!.size)
startActivity(intent)
}
}
} else {
val question = nQuestionsList?.get(nCurrentPosition -1)
if(question!!.correctAnswer != nSelectedOptionPosition){
answerView(nSelectedOptionPosition, R.drawable.wrong_bg)
} else {
nCorrectAnswers ++
}
answerView(question!!.correctAnswer, R.drawable.correct_bg)
if(nCurrentPosition == nQuestionsList!!.size){
btn_submit.text = "FINISH"
} else {
btn_submit.text = "Next Question"
}
nSelectedOptionPosition = 0
}
}
}
}
private fun answerView(answer:Int, drawableView:Int){
when(answer) {
1 -> {
txt_option_one.background = ContextCompat.getDrawable(this, drawableView)
}
2 -> {
txt_option_two.background = ContextCompat.getDrawable(this, drawableView)
}
3 -> {
txt_option_three.background = ContextCompat.getDrawable(this, drawableView)
}
4 -> {
txt_option_four.background = ContextCompat.getDrawable(this, drawableView)
}
}
}
private fun selectedOptionView(tv: TextView, selectedOptionNum: Int){
defaultOptionsView()
nSelectedOptionPosition = selectedOptionNum
tv.setTextColor(Color.parseColor("#363A43"))
tv.setTypeface(tv.typeface, Typeface.BOLD)
tv.background = ContextCompat.getDrawable(this, R.drawable.select_bg)
}
}
In the ResultActivity.kt we can find the business logic for country flags result view.
Java:
class ResultActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_result)
val totalQuestions = intent.getIntExtra(Constants.TOTAL_QUESTIONS, 0)
val correctAnswers = intent.getIntExtra(Constants.CORRECT_ANSWERS, 0)
txt_score.text = "Your Score is $correctAnswers out of $totalQuestions"
btn_finish.setOnClickListener {
startActivity(Intent(this, Home::class.java))
}
}
}
Create a data class Question.kt to access variables.
Java:
data class Question(
val id:Int,
val question:String,
val image:Int,
val optionOne:String,
val optionTwo:String,
val optionThree:String,
val optionFour:String,
val correctAnswer:Int
)
Create object class Constants.kt to show questions.
Java:
object Constants {
const val TOTAL_QUESTIONS: String = "total_question"
const val CORRECT_ANSWERS: String = "correct_answers"
fun getQuestions():ArrayList<Question>{
val questionsList = ArrayList<Question>()
// 1
val que1 = Question(1, "What Country does this flag belong to?",
R.drawable.angola_flag, "Zambia",
"Botswana", "Angola", "Namibia", 3)
questionsList.add(que1)
// 2
val que2 = Question(2, "What Country does this flag belong to?",
R.drawable.barmuda_flag, "Bermuda",
"Havana", "Merida", "Miami", 1)
questionsList.add(que2)
// 3
val que3 = Question(3, "What Country does this flag belong to?",
R.drawable.bolivia_flag, "Brazil",
"Bolivia", "Paraguay", "Uruguay", 2)
questionsList.add(que3)
// 4
val que4 = Question(4, "What Country does this flag belong to?",
R.drawable.cambodia_flag, "Vietnam",
"Laos", "Cambodia", "Jakarta", 3)
questionsList.add(que4)
// 5
val que5 = Question(5, "What Country does this flag belong to?",
R.drawable.chile_flag, "Peru",
"Panama", "Honduras", "Chile", 4)
questionsList.add(que5)
// 6
val que6 = Question(6, "What Country does this flag belong to?",
R.drawable.cuba_flag, "Guyana",
"Cuba", "Ecuador", "Guatemala", 2)
questionsList.add(que6)
// 7
val que7 = Question(7, "What Country does this flag belong to?",
R.drawable.honduras_flag, "Honduras",
"Costa Rica", "Puerto Rico", "Dominican Republic", 1)
questionsList.add(que7)
// 8
val que8 = Question(8, "What Country does this flag belong to?",
R.drawable.mali_flag, "Algeria",
"Libya", "Mali", "Tunisia", 3)
questionsList.add(que8)
// 9
val que9 = Question(9, "What Country does this flag belong to?",
R.drawable.norway_flag, "Sweden",
"Poland", "Austria", "Norway", 4)
questionsList.add(que9)
// 10
val que10 = Question(10, "What Country does this flag belong to?",
R.drawable.suriname_flag, "Barbados",
"Haiti", "Suriname", "Belize", 3)
questionsList.add(que10)
return questionsList
}
}
In the activity_quiz.xml we can create the UI screen for questions.
XML:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
tools:context=".flags.QuizActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"
android:gravity="center" >
<TextView
android:id="@+id/txt_question"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:gravity="center"
android:text="What Country does this flag belong to?"
android:textColor="#363A43"
android:textSize="18sp">
</TextView>
<ImageView
android:id="@+id/iv_image"
android:layout_width="wrap_content"
android:layout_height="120dp"
android:layout_marginTop="16dp"
android:src="@drawable/android_image"/>
<LinearLayout
android:id="@+id/progress_details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginTop="16dp" >
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:minHeight="50dp"
android:progress="0"
android:indeterminate="false"
android:max="10">
</ProgressBar>
<TextView
android:id="@+id/txt_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="15dp"
android:gravity="center"
android:textColorHint="#7A8089"
android:textSize="14sp"
tools:text="0/10">
</TextView>
</LinearLayout>
<TextView
android:id="@+id/txt_option_one"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/border_bg"
android:padding="15dp"
android:gravity="center"
android:textColor="#7A8089"
android:textSize="18sp"
tools:text="India">
</TextView>
<TextView
android:id="@+id/txt_option_two"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/border_bg"
android:padding="15dp"
android:gravity="center"
android:textColor="#7A8089"
android:textSize="18sp"
tools:text="Sri Lanka">
</TextView>
<TextView
android:id="@+id/txt_option_three"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/border_bg"
android:padding="15dp"
android:gravity="center"
android:textColor="#7A8089"
android:textSize="18sp"
tools:text="Burma">
</TextView>
<TextView
android:id="@+id/txt_option_four"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/border_bg"
android:padding="15dp"
android:gravity="center"
android:textColor="#7A8089"
android:textSize="18sp"
tools:text="USA">
</TextView>
<Button
android:id="@+id/btn_submit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@color/design_default_color_primary"
android:text="Submit"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
</ScrollView>
In the activity_result.xml we can create the UI screen for result.
Java:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="@drawable/result_bg"
android:padding="20dp"
tools:context=".flags.ResultActivity">
<TextView
android:id="@+id/txt_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="25dp"
android:text="Result"
android:textColor="@android:color/white"
android:textStyle="bold"
android:textSize="22sp">
</TextView>
<ImageView
android:id="@+id/img_trophy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:src="@drawable/trophy"/>
<TextView
android:id="@+id/txt_congratulations"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Hi, Congratulations!!"
android:textColor="@android:color/white"
android:textStyle="bold"
android:textSize="25sp">
</TextView>
<TextView
android:id="@+id/txt_score"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="Your Score is 9 out of 10"
android:textColor="@android:color/secondary_text_dark"
android:textSize="20sp">
</TextView>
<Button
android:id="@+id/btn_finish"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:background="@android:color/white"
android:text="Finish"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
Demo
Crash Service
Tips and Tricks
1. Make sure you are already registered as Huawei developer.
2. Set minSDK version to 24 or later, otherwise you will get AndriodManifest merge issue.
3. Make sure you have added the agconnect-services.json file to app folder.
4. Make sure you have added SHA-256 fingerprint without fail.
5. Make sure all the dependencies are added properly.
Conclusion
In this article, we have learned about the basic questions on different country flags of Quiz application. Also, we have learned to integrate Huawei Crash service of AppGallery Connect in Quiz application. Crash service provides a powerful lightweight solution to app crash problems. With the service, you can quickly detect, locate, and resolve app crashes (unexpected exits of apps), and have access to highly readable crash reports in real time, without the need to write any code.
I hope you have read this article. If you found it helpful, please provide likes and comments.
Reference
Crash Service – Documentation
Crash Service – Training Video

Check the similar words using Text Embedding feature by Huawei ML Kit in Android (Kotlin)

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Introduction
In this article, we can learn how to check similar words and sentences using Text Embedding feature of Huawei ML Kit. This Huawei ML Kit provides Text Embedding feature which helps to get matching vector value of words or sentences. Using this feature, we can improve our research based on the result. It provides similarity between two words or sentences and similar words of a particular word searched. We can also improve searching and browsing efficiency using after getting results related to search text.
Use Cases
This service can be used in text search scenarios. A user can enter a keyword in your news app to return hot news related to the word, improving the search and browsing efficiency.
Precautions
Text embedding depends on the on-cloud API for recognition. During commissioning and usage, ensure that the device can access the Internet.
Requirements
1. Any operating system (MacOS, Linux and Windows).
2. Must have a Huawei phone with HMS 4.0.0.300 or later.
3. Must have a laptop or desktop with Android Studio, Jdk 1.8, SDK platform 26 and Gradle 4.6 and above installed.
4. Minimum API Level 21 is required.
5. Required EMUI 9.0.0 and later version devices.
How to integrate HMS Dependencies
1. First register as Huawei developer and complete identity verification in Huawei developers website, refer to register a Huawei ID.
2. Create a project in android studio, refer Creating an Android Studio Project.
3. Generate a SHA-256 certificate fingerprint.
4. To generate SHA-256 certificate fingerprint. On right-upper corner of android project click Gradle, choose Project Name > Tasks > android, and then click signingReport, as follows.
Note: Project Name depends on the user created name.
5. Create an App in AppGallery Connect.
6. Download the agconnect-services.json file from App information, copy and paste in android Project under app directory, as follows.
7. Enter SHA-256 certificate fingerprint and click Save button, as follows.
Note: Above steps from Step 1 to 7 is common for all Huawei Kits.
8. Click Manage APIs tab and enable ML Kit.
9. Add the below maven URL in build.gradle(Project) file under the repositories of buildscript, dependencies and allprojects, refer Add Configuration.
Java:
maven { url 'http://developer.huawei.com/repo/' }
classpath 'com.huawei.agconnect:agcp:1.4.1.300'
10. Add the below plugin and dependencies in build.gradle(Module) file.
Java:
apply plugin: 'com.huawei.agconnect'
// Huawei AGC
implementation 'com.huawei.agconnect:agconnect-core:1.5.0.300'
// ML Kit Text Embedding
implementation 'com.huawei.hms:ml-nlp-textembedding:2.0.4.300'
11. Now Sync the gradle.
12. Add the required permission to the AndroidManifest.xml file.
Java:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
Let us move to development
I have created a project on Android studio with empty activity let us start coding.
In the MainActivity.kt we can find the business logic for buttons.
Java:
class MainActivity : AppCompatActivity() {
var wordSimilar: Button? = null
var sentenceSimilar:Button? = null
var similarWords:Button? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
MLApplication.getInstance().apiKey = getString(R.string.api_key)
wordSimilar = findViewById(R.id.word_similar)
sentenceSimilar = findViewById(R.id.sentence_similar)
similarWords = findViewById(R.id.similar_words)
wordSimilar!!.setOnClickListener(View.OnClickListener {
startActivity(Intent([email protected], WordSimilarActivity::class.java)) })
sentenceSimilar!!.setOnClickListener(View.OnClickListener {
startActivity(Intent([email protected], SentenceSimilarActivity::class.java)) })
similarWords!!.setOnClickListener(View.OnClickListener {
startActivity(Intent([email protected], SimilarWordsActivity::class.java)) })
}
}
In the WordSimilarActivity.kt we can find the business logic for similar words.
Java:
class WordSimilarActivity : AppCompatActivity() {
private var analyzer: MLTextEmbeddingAnalyzer? = null
private var checkWordSimilarity: Button? = null
var resultTextView: TextView? = null
var similarWord1: EditText? = null
var similarWord2:EditText? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_word_similar)
resultTextView = findViewById(R.id.similar_word_value)
checkWordSimilarity = findViewById(R.id.check_word_similarity)
similarWord1 = findViewById(R.id.similar_word1)
similarWord2 = findViewById(R.id.similar_word2)
checkWordSimilarity!!.setOnClickListener(View.OnClickListener { getWordSimillarityApi() })
analyzer = UtilForAnalyzer.getAnalyzer()
}
private fun getWordSimillarityApi() {
val wordsSimilarityTask = analyzer!!.analyseWordsSimilarity(
similarWord1!!.text.toString(), similarWord2!!.text.toString() )
wordsSimilarityTask.addOnSuccessListener { wordsSimilarity ->
resultTextView!!.text = "The similarity value is $wordsSimilarity"
}.addOnFailureListener { e -> onFailure(e) }
}
private fun onFailure(e: Exception?) {
if (e is MLTextEmbeddingException) {
val embeddingException = e
embeddingException.errCode
embeddingException.message
} else {
}
}
}
Create a class for analyzer UtilForAnalyzer.kt.
Java:
class UtilForAnalyzer {
companion object{
private var analyzer: MLTextEmbeddingAnalyzer? = null
var setting: MLTextEmbeddingSetting? = null
fun getAnalyzer(): MLTextEmbeddingAnalyzer? {
if (analyzer == null) {
setting = MLTextEmbeddingSetting.Factory()
.setLanguage(MLTextEmbeddingSetting.LANGUAGE_EN)
.create()
analyzer = MLTextEmbeddingAnalyzerFactory.getInstance().getMLTextEmbeddingAnalyzer(setting)
}
return analyzer
}
}
}
In the SentenceSimilarActivity.kt we can find the business logic for similar sentence.
Java:
class SentenceSimilarActivity : AppCompatActivity() {
private var analyzer: MLTextEmbeddingAnalyzer? = null
private var checkSentenceSimilarity: Button? = null
private var sentence_1: EditText? = null
private var sentence_2: EditText? = null
var resultTextView: TextView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sentence_similar)
sentence_1 = findViewById(R.id.sentence1)
sentence_2 = findViewById(R.id.sentence2)
resultTextView = findViewById(R.id.similar_word_value)
checkSentenceSimilarity = findViewById(R.id.check_sentence_similarity)
checkSentenceSimilarity!!.setOnClickListener(View.OnClickListener { getSentenceSimilarityApi() })
analyzer = UtilForAnalyzer.getAnalyzer()
}
private fun getSentenceSimilarityApi() {
val sentencesSimilarityTask = analyzer!!.analyseSentencesSimilarity(
sentence_1!!.text.toString(), sentence_2!!.text.toString()
)
sentencesSimilarityTask.addOnSuccessListener { sentencesSimilarity ->
resultTextView!!.text = "The similarity value is $sentencesSimilarity"
}.addOnFailureListener { e -> onFailure(e) }
}
private fun onFailure(e: Exception?) {
if (e is MLTextEmbeddingException) {
val embeddingException = e
embeddingException.errCode
embeddingException.message
} else {
}
}
}
In the SimilarWordsActivity.kt we can find the business logic for similar words count.
Java:
class SimilarWordsActivity : AppCompatActivity() {
private var findSimilarWords: Button? = null
private var word_1: EditText? = null
private var word_2:EditText? = null
private var analyzer: MLTextEmbeddingAnalyzer? = null
var resultTextView: TextView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_similar_words)
word_1 = findViewById(R.id.word1)
word_2 = findViewById(R.id.word2)
resultTextView = findViewById(R.id.similar_word_value)
findSimilarWords = findViewById(R.id.check_word_similarity)
findSimilarWords!!.setOnClickListener(View.OnClickListener { noOfSimilarWords() })
analyzer = UtilForAnalyzer.getAnalyzer()
}
private fun noOfSimilarWords() {
val multipleSimilarityWordsTask = analyzer!!.analyseSimilarWords(
word_1!!.text.toString(), word_2!!.text.toString().toInt() )
multipleSimilarityWordsTask.addOnSuccessListener { words ->
val stringBuilder = StringBuilder()
for (word in words) {
stringBuilder.append(word)
stringBuilder.append("\t")
}
resultTextView!!.text = stringBuilder.toString()
}.addOnFailureListener { e -> onFailure(e) }
}
private fun onFailure(e: Exception?) {
if (e is MLTextEmbeddingException) {
val embeddingException = e
embeddingException.errCode
embeddingException.message
} else {
}
}
}
In the activity_main.xml we can create the UI screen.
XML:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/word_similar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Check Word Similarity"
android:textAllCaps="false"
android:textSize="17sp"
app:layout_constraintBottom_toTopOf="@+id/sentence_similar"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/sentence_similar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Check Sentence Similarity"
android:textAllCaps="false"
android:textSize="17sp"
app:layout_constraintBottom_toTopOf="@+id/similar_words"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/word_similar" />
<Button
android:id="@+id/similar_words"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Get Similar Words"
android:textAllCaps="false"
android:textSize="17sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/word_similar" />
</androidx.constraintlayout.widget.ConstraintLayout>
In the activity_word_similar.xml we can create the UI screen for sentences.
Java:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".WordSimilarActivity">
<EditText
android:id="@+id/similar_word1"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="17sp"
app:layout_constraintBottom_toTopOf="@+id/similar_word2"
android:background="@drawable/edittext_bg"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/similar_word2"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="17sp"
android:background="@drawable/edittext_bg"
app:layout_constraintBottom_toTopOf="@+id/similar_word_value"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/similar_word1" />
<TextView
android:id="@+id/similar_word_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@+id/check_word_similarity"
android:textColor="@color/black"
android:textSize="20dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/similar_word2" />
<Button
android:id="@+id/check_word_similarity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Check word Similarity"
android:textAllCaps="false"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/similar_word_value" />
</androidx.constraintlayout.widget.ConstraintLayout>
In the activity_sentence_similar.xml we can create the UI screen for sentences.
XML:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SentenceSimilarActivity">
<EditText
android:id="@+id/sentence1"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:gravity="center"
android:background="@drawable/edittext_bg"
app:layout_constraintBottom_toTopOf="@+id/sentence2"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/sentence2"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:gravity="center"
android:background="@drawable/edittext_bg"
app:layout_constraintBottom_toTopOf="@+id/similar_word_value"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/sentence1" />
<TextView
android:id="@+id/similar_word_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@+id/check_sentence_similarity"
android:textColor="@color/purple_500"
android:textSize="20dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/sentence2" />
<Button
android:id="@+id/check_sentence_similarity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Check Sentence Similarity"
android:textSize="17sp"
android:textAllCaps="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/similar_word_value" />
</androidx.constraintlayout.widget.ConstraintLayout>
In the activity_similar_words.xml we can create the UI screen for words count.
XML:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SimilarWordsActivity">
<EditText
android:id="@+id/word1"
android:gravity="center"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:textSize="17sp"
app:layout_constraintBottom_toTopOf="@+id/word2"
android:background="@drawable/edittext_bg"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/word2"
android:gravity="center"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:hint="enter number"
android:textSize="17sp"
android:inputType="number"
android:background="@drawable/edittext_bg"
app:layout_constraintBottom_toTopOf="@+id/similar_word_value"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/word1" />
<TextView
android:id="@+id/similar_word_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
app:layout_constraintBottom_toTopOf="@+id/check_word_similarity"
android:textColor="@color/black"
android:textSize="15dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/word2" />
<Button
android:id="@+id/check_word_similarity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Check Similar Words"
android:textSize="17sp"
android:textAllCaps="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/similar_word_value" />
</androidx.constraintlayout.widget.ConstraintLayout>
Demo
Tips and Tricks
1. Make sure you are already registered as Huawei developer.
2. Set minSDK version to 21 or later, otherwise you will get AndriodManifest merge issue.
3. Make sure you have added the agconnect-services.json file to app folder.
4. Make sure you have added SHA-256 fingerprint without fail.
5. Make sure all the dependencies are added properly.
Conclusion
In this article, we can learn how to check similar words and sentences using Text Embedding feature of Huawei ML Kit. This Huawei ML Kit provides Text Embedding feature which helps to get matching vector value of words or sentences. Using this feature, we can improve our research based on the result. It provides similarity between two words or sentences and similar words of a particular word searched. We can also improve searching and browsing efficiency using after getting results related to search text.
I hope you have read this article. If you found it is helpful, please provide likes and comments.
Reference
ML Kit – Text Embedding
ML Kit – Training Video

Categories

Resources