How to build an Android Quiz App from a Scratch?

In this build mobile app development tutorial, I am going to share you how to build an android mobile quiz app from scratch. We will be learning the Model, Utility, and Quiz App classes along with learning the usages of various android Java packages. Also, the source code for the android app tutorial is included.

 

app-development-tutorial

Get the Android Quiz App Development Ideas from RabinsXP.

 

Android App Development

I assume that you are already familiar with Java language and somehow know a little of bit of Android Studio or Eclipse or has any working experience with Netbeans. If you don’t know anything about JAVA then you will not be knowing things properly.

However, there is no harm in learning new things. Before we actually write a code we need to understand how this application gonna works. I will be talking about needs in the code point of view.

Library Dependencies

The And Quiz App I’m gonna share you here will have android dependencies like:

  • AppCompatActivity – It provides Material color themes, widget tinting, and app bar support to earlier devices. Use of this class requires that you use Theme.AppCompat themes for consistent visual presentation.
  • Google Play Services – The Google Play services library includes utility methods that help you determine whether or not the Google Play services version on the device supports the version of the client library you are using.

Coding Procedure

I’m calling it a coding procedure but you can call it development strategy too. Why so? Because I’m gonna write this app in such a manner a new in Android guy will easily understand. This is how I divide the app coding process in three ways or say 3 modules.

  1. Model
  2. Utility
  3. Quiz App

1. Model

Inside the Model, we will first create two methods — Image and ImageItem. The second class file or ImageItem will be extended from the first class ie. Image.

1.1 Image Class:  We will be using the  Parcelable (i.e android.os.Parcelable) as we know we cannot just pass objects to activities. In Android, the objects must be either implement a Serializable or Parcelable interface to do this. In the Image class, we will perform the following things after extending the Parcelable.

  • getTitle()
  • getDescription()
  • getPath()
  • getThumbPath()

Here’s the above in code.

public interface Image extends Parcelable {
public String getTitle();
public String getDescription();
public String getPath();
public String getThumbPath();
}

1.2 ImageItem Class: In this class, we will importing public final class Parcel (i.e android.os.Parcel) and implementing the Image class. In this class, we will be performing the following things after we implement Image class and mentioning private String nameprivate String description, and private String path.

  • ImageItem()
  • ImageItem(String name, String description, String path)
  • getName()
  • setName(String name)
  • setDescription(String description)
  • setPath(String path)

Here’s the above in code.

public ImageItem() {
        super();
    }

    public ImageItem(String name, String description, String path) {
        super();
        this.name = name;
        this.description = description;
        this.path = path;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public void setPath(String path) {
        this.path = path;
    }

Now we will overide the Image Interface inside the same class.

  • getTitle() – don’t forget to return name.
  • getThumbPath – don’t forget to retun null.
  • getDescription() – don’t forget to retun description.
  • getPath() – don’t forget to retun path.

See the above in code.

@Override
    public String getTitle() {

        return name;
    }

    @Override
    public String getThumbPath() {

        return null;
    }

    @Override
    public String getDescription() {
        return description;
    }

    @Override
    public String getPath() {
        return path;
    }

Now comes the Parcelable Interface.

  • ImageItem(Parcel in)
  • readFromParcel(Parcel in) – Read from parcel.  // param in the ‘in’
  • describeContents()
  • writeToParcel(Parcel dest, int flags)

Finally, the Constant creator.

@SuppressWarnings("rawtypes")
    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
        public ImageItem createFromParcel(Parcel in) {
            return new ImageItem(in);
        }
        public ImageItem[] newArray(int size) {
            return new ImageItem[size];
        }
    };

2. Utility

In the Utility has a helper class that has only static methods and encapsulates no state. Here, I’m going to use ‘MenuFuctions‘ as a utility class or a helper method.

