Spinner Fragment: show loading progress bar
– Android TV app hands on Tutorial Appendix A

spinner fragment

In the Appendix of this Tutorial, I will introduce useful Android common library/function. These are usually applicable not only for Android TV, but also for Android phone/tablet device as well.

Spinner Fragment – show loading progress bar

While user is downloading big contents from web, you might want to show progress bar to notify user that some process (in this time downloading) is being done in background. It helps navigating user to wait this process.

Here, SpinnerFragment can be used to show circle arrow progress bar. Starting by making class by right click on “ui” package → [New] → [Java Class] → put Name as “SpinnerFragment”.

This class is a subclass of Fragment, and it is just making ProgressBar in onCreateView

package com.corochann.androidtvapptutorial.ui;

import android.app.Fragment;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ProgressBar;

/**
 * SpinnerFragment shows spinning progressbar to notify user that
 * application is processing something (while downloading, or preparing sth etc.)
 *
 * Example of usage in AsyncTask
 * + Start showing: OnPreExecute
 *         mSpinnerFragment = new SpinnerFragment();
 *         getFragmentManager().beginTransaction().add(R.id.some_view_group, mSpinnerFragment).commit();
 * + Stop showing: OnPostExecute
 *         getFragmentManager().beginTransaction().remove(mSpinnerFragment).commit();
 */
public class SpinnerFragment extends Fragment {

    private static final String TAG = SpinnerFragment.class.getSimpleName();

    private static final int SPINNER_WIDTH = 100;
    private static final int SPINNER_HEIGHT = 100;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        ProgressBar progressBar = new ProgressBar(container.getContext());
        if (container instanceof FrameLayout) {
            FrameLayout.LayoutParams layoutParams =
                    new FrameLayout.LayoutParams(SPINNER_WIDTH, SPINNER_HEIGHT, Gravity.CENTER);
            progressBar.setLayoutParams(layoutParams);
        }
        return progressBar;
    }
}

Usage of Spinner Fragment – AsyncTask

Put button in MainFragment

To introduce the usage of SpinnerFragment, make button to show this Fragment. I will make “Spinner” button in MainFragment.

public class MainFragment extends BrowseFragment {
    ...
    private static final String GRID_STRING_SPINNER = "Spinner";

    ...

    private void loadRows() {
        mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());

        /* GridItemPresenter */
        HeaderItem gridItemPresenterHeader = new HeaderItem(0, "GridItemPresenter");

        GridItemPresenter mGridPresenter = new GridItemPresenter();
        ArrayObjectAdapter gridRowAdapter = new ArrayObjectAdapter(mGridPresenter);
        gridRowAdapter.add(GRID_STRING_ERROR_FRAGMENT);
        gridRowAdapter.add(GRID_STRING_GUIDED_STEP_FRAGMENT);
        gridRowAdapter.add(GRID_STRING_RECOMMENDATION);
        gridRowAdapter.add(GRID_STRING_SPINNER);
        mRowsAdapter.add(new ListRow(gridItemPresenterHeader, gridRowAdapter));

        ...

        /* Set */
        setAdapter(mRowsAdapter);
    }

    ...
    private final class ItemViewClickedListener implements OnItemViewClickedListener {
        @Override
        public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
                                  RowPresenter.ViewHolder rowViewHolder, Row row) {

                ...
                } else if (item == GRID_STRING_SPINNER) {
                   // Show SpinnerFragment, while doing some is executed.
                   new ShowSpinnerTask().execute();
                }
            }
        }
    }

After click “Spinner” button, ShowSpinnerTask starts, which is explained following. 

AsyncTask implementation

Use case of SpinnerFragment is when something is processed in background, and AsyncTask is a one popular choice to do something in background.

Below, ShowSpinnerTask is introduced as a innerclass of MainFragment. It is mock example how to use SpinnerFragment. SpinnerFragment is added to the MainFragment before background process starts (onPreExecute), and removed after background process finishes (onPostExecute). This add and remove is done by using FragmentManager.

Adding and removing SpinnerFragment is enough. We don’t need to specify any animation, and UI update process during the background process is required.

