Let's build an Android Quiz Application with Appwrite
Tags: android, opensource, tutorial, discuss
Published: 2021-07-09 11:20:45

## 🤔 What is Appwrite?
In case you’re new to Appwrite, Appwrite is an new open-source, end-to-end, backend server for front-end and mobile developers that allows you to build apps much faster. Its goal is to abstract and simplify common development tasks behind REST APIs and tools, helping you to build advanced apps faster.

## 🤖 Appwrite for Android
Appwrite provides **sleek REST APIs** for various common features that are required for mobile application development such as a **database**, **storage**, **cloud functions**, **authentication** etc. so that we as a developer can focus on our application rather than on backend implementation. This makes Appwrite very suitable for those of us who want to build Android applications. And with the latest release, Appwrite now has an **official Android SDK** to make it even easier to use Appwrite in our Android applications. In this tutorial we'll build a simple android quiz application using Appwrite. So let's get started.

## 📝 Prerequisites
In order to continue with this tutorial, you need to have an Appwrite console that you can access and have permission to create a project or already have an existing project. If you have not already installed Appwrite, please do so. Installing Appwrite is really simple following Appwrite's official [installation docs](https://appwrite.io/docs/installation). Installation should be done in less than 2 minutes. Once installed login to your console and **create a new Project**.

## 💾 Setup Database
In the Appwrite console, let's select the project that we will be using for our Android app. If you don't have a project yet, you can easily create one by clicking on the **Create Project** button. Once inside, select **Database** from the left sidebar. Once on the database page click on the **Add Collection** button and inside the dialog set the collection name to **Questions** and then click the **Create** button. This will then create a collection and you will be redirected to the new collection's page where we can define rules for our collection. Define the following rules and click on the **Update** button.

- **Question**
    - label: Question
    - Key: question
    - Rule Type: Text
    - Required: true
    - Array: false
- **Options**
    - label: Options
    - Key: options
    - Rule Type: Text
    - Required: true
    - Array: true
- **Answer**
    - label: Answer
    - Key: answer
    - Rule Type: Text
    - Required: true
    - Array: false

![Questions Collection](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rliaqicn2z3b43afm2b1.png)
 

Now you can navigate to the **Documents** tab and using the **Add Document** button, add as many questions with options and answers as you like for your quiz application. Make sure to add a few questions so that we can easily fetch and build our quiz application in Android.

## ⚙️ Setup Android Project and Dependencies

Using Android Studio, create a new Android Application project choosing the **Empty Activity** template. Once the project is created, in your app's root level `build.gradle(.kts)` file,  add the `mavenCentral()` repository in order to fetch the Appwrite Android SDK.

```groovy
repositories {      
    mavenCentral()
}
```

Next, add the dependency to your app's `build.gradle(.kts)` file:

```groovy
implementation("io.appwrite:sdk-for-android:0.0.1")
```