2.1 MenuFuctions Class: In this class, we will be importing the following packages.

  1. ActivityNotFoundException – This exception is thrown when a call to startActivity(Intent) or one of its variants fails because an Activity cannot be found to execute the given Intent.
  2. Context – Interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.
  3. Intent – An intent is an abstract description of an operation to be performed. It can be used with startActivity to launch an Activity, broadcastIntent to send it to any interested BroadcastReceiver components, and startService(Intent) or bindService(Intent, ServiceConnection, int) to communicate with a background Service.An Intent provides a facility for performing late runtime binding between the code in different applications. Its most significant use is in the launching of activities, where it can be thought of as the glue between activities. It is basically a passive data structure holding an abstract description of an action to be performed.
  4. Uri (Android) – Immutable URI reference. A URI reference includes a URI and a fragment, the component of the URI following a ‘#’. Builds and parses URI references which conform to RFC 2396.In the interest of performance, this class performs little to no validation. Behavior is undefined for invalid input. This class is very forgiving–in the face of invalid input, it will return garbage rather than throw an exception unless otherwise specified.
  5. Toast – A toast is a view containing a quick little message for the user. The toast class helps you create and show those. When the view is shown to the user, appears as a floating view over the application. It will never receive focus. The user will probably be in the middle of typing something else. The idea is to be as unobtrusive as possible, while still showing the user the information you want them to see. Two examples are the volume control, and the brief message saying that your settings have been saved.The easiest way to use this class is to call one of the static methods that construct everything you need and returns a new Toast object.

Inside the MenuFunction Class, we will try Google Play. The code will look like this.

public class MenuFunctions {

    public static boolean openMore(Context context){

        Intent intent = new Intent(Intent.ACTION_VIEW);
        //Try Google play
        intent.setData(Uri.parse("market://developer?id=" + context.getResources().getString(R.string.developer)));
        if (MyStartActivity(intent, context) == false) {
            //Market (Google play) app seems not installed, let's try to open a webbrowser
            intent.setData(Uri.parse("https://play.google.com/store/apps/developer?id="+context.getResources().getString(R.string.developer)));
            if (MyStartActivity(intent, context) == false) {
                //Well if this also fails, we have run out of options, inform the user.
                Toast.makeText(context, "Could not open Android market, please install the market app.", Toast.LENGTH_SHORT).show();
            }
        }
        return true;
    }

    private static boolean MyStartActivity(Intent aIntent, Context context) {
        try
        {
            context.startActivity(aIntent);
            return true;
        }
        catch (ActivityNotFoundException e)
        {
            return false;
        }
    }
}

3. Quiz App

We further divide the Quiz App into three main Classes. Here we gonna say as:

3.1 HomeActivity Class – In this class we gonna wanna import the following packages.

  1. MenuFunctions – This is just the helper or utility class we created earlier inside the Utils ie.
  2. ImageItem – Similar to the above, we had created an ImageItem classed inside the Model.
  3. Activity – An activity is a single, focused thing that the user can do. Almost all activities interact with the user, so the Activity class takes care of creating a window for you in which you can place your UI with setContentView(View). While activities are often presented to the user as full-screen windows, they can also be used in other ways: as floating windows (via a theme with windowIsFloating set) or embedded inside of another activity (using ActivityGroup).
  4. Context (see 2.1 above)
  5. Intent (see 2.1 above)
  6. SharedPreferences – The SharedPreferences APIs allow you to read and write persistent key-value pairs of primitive data types: booleans, floats, ints, longs, and strings. The key-value pairs are written to XML files that persist across user sessions, even if your app is killed. You can manually specify a name for the file or use per-activity files to save your data. The API name “shared preferences” is a bit misleading because the API is not strictly for saving “user preferences,” such as what ringtone a user has chosen. You can use SharedPreferences to save any kind of simple data, such as the user’s high score.
  7. Drawable – A Drawable is a general abstraction for “something that can be drawn.” Most often you will deal with Drawable as the type of resource retrieved for drawing things to the screen; the Drawable class provides a generic API for dealing with an underlying visual resource that may take a variety of forms. Unlike a View, a Drawable does not have any facility to receive events or otherwise interact with the user.
  8. AppCompatActivity (ActionBarActivity is now deprecated) –  Base class for activities that use the support library action bar features. You can add an ActionBar to your activity when running on API level 7 or higher by extending this class for your activity and setting the activity theme to Theme.AppCompat or a similar theme.
  9.  Bundle – A mapping from String keys to various Parcelable values.
  10. KeyEvent – Object used to report key and button events.
  11. Menu –  Interface for managing the items in a menu. By default, every Activity supports an options menu of actions or options. You can add items to this menu and handle clicks on your additions. The easiest way of adding menu items is inflating an XML file into the Menu via MenuInflater. The easiest way of attaching code to clicks is via onOptionsItemSelected(MenuItem) and onContextItemSelected(MenuItem).
  12. MenuItem – Interface for direct access to a previously created menu item. An Item is returned by calling one of the add(int) methods.
  13. View – This class represents the basic building block for user interface components. A View occupies a rectangular area on the screen and is responsible for drawing and event handling. The ‘View’ is the base class for widgets, which are used to create interactive UI components (buttons, text fields, etc.). The ViewGroup subclass is the base class for layouts, which are invisible containers that hold other Views (or other ViewGroups) and define their layout properties.
  14. ImageView – Displays image resources, for example, Bitmap or Drawable resources. ImageView is also commonly used to apply tints to an image and handle image scaling.
  15. ProgressBar – A user interface element that indicates the progress of an operation. Progress bar supports two modes to represent progress: determinate, and indeterminate. For a visual overview of the difference between determinate and indeterminate progress modes, see Progress & activity. Display progress bars to a user in a non-interruptive way. Show the progress bar in your app’s user interface or in a notification instead of within a dialog
  16. RelativeLayout – A Layout where the positions of the children can be described in relation to each other or to the parent. Note that you cannot have a circular dependency between the size of the RelativeLayout and the position of its children. For example, you cannot have a RelativeLayout whose height is set to WRAP_CONTENT and a child set to ALIGN_PARENT_BOTTOM.
  17. TextView – A user interface element that displays text to the user.
  18. IOException – Signals that an I/O exception of some sort has occurred. This class is the general class of exceptions produced by failed or interrupted I/O operations.
  19. InputStream – This abstract class is the superclass of all classes representing an input stream of bytes. Applications that need to define a subclass of InputStream must always provide a method that returns the next byte of input.
  20. ArrayList – Resizable-array implementation of the List interface. Implements all optional list operations, and permits all elements, including null. In addition to implementing the List interface, this class provides methods to manipulate the size of the array that is used internally to store the list. (This class is roughly equivalent to Vector, except that it is unsynchronized.)

Also, if we wanna include Ad-mob, we can AdListener, AdRequest or InterstitialAd depending on our choice.

What we gonna add to the HomeActivity Class? We can add whatever we like to add. But for now, we gonna add the following features.

  1. Better Life
  2. Player High Score
  3. Restore preferences
  4. Set difficulty level
  5. Set the date of the first launch
  6. List images and from the images array
  7. Handler to update UI after the backend thread
  8. XP
  9. Pick a random number for the home background
  10. Get input stream
  11. Load image as Drawable
  12. Set image to ImageView

Since some of us gonna add Admob ads too, we gonna include the followings too.

  1. Create the interstitial
  2. Create an Ad request
  3. Begin loading your interstitial
  4. Extra Difficulty
  5. Invoke displayInterstitial() when you are ready to display an interstitial

Now lets us perform some overrides.

  1. We override the back button and may display AdMob Full-Screen Ad.
  2. Inflate the menu; this adds items to the action bar if it is present.
  3. Handle action bar item clicks here. The action bar will automatically handle clicks on the Home/Up button, so long as you specify a parent activity in AndroidManifest.xml.

Here is the complete source code of HomeActivity Class file.

public class HomeActivity extends Activity {

    public static final String PREFS_NAME = "better_life" ;
    public static final String PREFS_HIGH_SCORE = "playerHighScore" ;

    TextView startTV;
    TextView highScoreTV;
    TextView homeTV;
    ImageView mainBackgroundIV;

    SharedPreferences storage;

    RelativeLayout mainLayout;

    public static ArrayList images;

    static int difficulty;

    public static int playerHighScore=0;

    private InterstitialAd interstitial;

    Context context = this;

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