In the first argument of add method, we need to specify an layout id of ViewGroup to attach SpinnerFragment. In this example main_browse_fragment is used.

    private class ShowSpinnerTask extends AsyncTask<Void, Void, Void> {
        SpinnerFragment mSpinnerFragment;

        @Override
        protected void onPreExecute() {
            mSpinnerFragment = new SpinnerFragment();
            getFragmentManager().beginTransaction().add(R.id.main_browse_fragment, mSpinnerFragment).commit();
        }

        @Override
        protected Void doInBackground(Void... params) {
            // Do some background process here.
            // It just waits 5 sec in this Tutorial
            SystemClock.sleep(5000);
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            getFragmentManager().beginTransaction().remove(mSpinnerFragment).commit();
        }
    }

Build and run

When “Spinner” button is pressed, circle type progress bar will appear.

Source code is on github.

Refactoring source code construction
– Android TV app hands on Tutorial 14

Refactoring

I have explained Android TV specific UI implementations (sample source code referenced from Android TV sample application) through this tutorial. So I conclude this project by reorganizing the source code files. I did refactoring based on the role of each classes, and finished with below structure.

  • com.corochann.androidtvapptutorial
    • common – common functions. This module has no dependency of this application’s specific implementation so that you can “re-use” the code in other project as well.
      •  PlaybackController
      • Utils
    • data – the data set of “Model”
      • MovieProvider
    • model – “Model” part of MVP architecture
      • Movie
    • recommendation – Recommendation function part
      • RecommendationBuilder
      • RecommendationFactory
    • ui – UI handling modules (Activity & Fragments)
      • MainActivity & MainFragment
      • DetailsActivity & VideoDetailsFragment
      • PlaybackOverlayActivity & PlaybackOverlayFragment
      • SearchActivity & SearchFragment
      • ErrorActivity & ErrorFragment
      • GuidedStepActivity
        • presenter – “Presenter” part of MVP architecture
          • CardPresenter
          • (GridItemPresenter) * It is defined in MainFragment, but you may move to here.
          • DescriptionPresenter
          • DetailsDescriptionPresenter
        • view – “View” part of MVP architecture
          •  Nothing in this Tutorial. Custom designed View came this place. For example, ImageCardView will be placed here, if it is not provided by Leanback support library.
        • background – The modules which handles background. It is also a commonly useful modules.
          • SimpleBackgroundManager
          • PicassoBackgroundManager

I continue little supplemental explanation below.

UI handling modules

At first, I want to differentiate the part which handles UI and doesn’t. The modules which is updating UI is the following,

  • ~Activity – Main component of constituting current Activity.
  • ~Fragment – Fragment supports UI of Activity by  filling up specific sub-component.
  • ~Presenter – Presenter defines how to show specific “item”, which is explained detail later.

Let’s make new package “ui” and replace above inside this package. It can be done by right click on package name → New → Package → type “ui”. Then new folder “ui” appears in your Android studio.

Model-View-Presenter (MVP) architectural pattern

Through this tutorial, we are using Movie class as a item to show, and we are displaying its instance with ImageCardView. It is achieved by the mediator CardPresenter which specifies how to show this Movie instance to ImageCardView.

This architecture is called Model-View-Presenter (MVP) architectural pattern. Model is the definition of item to handle it as “object” which is a base of Object Oriented Programming, View is the actual UI to show this item, and Presenter intermediates Model and View. 

In our case, we can write this correspondence.

ModelStringMovie
ViewTextViewImageCardView
PresenterGridItemPresenterCardPresenter

If you have the experience of Web application development, you will probably remind Model-View-Controller (MVC) pattern, (especially for ruby on rails developer). Below is the comparison between MVC & MVP

MVC

MVP

Cite from http://www.gwtproject.org/articles/testing_methodologies_using_gwt.html

Model, View and Presenter for each module are separated to each modules after refactoring. I put View and Presenter in “ui” package since it is changing UI.

References

Conclusion of this Tutorial

So far, I have explained about Leanback support library which makes our UI design of Android TV application much easier, simpler. I would say it was not a short tutorial, but now almost all the Android TV specific UI designs (until API level 22) are covered! I hope you get basics of Android TV app development, and you don’t lost a way to start developing your own design application.

The source code can be found on github.

Build executable file with Android NDK after Lollipop (Android API 21)

I’ll introduce more functionality of Android NDK continuing from Android NDK set up introduction. Android NDK is not only a tool to build up .so library to call through JNI, but it is also possible to build executable file itself. It is achieved by just changing Android.mk configuration. 