## ➕️ Add Android Platform
To initialize your SDK and start interacting with Appwrite services, you need to add a new Android platform to your project. To add a new platform, go to your Appwrite console, select your project (create one if you haven't already), and click the 'Add Platform' button on the project Dashboard.

From the options, choose to add a new Android platform and add your app credentials.

Add your app name and package name. Your package name is generally the `applicationId` in your app-level `build.gradle` file. You may also find your package name in your `AndroidManifest.xml` file. By registering a new platform, you are allowing your app to communicate with the Appwrite API.

## ⚒️ Build Activity and Layout

Add new activity by going to `File>New>Activity>Empty Activity` and name it **QuizActivity**. This will create `QuizActivity.kt` and `activity_quiz.xml` files in their respective folders.

Now, open your `app/src/main/res/layout/activity_main.xml` and update the layout as following

```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"
    android:background="@color/darkslategray"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:fontFamily="sans-serif-medium"
        android:text="Demo Quiz With Android"
        android:textColor="@color/darkgray"
        android:textSize="24sp"
        app:layout_constraintBottom_toTopOf="@+id/btnPlay"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/btnPlay"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Play Now"
        style="@style/buttonStyle"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
```

Then, open `app/src/main/java/com/example/demoquizwithandroid/MainActivity.kt` and update the `onCreate` function like so:

```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val button = findViewById<Button>(R.id.btnPlay)
    button.setOnClickListener {
        val intent = Intent(this, QuizActivity::class.java)
        startActivity(intent)
    }
}
```

Now, open `app/src/main/res/layout/activity_quiz.xml` and update the layout to the following:

```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"
    android:padding="24dp"
    android:background="@color/darkslategray"
    tools:context=".QuizActivity">

    <TextView
        android:id="@+id/questionNumber"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="Question 5/15"
        android:textSize="32sp"
        android:textStyle="bold"
        android:textColor="@color/darkgray"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/dashedLine"
        android:layout_width="match_parent"
        android:layout_height="4dp"
        android:layout_marginTop="16dp"
        android:src="@drawable/dashed_line"
        app:layout_constraintTop_toBottomOf="@id/questionNumber"
        android:layerType="software" />

    <TextView
        android:id="@+id/question"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginTop="16dp"
        android:text="Question"
        android:textColor="@color/white"
        android:textSize="26sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toTopOf="@+id/options"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/dashedLine" />

    <RadioGroup
        android:id="@+id/options"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginBottom="24dp"
        app:layout_constraintBottom_toTopOf="@+id/btnNext"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">

        <RadioButton
            android:id="@+id/option1"
            style="@style/optionRadioButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Option 1"
            tools:layout_editor_absoluteX="116dp"
            tools:layout_editor_absoluteY="75dp" />

        <RadioButton
            android:id="@+id/option2"
            style="@style/optionRadioButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Option 2" />

        <RadioButton
            android:id="@+id/option3"
            style="@style/optionRadioButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Option 3" />

        <RadioButton
            android:id="@+id/option4"
            style="@style/optionRadioButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Option 4" />
    </RadioGroup>

    <Button
        android:id="@+id/btnNext"
        style="@style/buttonStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:text="Next"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
```

## 👩‍🔧 Create View Model

Create `app/src/main/java/com/example/demoquizwithandroid/QuizViewModel.kt` and update it with following code. Make sure to replace `YOUR_APPWRITE_ENDPOINT`, `YOUR_PROJECT_ID` and `YOUR_QUESTIONS_COLLECTION_ID` with your values which can all be found in your Appwrite console.

```kotlin
import android.content.Context
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import io.appwrite.Client
import io.appwrite.exceptions.AppwriteException
import io.appwrite.services.Database
import kotlinx.coroutines.launch
import org.json.JSONArray
import org.json.JSONObject

class QuizViewModel : ViewModel() {
    private val collectionId = "YOUR_QUESTIONS_COLLECTION_ID" // Replace with your own questions collection id that we created above
    private val db by lazy {
        Database(client)
    }
    private val _questions = MutableLiveData<JSONArray>().apply { value = null }
    lateinit var client : Client
    val questions: LiveData<JSONArray> = _questions;
    val selectedQuestion = MutableLiveData<Int>().apply { value = 0}
    val correct = MutableLiveData<Int>().apply { value = 0 }

    fun create(context: Context) {
        client = Client(context)
            .setEndpoint("YOUR_APPWRITE_ENDPOINT") // Replace with your own endpoint
            .setProject("YOUR_PROJECT_ID") // Replace with your project id
        getQuestions()
    }

    private fun getQuestions() {
        viewModelScope.launch {
            try {
                var response = db.listDocuments(collectionId)
                val json = response.body?.string() ?: ""
                var que = JSONObject(json)
                _questions.postValue( que["documents"] as JSONArray)
            } catch(e : AppwriteException) {
                Log.e("Get questions",e.message.toString())
            }
        }
    }
}
```

For this to work you also need to add following dependencies to your `app/build.gradle` file. These are the dependencies required for `LiveData` and `ViewModel` to work.

```groovy
dependencies{
    implementation 'androidx.appcompat:appcompat:1.3.0'
    implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
}
```

Finally update `app/src/main/java/com/example/demoquizwithandroid/QuizActivity.kt` with the following code and build your application

```kotlin
class QuizActivity : AppCompatActivity() {
    private lateinit var viewModel: QuizViewModel
    private var currentQuestion : JSONObject? = null;
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_quiz)
        viewModel = ViewModelProvider(this).get(QuizViewModel::class.java)
        viewModel.create(this)
        viewModel.questions.observe(this, {
            questions ->
            if(questions != null) {
                viewModel.selectedQuestion.observe(this, { index ->
                    findViewById<TextView>(R.id.questionNumber).text = "Question ${(index+1)}/${questions.length()}"
                    currentQuestion = questions[index] as JSONObject

                    val options = currentQuestion!!["options"] as JSONArray
                    findViewById<TextView>(R.id.question).text = currentQuestion!!["question"].toString()
                    findViewById<RadioButton>(R.id.option1).text = options[0].toString()
                    findViewById<RadioButton>(R.id.option2).text = options[1].toString()
                        val option3= findViewById<RadioButton>(R.id.option3)
                        val option4=findViewById<RadioButton>(R.id.option4)
                    if(options.length() > 2) {
                            option4.text = options[3].toString()
                            option3.text = options[2].toString()
                        option3.visibility = View.VISIBLE
                        option4.visibility = View.VISIBLE
                    } else {
                        option3.visibility = View.GONE
                        option4.visibility = View.GONE

                    }
                })
            }
        })
        findViewById<Button>(R.id.btnNext).setOnClickListener {
            _ -> onNextClicked()
        }
    }

    private fun onNextClicked() {
        if(currentQuestion == null) return
        val rbGroup : RadioGroup = findViewById<RadioGroup>(R.id.options)
        val rbSelected : RadioButton = findViewById(rbGroup.checkedRadioButtonId) ?: return
        val ans: String = rbSelected.text.toString();
        if (ans == currentQuestion!!["answer"].toString()) {
            viewModel.correct.postValue(viewModel.correct.value?.inc())
        }
        rbGroup.clearCheck()
        if(viewModel.selectedQuestion.value!! >= (viewModel.questions.value!!.length() - 1)) {
            //show complete dialog
            Log.d("Quiz complete","Quiz complete")
            val alertDialog = AlertDialog.Builder(this)
                .setTitle("Quiz complete")
                .setMessage("Score: ${viewModel.correct.value!!} / ${viewModel.questions.value!!.length()}")
                .setNeutralButton("Done", DialogInterface.OnClickListener { _, _ ->
                    val intent = Intent(this, MainActivity::class.java)
                        .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
                        .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                startActivity(intent)
            })
            alertDialog.show()
        } else {
            viewModel.selectedQuestion.postValue(viewModel.selectedQuestion.value?.inc())
        }
    }
}
```

We should now have our complete quiz application which should look as follows.

<p align="center">
   <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tlf2kxgkkvku2n0oco6l.png" width="300">
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e5h4c1pve8heu515nrc5.png" width="300"> 
</p>

## 🥂 Conclusion

I hope you enjoyed building this Quiz Application with Appwrite and Android. Let's us know if you have any feedback and suggestions. Can't wait for the community to build awesome apps with Appwrite and Android.

## 🎓 Learn More
- [Getting Started With Android](https://appwrite.io/getting-started-with-android)
- [Android Playground](https://github.com/appwrite/playground-for-android)
- [Demo Quiz Application](https://github.com/appwrite/demo-quiz-with-android)
- [Appwrite Docs](https://appwrite.io/docs)