        mainLayout = (RelativeLayout) findViewById(R.id.home_main_activity_layout);
        startTV = (TextView) findViewById(R.id.home_start_text_view);
        highScoreTV = (TextView) findViewById(R.id.home_high_score_text_view);
        homeTV = (TextView) findViewById(R.id.home_more_text_view);
        mainBackgroundIV = (ImageView) findViewById(R.id.home_background_image);

        // Restore preferences
        storage = getSharedPreferences(PREFS_NAME, MODE_MULTI_PROCESS);
        SharedPreferences.Editor editor = storage.edit();

        //set difficulty
        difficulty = Integer.parseInt(getString(R.string.difficulty_index));

        initAdmobInterstitial();

        // Set the date of the first launch
        Long firstLaunchDate = storage.getLong("firstLaunchDate", 0);
        if (firstLaunchDate == 0) {
            firstLaunchDate = System.currentTimeMillis();
            editor.putLong("firstLaunchDate", firstLaunchDate);
            editor.commit();
        }

        ImageItem img;

        images = new ArrayList();

        //list images and them to the images array
        try {
            String[] files = getAssets().list("aimages");
            for (String file : files) {
                img = new ImageItem();
                //i3.setName("Love");
                String[] parts = file.split("\\.");
                img.setName(parts[0].replaceAll("-", " "));
                img.setPath("aimages/"+file);
                images.add(img);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }


        //Handler to update UI after the backend thread

        playerHighScore = storage.getInt(PREFS_HIGH_SCORE, 0);

        highScoreTV.setText(String.valueOf(playerHighScore * 1000) + "XP");

        startTV.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                initNewGame();

            }
        });

        homeTV.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MenuFunctions.openMore(context);
            }
        });


        //picks a random number for the home background
        int randomBackground = 0 + (int)(Math.random() * ((images.size() - 1) + 1));

        try
        {
            // get input stream
            InputStream ims = getAssets().open(images.get(randomBackground).getPath());
            // load image as Drawable
            Drawable d = Drawable.createFromStream(ims, null);
            // set image to ImageView
            mainBackgroundIV.setImageDrawable(d);
        }
        catch(IOException ex)
        {
            return;
        }
    }

    private void initAdmobInterstitial(){
        // Create the interstitial.
        interstitial = new InterstitialAd(this);
        interstitial.setAdUnitId(getString(R.string.admob_challenge_interstitial));

        // Create ad request.
        AdRequest adRequest = new AdRequest.Builder().build();

        // Begin loading your interstitial.
        interstitial.loadAd(adRequest);
        interstitial.setAdListener(new AdListener() {
            @Override
            public void onAdClosed() {
                super.onAdClosed();
                finish();
            }

            @Override
            public void onAdFailedToLoad(int errorCode) {
                super.onAdFailedToLoad(errorCode);
            }
        });
    }
    // Invoke displayInterstitial() when you are ready to display an interstitial.
    public void displayInterstitial() {
        if (interstitial.isLoaded()) {
            interstitial.show();
        }
    }

    private void initNewGame(){

        Intent challengeIntent = new Intent(this , ChallengeActivity.class);
        challengeIntent.putExtra("EXTRA_DIFFICULTY", difficulty);

        this.startActivity(challengeIntent);

    }

    /**
     * Override the back button
     */
    @Override
    public boolean onKeyDown(final int keyCode, final KeyEvent event)
    {
        if (keyCode== KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0)
        {

            if(!getString(R.string.admob_challenge_interstitial).equals("")){
                //RevMob Full Screen Ad
                displayInterstitial();
            }
            // return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.home, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

3.2 Challange Class – In this class, we gonna wanna import all of the packages from the HomeActivity Class and add the following packages too.

  1. AlertDialog – The AlertDialog class takes care of automatically setting WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM for you based on whether any views in the dialog return true from View.onCheckIsTextEditor(). Generally, you want this set for a Dialog without text editors so that it will be placed on top of the current input method UI. You can modify this behavior by forcing the flag to your desired mode after calling onCreate(Bundle).
  2. DialogInterface – Interface that defines a dialog-type class that can be shown, dismissed, or canceled, and may have buttons that can be clicked.
  3. Color – The Color class provides methods for creating, converting and manipulating colors.
  4. CountDownTimer – Schedule a countdown until a time in the future, with regular notifications on intervals along the way.
  5. Handler – A Handler allows you to send and process Message and Runnable objects associated with a thread’s MessageQueue. Each Handler instance is associated with a single thread and that thread’s message queue. When you create a new Handler, it is bound to the thread/message queue of the thread that is creating it — from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
  6. Log – API for sending log output. Generally, you should use the Log.v(), Log.d(), Log.i(), Log.w(), and Log.e() methods to write logs. You can then view the logs in logcat.
  7. Collections – The java.util.Collections class consists exclusively of static methods that operate on or return collections.
  8. List – An ordered collection (also known as a sequence). The user of this interface has precise control over where in the list each element is inserted. The user can access elements by their integer index (position in the list), and search for elements in the list.
    Unlike sets, lists typically allow duplicate elements. More formally, lists typically allow pairs of elements e1 and e2 such that e1.equals(e2), and they typically allow multiple null elements if they allow null elements at all. It is not inconceivable that someone might wish to implement a list that prohibits duplicates, by throwing runtime exceptions when the user attempts to insert them, but we expect this usage to be rare.
  9. Random – It is used to generate pseudo-random numbers in java. The instance of this class is thread-safe. The instance of this class is however cryptographically insecure. This class provides various method call to generate different random data types such as float, double, int.

What we gonna add to the ChallengeActivity Class? We can add whatever we like to add. But for now, we gonna add the following features.

  1. Quiz App
  2. Extra Difficulty
  3. Default button color.
  4. Get the default background color.
  5. Randomize the order of the images in the array.
  6. Create the interstitial.
  7. Create Ad request.
  8. Begin loading your interstitial.
  9. Invoke displayInterstitial() when you are ready to display an interstitial.
  10. Get All the file names in an array.
  11. Override the back button and may display Ad-Mob Full-Screen Ad.
  12. Pick a random number for the answer.
  13. Create an array of answers from file names.
  14. Get 3 random answers and add it to the array.
  15. Get input stream.
  16. Load image as Drawable.
  17. Set image to ImageView
  18. Show the dialog or buttons for the correct answer to be pressed.

Now lets us perform some overrides just like we did above.

  1. We override the back button and may display AdMob Full-Screen Ad.
  2. Extra Player Score
  3. Extra Timer Count
  4. Extra Timer Time
  5. Inflate the menu; this adds items to the action bar if it is present.
  6. Handle action bar item clicks here. The action bar will automatically handle clicks on the Home/Up button, so long as you specify a parent activity in AndroidManifest.xml.

The full source code for ChallangeActivity Class is shown below:

public class ChallengeActivity extends Activity {

    public final String TAG = "QuizApp";

    ImageView mainIV;

    private InterstitialAd interstitial;

    public static ArrayList imagesShuffled;

    int correctAnswer;

    int currentQuestion;

    TextView btn1;
    TextView btn2;
    TextView btn3;
    TextView btn4;

    TextView timerTV;
    TextView scoreTV;

    //default button color
    Drawable d;

    int playerScore = 0;

    CountDownTimer timer;
    int timerCount = 0;
    int timerTime = 0;

    int difficulty;

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

        Bundle extras = getIntent().getExtras();
        if (extras != null) {
            difficulty = extras.getInt("EXTRA_DIFFICULTY");
        }

        mainIV = (ImageView) findViewById(R.id.main_image_view);
        btn1 = (TextView) findViewById(R.id.choice_button_1);
        btn2 = (TextView) findViewById(R.id.choice_button_2);
        btn3 = (TextView) findViewById(R.id.choice_button_3);
        btn4 = (TextView) findViewById(R.id.choice_button_4);


        timerTV = (TextView) findViewById(R.id.timer_text_view);
        scoreTV = (TextView) findViewById(R.id.score_text_view);

        //Get the default background color
        d = btn1.getBackground();

        btn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                submitAnswer(0);
            }
        });

        btn2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                submitAnswer(1);
            }
        });

        btn3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                submitAnswer(2);
            }
        });


        btn4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                submitAnswer(3);
            }
        });



        imagesShuffled = new ArrayList(HomeActivity.images);

        //Randomize the order of the images in the array
        long seed = System.nanoTime();
        Collections.shuffle(imagesShuffled, new Random(seed));


        timerTime = (3/difficulty) * 1000 * imagesShuffled.size();

        initAdmobInterstitial();

        startQuiz();

    }

    private void initAdmobInterstitial(){
        // Create the interstitial.
        interstitial = new InterstitialAd(this);
        interstitial.setAdUnitId(getString(R.string.admob_challenge_interstitial));

        // Create ad request.
        AdRequest adRequest = new AdRequest.Builder().build();

        // Begin loading your interstitial.
        interstitial.loadAd(adRequest);

    }


    // Invoke displayInterstitial() when you are ready to display an interstitial.
    public void displayInterstitial() {
        if (interstitial.isLoaded()) {
            interstitial.show();
        }
    }


    @Override
    protected void onPause() {
        timer.cancel();
        super.onPause();

    }


    @Override
    protected void onResume() {
        super.onResume();
        timer.cancel();
        startTimer(timerTime - (timerCount*1000));
    }

    public void startQuiz(){

        //Get All the file names in an array
        currentQuestion = 0;
        createQuestion();
        startTimer(timerTime);

    }


    public void  startTimer(int time){
        timer = new CountDownTimer(time, 1000) {

            public void onTick(long millisUntilFinished) {
                timerTV.setText(getString(R.string.timer_text) +" "+ millisUntilFinished / 1000);
                timerCount++;
            }

            public void onFinish() {
                timerTV.setText("done!");
                resultsPage();
            }
        }.start();
    }

    /**
     * Override the back button
     */
    @Override
    public boolean onKeyDown(final int keyCode, final KeyEvent event)
    {
        if (keyCode== KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0)
        {

            if(!getString(R.string.admob_challenge_interstitial).equals("")){
                //RevMob Full Screen Ad
                displayInterstitial();
                timer.cancel();
                finish();

            }
            // return true;
        }
        return super.onKeyDown(keyCode, event);
    }


    private void createQuestion(){

        int randomFileIndex;

        if(currentQuestion%10 == 0 && interstitial.isLoaded()){
            displayInterstitial();
            initAdmobInterstitial();
        }

        //picks a random number for the answer
        correctAnswer = 0 + (int)(Math.random() * ((3 - 0) + 1));

        //create an array of answers from file names
        ArrayList answers = new ArrayList();
        List categoryList = new ArrayList();

        for (int subArrayFlag = 0; subArrayFlag < imagesShuffled.size();subArrayFlag++){
            if(imagesShuffled.get(currentQuestion).getName().substring(0,1)
                    .equalsIgnoreCase(imagesShuffled.get(subArrayFlag).getName().substring(0, 1))){
                categoryList.add(subArrayFlag);

            }
        }

        //get 3 random answers and add it to the array
        for (int i = 0 ; i < 4 ;i++ ){ if (i == correctAnswer){ answers.add(imagesShuffled.get(currentQuestion).getName()); }else { do { randomFileIndex = (int) (Math.random() * categoryList.size()); } while ( categoryList.get(randomFileIndex) == currentQuestion && categoryList.size() > 0 );

                answers.add(imagesShuffled.get(categoryList.get(randomFileIndex)).getName());
            }

        }


        try
        {
            // get input stream
            InputStream ims = getAssets().open(imagesShuffled.get(currentQuestion).getPath());
            // load image as Drawable
            Drawable d = Drawable.createFromStream(ims, null);
            // set image to ImageView
            mainIV.setImageDrawable(d);
        }
        catch(IOException ex)
        {
            return;
        }

        btn1.setText(answers.get(0).substring(2));
        btn2.setText(answers.get(1).substring(2));
        btn3.setText(answers.get(2).substring(2));
        btn4.setText(answers.get(3).substring(2));

        btn1.setBackgroundDrawable(d);
        btn2.setBackgroundDrawable(d);
        btn3.setBackgroundDrawable(d);
        btn4.setBackgroundDrawable(d);
    }

    private void submitAnswer(int answer){


        if(answer == correctAnswer){
            currentQuestion++;
            playerScore++;

            if (currentQuestion == imagesShuffled.size()){
                //Show the dialog
                resultsPage();

            }else{

                switch (answer) {
                    case 0:
                        btn1.setBackgroundColor(Color.GREEN);
                        break;
                    case 1:
                        btn2.setBackgroundColor(Color.GREEN);
                        break;
                    case 2:
                        btn3.setBackgroundColor(Color.GREEN);
                        break;
                    case 3:
                        btn4.setBackgroundColor(Color.GREEN);
                        break;
                }

                final int finalAnswer = answer;

                // SLEEP 2 SECONDS HERE ...
                Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    public void run() {
//                        if (currentQuestion%2 == 0){
//                            displayInterstitial();
//
//                        }


                        createQuestion();
                    }
                }, 500);

            }
        }else{
            playerScore--;
            switch (answer) {
                case 0:
                    btn1.setBackgroundColor(Color.RED);
                    break;
                case 1:
                    btn2.setBackgroundColor(Color.RED);
                    break;
                case 2:
                    btn3.setBackgroundColor(Color.RED);
                    break;
                case 3:
                    btn4.setBackgroundColor(Color.RED);
                    break;
                default:
                    break;
            }

        }

        scoreTV.setText(getString(R.string.score_text)+playerScore);


    }


    private void resultsPage(){

        String msg = "";

        currentQuestion = 0;

        if(timerTime > timerCount){
            msg = "Congrats!";
        }

        timer.cancel();

        Intent resultIntent = new Intent(this , ResultsActivity.class);
        resultIntent.putExtra("EXTRA_PLAYER_SCORE", playerScore);
        resultIntent.putExtra("EXTRA_TIMER_COUNT", timerCount);
        resultIntent.putExtra("EXTRA_TIMER_TIME", timerTime);

        this.startActivity(resultIntent);

        finish();
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.home, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

3.3 ResultsActivity Class – In this class, we gonna wanna import all of the packages from the HomeActivity Class excluding ActionBarActivity and ImageItem.

What we gonna add to the ResultsActivity Class? We can add whatever we like to add. But for now, we gonna add the following features.

  1. Extra Player Score
  2. Extra Timer Count
  3. Extra Timer Time
  4. Get Input Stream
  5. Load image as Drawable
  6. Set image to ImageView
  7. XP
  8. Show interstitial and close the app. // Anything can be added to this Menu Functions
  9. Add store listing. // Anything can be added to this Menu Functions
  10. Create the interstitial.
  11. Create Ad request.
  12. Begin loading your interstitial.
  13. Invoke displayInterstitial() when you are ready to display an interstitial.
  14. Extra Difficulty
  15. We override the back button and may display AdMob Full-Screen Ad.
  16. Inflate the menu; this adds items to the action bar if it is present.
  17.  Handle action bar item clicks here. The action bar will automatically handle clicks on the Home/Up button, so long as you specify a parent activity in AndroidManifest.xml.

The full source code for ResultActivity Class is shown below:

public class ResultsActivity extends Activity {

    RelativeLayout resultLL;

    TextView retryBT;
    TextView moreBT;
    TextView titleTV;
    TextView descriptionTV;
    TextView levelTV;
    TextView scoreTV;
    TextView highScoreTV;

    ImageView backgroundIV;

    int playerScore;
    int timerTime;
    int timerCount;

    private InterstitialAd interstitial;

    Context context = this;


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

        Bundle extras = getIntent().getExtras();
        if (extras != null) {
            playerScore = extras.getInt("EXTRA_PLAYER_SCORE");
            timerTime = extras.getInt("EXTRA_TIMER_TIME");
            timerCount = extras.getInt("EXTRA_TIMER_COUNT");
        }

        resultLL = (RelativeLayout) findViewById(R.id.result_layout);
        retryBT = (TextView) findViewById(R.id.retry_text_view);
        moreBT = (TextView) findViewById(R.id.exit_text_view);


        titleTV = (TextView) findViewById(R.id.result_title_text_view);
        descriptionTV = (TextView) findViewById(R.id.description_text_view);
        levelTV = (TextView) findViewById(R.id.level_text_view);
        scoreTV = (TextView) findViewById(R.id.current_score_text_view);
        highScoreTV = (TextView) findViewById(R.id.highest_score_text_view);

        backgroundIV = (ImageView) findViewById(R.id.result_background_image);

        initAdmobInterstitial();


        SharedPreferences storage =
                this.getSharedPreferences(HomeActivity.PREFS_NAME, Context.MODE_MULTI_PROCESS );
        SharedPreferences.Editor editor = storage.edit();

        int highestScore = storage.getInt(HomeActivity.PREFS_HIGH_SCORE, 0);

        if(playerScore > highestScore){
            titleTV.setText(R.string.new_record);
            editor.putInt(HomeActivity.PREFS_HIGH_SCORE, playerScore );
            editor.commit();
        }else{
            titleTV.setText(R.string.not_as_good);
        }


        if (playerScore > 0){
            levelTV.setText(HomeActivity.images.get((playerScore - 1)).getName().substring(2));


            try
            {
                // get input stream
                InputStream ims = getAssets().open(HomeActivity.images.get(playerScore-1).getPath());
                // load image as Drawable
                Drawable d = Drawable.createFromStream(ims, null);
                // set image to ImageView
                backgroundIV.setImageDrawable(d);
            }
            catch(IOException ex)
            {
                return;
            }

        }else{
            titleTV.setText(getString(R.string.not_good_enough_text));
            levelTV.setText(R.string.negative_score_description);
            descriptionTV.setText("");
        }



        scoreTV.setText(String.valueOf(playerScore * 1000) + "XP");
        highScoreTV.setText("Best\n" + String .valueOf(highestScore * 1000) + "XP");

        retryBT.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (interstitial.isLoaded()){
                    displayInterstitial();
                }else{
                    initNewGame();
                }


            }
        });

        moreBT.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {


                MenuFunctions.openMore(context);
                //Show interestitial and close the app
                //TODO: Add store listing here
            }
        });



    }


    private void initAdmobInterstitial(){
        // Create the interstitial.
        interstitial = new InterstitialAd(this);
        interstitial.setAdUnitId(getString(R.string.admob_challenge_interstitial));

        // Create ad request.
        AdRequest adRequest = new AdRequest.Builder().build();

        // Begin loading your interstitial.
        interstitial.loadAd(adRequest);

        interstitial.setAdListener(new AdListener() {
            @Override
            public void onAdClosed() {
                super.onAdClosed();
                initNewGame();
            }



        });
    }


    // Invoke displayInterstitial() when you are ready to display an interstitial.
    public void displayInterstitial() {
        if (interstitial.isLoaded()) {
            interstitial.show();
        }
    }


    private void initNewGame(){

        Intent challengeIntent = new Intent(this , ChallengeActivity.class);
        challengeIntent.putExtra("EXTRA_DIFFICULTY", HomeActivity.difficulty);

        this.startActivity(challengeIntent);
        finish();

    }


    /**
     * Override the back button
     */
    @Override
    public boolean onKeyDown(final int keyCode, final KeyEvent event)
    {
        if (keyCode== KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0)
        {

            if(!getString(R.string.admob_challenge_interstitial).equals("")){
                //RevMob Full Screen Ad
                displayInterstitial();
            }
            // return true;
        }
        return super.onKeyDown(keyCode, event);
    }




    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.results, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

Conclusion: Now we know how to code for Model and Utility helper class and also the necessary Quiz App Activities classes. This concludes the end of an Android Mobile Quiz App Development.

In the next series, I’m gonna share the assets, drawable, layout and values for the very Android Quiz App.

If you like this and find useful, then don’t forget to like and share. 🙂

Rabins Sharma Lamichhane

Rabins Sharma Lamichhane is senior ICT professional who talks about #it, #cloud, #servers, #software, and #innovation. Rabins is also the first initiator of Digital Nepal. Facebook: rabinsxp Instagram: rabinsxp

You may also like...

1 Response

  1. May 21, 2018

    […] How to build Android Quiz App? […]

Leave a Reply

Your email address will not be published. Required fields are marked *