Below is example implementation to build hello-exe file.

1. Write Native (C/C++ language) source code

Make “hello-exe” folder anywhere and inside this folder make “jni” folder. Place “hello-exe.c” in “jni” folder and write following. So we have a folder construction like hello-exe/jni/hello-exe.c.

#include <stdio.h>

int main(int argc, char ** argv){
	printf("Hello world from NDK executable!\n");
	return 0;
}

For this tutorial, it is enough for native source code implementation 🙂

2-1. Build configuration by Android.mk (Before Android L)

Write Android.mk as following in side “jni” folder. The last line, “include $(BUILD_EXECUTABLE)“, is the key for building executable file.

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE     := hello-exe
LOCAL_SRC_FILES  := hello-exe.c

include $(BUILD_EXECUTABLE)

However, when I try this code with Android Lollipop device, it was failed with the error 

error: only position independent executables (PIE) are supported

It seems that new security feature added from Android L cause this problem.

2-2. Build configuration by Android.mk (Before Android L)
       – Enable Position Independent Executables –

Instead of 2-1, write jni/Android.mk as following.

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

# Enable PIE manually. Will get reset on $(CLEAR_VARS). This
# is what enabling PIE translates to behind the scenes.
LOCAL_CFLAGS += -fPIE
LOCAL_LDFLAGS += -fPIE -pie

LOCAL_MODULE     := hello-exe-with-pie
LOCAL_SRC_FILES  := hello-exe.c

include $(BUILD_EXECUTABLE)

3. Build

Open command prompt at “hello-exe” folder and execute ndk-build command. You can get the result like below.

D:\workspace\eclipse\ndk\hello-exe>ndk-build
[armeabi] Compile thumb  : hello-exe-with-pie <= hello-exe.c
[armeabi] Executable     : hello-exe-with-pie
[armeabi] Install        : hello-exe-with-pie => libs/armeabi/hello-exe-with-pie

Now “libs” and “obj” folders are automatically created in the same folder hierarchy with “jni” folder. Executable file is found at “hello-exe/libs/armeabi/hello-exe-with-pie”

4. Run

To execute you need to push executable file to Android device,

D:\workspace\eclipse\ndk\hello-exe>adb push libs\armeabi\hello-exe-with-pie /data/local/tmp/
1839 KB/s (9420 bytes in 0.005s)

Followed by execute at Android device. Be careful about execute permission.

D:\workspace\eclipse\ndk\hello-exe>adb shell
$ cd /data/local/tmp
$ chmod 777 ./hello-exe-with-pie
$ ./hello-exe-with-pie
Hello world from NDK executable!

One very useful usage is to execute device handling interactively. For example, high-performance consecutive sendevent command is introduced in here.

Reference

Starting Android NDK is easy!

Android NDK Develop environment set up summary

Usually Android application is developed by Java, but you can use C/C++ source code together with Android NDK (Android Native Development Kit). It provides us a opportunity to re-use/integrate existing C source code as well.

Below is summary for the steps how to start working with Android NDK.

Step1. Download installer from official site

Visit download site here, and choose installer depending on your development OS platform. In my case, I was working on Windows 7 64-bit OS, I chose android-ndk-r10e-windows-x86_64.exe.

Step2. Execute installer 

Double click to execute downloaded installer(.exe file in Windows case). It will just automatically extract the files to construct NDK working directory set. It takes a time, maybe ~ 10 min.

Step3. Move extracted folder to favorite place

After Step2, you get extracted directory, something like “android-ndk-r10e“. Move whole this directory to any favorite place.

(For example, I moved it to C:\Users\[myUserName]\AppData\Local\Android\android-ndk-r10e, since there was sdk folders in C:\Users\[myUserName]\AppData\Local\Android\sdk .)

Step4. Set environment PATH to point NDK folder path

Windows case: Go to [Control Panel] → [System and Security] → [System] → [Advanced system settings] → [Environment Variables]

In System variables category, find “Path” variable and press [Edit…] to add NDK folder path. In my case it is adding Variable value as,

The paths already written;C:\Users\[myUserName]\AppData\Local\Android\android-ndk-r10e

That’s all. Environment Path setting is necessary for executing “ndk-build” command, which is used to compile C/C++ source code for Android development. You can find ndk-build in C:\Users\[myUserName]\AppData\Local\Android\android-ndk-r10e\ndk-build.

I will write C:\Users\[myUserName]\AppData\Local\Android\android-ndk-r10e as $NDK_PATH.

Sample source code testing

NDK folder comes with many sample source codes so that you can easily find how to write C code and JNI. The sample source codes can be found in $NDK_PATH/samples.

Details are explained in Android developer ndk setup guides page.

More to do

Usually, we build .so file from C/C++ source code and use it as library. Instead, it is also possible to build executable file and execute directory inside Android device.

Javadoc coding rule of @link, @linkplain, @see

How to write link reference in javadoc

See previous post for general javadoc explanation.

Basic rule

To show “label” which refers to other field class/method/member, where “label” is optional..

@see package.class#member label

Example,

/**
 *  Javadoc 
 *  @see SampleClass#methodName(int, int) methodName
 */

Here, package name is omitted. You can use omitted name to avoid writing long sentences.

Below is the list of how you can write links.

1. Refer current class member

@see  #field
@see  #method(Type, Type,...)
@see  #method(Type argname, Type argname,...)
@see  #constructor(Type, Type,...)
@see  #constructor(Type argname, Type argname,...)

When you refer current class member, it is possible to omit writing Package.class.

2. Refer current class or imported package’s other class 

@see  Class#field
@see  Class#method(Type, Type,...)
@see  Class#method(Type argname, Type argname,...)
@see  Class#constructor(Type, Type,...)
@see  Class#constructor(Type argname, Type argname,...)
@see  Class.NestedClass
@see  Class

When you refer member which is in current class or imported package’s class, it is possible to omit writing Package.

3. Refer other package’s member

@see  package.Class#field
@see  package.Class#method(Type, Type,...)
@see  package.Class#method(Type argname, Type argname,...)
@see  package.Class#constructor(Type, Type,...)
@see  package.Class#constructor(Type argname, Type argname,...)
@see  package.Class.NestedClass
@see  package.Class
@see  package

You must write explicitly (cannot omit) in this case.

Example

Write two classes, Rectangle class and Square class refer each other.

/**
 * Javadoc link test
 * It is super class of {@link Square}
 * @see Square
 */
public class Rectangle {

    private int width;
    private int height;

    /**
     * Sets size.
     * @param width  width of rectangle
     * @param height height of rectangle
     */
    public void setSize(int width, int height){
        this.width = width;
        this.height = height;
    }

    /**
     * Gets width
     * @return {@link #width}
     * @see #getHeight()
     */
    public int getWidth(){
        return width;
    }

    /**
     * Gets height
     * @return {@link Rectangle#height}
     * @see Rectangle#getWidth()
     */
    public int getHeight(){
        return height;
    }
}

The javadoc of getWidth method is using omitted link, and javadoc of getHeight method is writing link more specifically (which is not necessary usual). 

/**
 * Javadoc link test.
 * Square is subclass of {@link Rectangle}
 * @see Rectangle
 */
public class Square extends Rectangle {
    /**
     * Sets size.
     * Below two lines refers same method.
     * @param edge length of square
     * @see Rectangle#setSize
     * @see #setSize(int width, int height)
     */
    public void setSize(int edge) {
        super.setSize(edge, edge);
    }
}

Now the java documentation of these classes refers the other field properly. It can be also confirmed by IDE. For example, when you refer the class description of Rectangle class in Android studio, by pressing [Ctrl-q], it is refering Square class so that developer can easily jump.

Explanation of Rectangle class, it contains the link of Square class.

In the same way, when we check Square.setSize method , it has a link of Rectangle.setSize method.

Explanation of Square.setSize method, it contains the link of Rectangle.setSize method.

To get the link, I wrote in 2 way,

  1. @see Rectangle#setSize
  2. @see #setSize(int width, int height)

Now you can understand what kind of omitting is allowed or not. That is, it is ok as long as it is unique to identify which setSize method we are refering.

Appendix: Refer webpage (Linking to an external URL)  

[updated on 2015/10/23]

For the purpose of linking internet website, you can use HTML tag.

Example.

/**
 * @see <a href="https://corochann.com">corochannNote</a>
 */

Reference

Get to know coding rule of Javadoc in 10 mins

Javadoc – Java document comment

Javadoc is used in Java language to write comment with the format stats from “/**” (2 asterisk needed) and ends with “*/” 

//  This is usual one line comment
/*  This is usual multiline comment */

/** Javadoc is written in here */

/**
 * Usually Javadoc is written in multiline
 * with this format. 
 */

 It is used as a explanation document for the program which is embedded in source code. Usually, Brief explanation of Class, method, and member can be written as Javadoc format.

If the Javadoc was written, we can also auto generate HTML type documentation file, for example see Java Platform SE API reference page.  

HTML TAG

HTML tag can be used to write Javadoc, which makes it formatted document and easy to refer. When you use IDE like Eclipse or Android studio, explanation is automatically formatted.

TAG

Nice summary for Javadoc Tag here (English).

TagDescription
@authorAuthor of Class
@paramExplanation of method parameter/argument
@returnExplanation of method return value
@throwException class generated by this method
@seeReference of other API
@deprecatedTo notify it is not recommended to use
@sinceVersion where this class/method is introduced
@versionVersion
{@link}Refer to other class/method
{@linkplain}Refer to other class/method
  • Block tag: @tag 
    Usually the scopr of this tag is until the end of line.
  • Inline tag: {@tag}
    The scope of this tag is inside {}

Usage of major tag

@param

Show description of parameter, member.

@param parameter-name description

@return

Show description of return value.

@return description

@link

It acts similar to <a href=””> tag of HTML, so that you can embed link to the string.

{@link package.class#member label}

label” will appear as text, and it has link to “package.class#member“. When the label is omitted, the class/member/method name will be shown. 

Example

    public class SampleLink{
        String variable;

        /**
         * Sets variable
         * Refer {@link SampleLink#getVar() getName} to get variable.
         * @param var variable
         */
        public void setVar(String var){
            variable = var;
        }

        /**
         * Gets variable.
         * Refer {@link #setVar(String)} for setting variable.
         * @return variable String
         */
        public String getVar(){
            return variable;
        }
    }

See “Javadoc coding rule of  @link, @linkplain, @see” for more details of how to write link.

@linkplain

Same with {@link}, except that the reference string will be shown plaintext instead of code text

@see

Refers other field, method.

@see reference

or

@see package.class#member label

See “Javadoc coding rule of  @link, @linkplain, @see” for more details of how to write link.

Generating javadoc

javadoc command can be used. It is in the same folder with javac command (java compiler).

javadoc "scope" -d "destination" -sourcepath "root directory of source" "package name"

Example

javadoc -d doc Sample.java

You can also refer “javadoc -help”.

At the end..

I read the story that some company decide to hire the engineer after reading his source code with the reason that his documentation comment was really organized. Yes, nice documentation can be a reason to evaluate this engineer has a skill, worth to work together. So it is a nice practice to write documentation comment even for the personal project.

Reference (Japanese)

Android Studio Live Templates Introduction

live_template

How to use Live Templates

Go to [File] → [Setting] → [Live Templates], already registered live templates are shown. We can check the Abbreviation, Description and Template text here.

During the coding, typing “Abbreviation”(shorcut command) followed by pressing [Tab], “Template text” will be expanded.

Live templates are very useful to eliminate to write the code which we often use. For example, Abbreviation “fbc” can be used for coding findViewById method (You definitely often use it when you want a reference to UI, right?). Type “fbc” and press Tab, it will automatically expand

() findViewById(R.id.);

and the cursor is selected to inside the first (), so that you can start typing class name to cast. Also, you don’t need to move cursor to fill in resource id in the argument after finish writing class name, but just press [Enter], then the cursor automatically jumps to the resource id argument. So convenient :). 

How to register your own customized Live Templates

Go to [File] → [Setting] → [Live Templates], you can use “user” category to register your own live templates. Press green [+] mark → [1. Live Templates] at the top-right to add new live templates. 

  • Abbreviation – the shortcut name to call Template.
  • Description (option) – description for this live template, not compulsory.
  • Template text – the body of template text.

After fill in 3 fields, you also need to specify the context, programming language, to call this live template.  You could see “No applicable contexts yet. Define” at the bottom, Click [Define] to set context (Just tick “JAVA” language if you are developing Android app, and want to use live template at the java programming coding). 

Now you can use your own live template as well. See Android Studio Live Templates Usage Examples for concrete useful examples!

Cannot use Software keyboard after pairing with TV SideView on SONY BRAVIA Android TV

Software keyboard cannot be launched and I cannot type from TV

When I was using SONY’s TV SideView application, I faced a problem after pairing with TV SideView on SONY BRAVIA Android TV. I could not type any alphabet from TV, it always ask me to type from paired mobile with the word “Use the keyboard on your mobile device.“. 

Even

Solution: check Android system Keyboard setting

The cause was coming from the Current keyboard setting has changed. You can change it by going to [Setting] → [Keyboard] (on System Preferences row) → [Current keyboard].

When “Virtual Remote keyboard” was selected, it was the root cause. Change it to the other.

Leanback keyboard is the default keyboard behavior.

Leanback keyboard(default). Now I can type alphabet by using remote controller as well 🙂

In-app Search function implementation
– Android TV app hands on Tutorial 13

In-app search

Search function implementation

The usage of SearchFragment of Leanback support library and UI related implementation are explained in previous chapter. In this chapter, I will explain (background) search function logic.

Most of the implementation in this chapter is just a explanation of googlesamples.

In-app search algorithm

Search algorithm is implemented in loadRows method, especially the main logic is in doInBackground method of AsyncTask. It is actually simple, just checking the string “query” is contained in either title or description of Movie items.

The UI related task Adapter handling is done in UI thread. onPreExecute initializes mRowsAdapter, which will contain the search results, by clear method. Searching itself is executed in background thread in doInBackground, and it makes new ListRow which contains the search results. This listRow is added to Adapter in UI thread by onPostExecute method. 

    private void loadRows() {
        // offload processing from the UI thread
        new AsyncTask<String, Void, ListRow>() {
            private final String query = mQuery;

            @Override
            protected void onPreExecute() {
                mRowsAdapter.clear();
            }

            @Override
            protected ListRow doInBackground(String... params) {
                final List<Movie> result = new ArrayList<>();
                for (Movie movie : mItems) {
                    // Main logic of search is here. 
                    // Just check that "query" is contained in Title or Description or not.
                    if (movie.getTitle().toLowerCase(Locale.ENGLISH)
                            .contains(query.toLowerCase(Locale.ENGLISH))
                            || movie.getDescription().toLowerCase(Locale.ENGLISH)
                            .contains(query.toLowerCase(Locale.ENGLISH))) {
                        result.add(movie);
                    }
                }

                ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
                listRowAdapter.addAll(0, result);
                HeaderItem header = new HeaderItem("Search Results");
                return new ListRow(header, listRowAdapter);
            }

            @Override
            protected void onPostExecute(ListRow listRow) {
                mRowsAdapter.add(listRow);
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

Execute search

Since search algorithm is already implemented above, we only need to call this function to get search results.

    @Override
    public ObjectAdapter getResultsAdapter() {
        Log.d(TAG, "getResultsAdapter");
        // Delete previously implemented mock code.
        // mRowsAdapter (Search result) is already prepared in loadRows method
        return mRowsAdapter;
    }

    ...

    @Override
    public boolean onQueryTextSubmit(String query) {
        Log.i(TAG, String.format("Search Query Text Submit %s", query));
        mQuery = query;
        loadRows();
        return true;
    }

Call loadRows method in onQueryTextSubmit method. Easy implementation is already done! let’s try build and run the code here.

Search function works correctly.

We have already finished minimum implementation for search function. Next step is to enable search even during the user’s text typing.

Dynamic search execution

To detect when user typing search query, we can use onQueryTextChange method. So basic concept is to just execute loadRows method in onQueryTextChange to implement dynamic (during user input) search. However, onQueryTextChange will be executed every time user input one words, and we should not call loadRows method when it has already executed. Here, Handler is used to manage executing loadRows method.

    private static final long SEARCH_DELAY_MS = 1000L;

    private final Handler mHandler = new Handler();
    private final Runnable mDelayedLoad = new Runnable() {
        @Override
        public void run() {
            loadRows();
        }
    };

     ...

    /**
     * Starts {@link #loadRows()} method after delay.
     * @param query the word to be searched
     * @param delay the time to wait until loadRows will be executed (milliseconds).
     */
    private void loadQueryWithDelay(String query, long delay) {
        mHandler.removeCallbacks(mDelayedLoad);
        if (!TextUtils.isEmpty(query) && !query.equals("nil")) {
            mQuery = query;
            mHandler.postDelayed(mDelayedLoad, delay);
        }
    }

loadQueryWithDelay method uses Handler to post loadRows task with a little delay so that loadRows task is not executed too frequently. The last modification is to call this loadQueryWithDelay method from onQueryTextChange.

    @Override
    public boolean onQueryTextChange(String newQuery){
        Log.i(TAG, String.format("Search Query Text Change %s", newQuery));
        loadQueryWithDelay(newQuery, SEARCH_DELAY_MS);
        return true;
    }

    @Override
    public boolean onQueryTextSubmit(String query) {
        Log.i(TAG, String.format("Search Query Text Submit %s", query));
        // No need to delay(wait) loadQuery, since the query typing has completed.
        loadQueryWithDelay(query, 0);
        return true;
    }

Build and run

As can be seen by video, search has executed even during the user is typing search query.

Source code is on github.

AsyncTask usage summary

AsyncTask01

Overview

AsyncTask is useful when you are working on UI (main) thread, and want to do some (maybe long) background process, and want to get callback after the background process finishes. For example, consider the case when you want to update UI of Activity according to the result of internet access. You must execute URLconnection in background thread, while updating UI must be done in UI thread after getting result. It can be implemented without caring about threads or handlers by using AsyncTask. 

Basics

4 Steps method execution flow

AsyncTask – method sequence
  1. onPreExecute: invoked on the UI thread, before doInBackground starts. Initial set up part.
  2. doInBackground: invoked on the background thread. Long computation/process (ex. downloading) is executed in this method. It must be overriden.
  3. onProgressUpdate: invoked on the UI thread, during doInBackground. It is invoked after doInBackground method calls publishProgress to update UI of background process progress.
  4. onPostExecute: invoked on the UI thread, after doInBackground finishes. Final UI update part. 

The purpose to use AsyncTask is usually updating UI according to the result of background task, so at least you usually implement 2. doInBackground (MUST) and 4. onPostExecute.
(If you only need background process and callback to main thread is not necessary, just use Thread.start() or Handler.post() )

3 Types declaration 

AsyncTask is used by extending the class to your custom Class. You need to specify 3 types when extending AsyncTask.

public class CustomAsyncTask extends AsyncTask<Params, Progress, Result> { ... }
  1. Params: input parameter, used in doInBackground method.
  2. Progress: the parameter passed from doInBackground to onProgressUpdate via publishProgress(Progress...)
  3. Result: return parameter of doInBackground,which is passed to onPostExecute.

※ If not necessary, just set Void type for each.

Usage – template

  • AsyncTask side 

Create subclass of AsyncTask. As written in Advance, it may be implemented as a inner class of Activity class.

import android.os.AsyncTask;

/**
 * AsyncTask<Params, Progress, Result>
 *     Params:   Input parameter type
 *        - arg of {@link #doInBackground}
 *
 *     Progress: Progress parameter type
 *        - arg of {@link #onProgressUpdate}
 *
 *     Result:   Return parameter from background process
 *        - return type of {@link #doInBackground}
 *        - arg of {@link #onPostExecute}
 */
public class CustomAsyncTask extends AsyncTask<Void, Void, Void> {

    private static final String TAG = CustomAsyncTask.class.getSimpleName();

    private int mParam;

    public CustomAsyncTask(int param) {
        // Constructor can be used to set field variable.
        mParam = param;
    }

    @Override
    protected void onPreExecute() {
        // Initial UI set up here (if necessary)
    }

    @Override
    protected Void doInBackground(Void... params) {
        // Implement (maybe long) background process here!

        //publishProgress(); // If you want to update UI during this process

        return null;
    }

    @Override
    protected void onProgressUpdate(Void... values) {
        // invoked when publishProgress() is called,
        // to update UI of progress during doInBackground is running.
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        // Finally, the result of doInBackground is handled on UI thread here.
    }
}
  • Execution side

Usually the purpose is to update the UI, so execution is done from Activity/Fragment class.

int param;

  ...

new CustomAsyncTask(param).execute();

Note that even type of “params”  is Void, the variables can be passed by Constructor. This is useful tip when you want to pass/input more than 2 types of variable.

More concrete examples

For example, refer AsyncTask Android example.

Advance

AsyncTask is usually used with Activity/Fragment, while the background task may be completely independent process from Activity itself. So the question comes up: how to establish independency between Activity & AsyncTask? which is the next topic

Reference