Vincec's Dimension

Android Development Notes

Word count: 2,825 / Reading time: 18 min
2019/02/03 Share

Register in Android Manifest

  • Activity: resposible for user interaction screens, creating windows, Views manage display and user interactivity
  • Serivce: background tests
  • Content Provider: provide managed access to data
  • Broadcast Receiver: react to messages

Setting adb to global

Windows:

  • contorl panel -> environment (edit system environment variables)
  • Environment variables
  • Edit User/System
  • PATH, (tools;platform-tools path)

    Mac

  • ~ sudo nano .bash_profile
  • export PATH=$PATH:~/Library/Android/sdk/tools:~/Library/Android/sdk/platform-tools

Permission Example

AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//onCreate{
if(!permissionGranted){
checkPermissions();
return;
}
//}

// Checks if external storage is available for read and write
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
return Environment.MEDIA_MOUNTED.equals(state);
}

// Initiate request for permissions.
private boolean checkPermissions() {

if (!isExternalStorageWritable()) {
Toast.makeText(this, "This app only works on devices with usable external storage",
Toast.LENGTH_SHORT).show();
return false;
}

int permissionCheck = ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_PERMISSION_WRITE);
return false;
} else {
return true;
}
}

// Handle permissions result
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String permissions[],
@NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_PERMISSION_WRITE:
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
permissionGranted = true;
Toast.makeText(this, "External storage permission granted",
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "You must grant permission!", Toast.LENGTH_SHORT).show();
}
break;
}
}

Launcher Icon Assets

app -> new -> image assets

Setting Activity

app -> new -> activity -> setting activity

1
2
3
4
5
6
7
8
9
10
11
//import Intent
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
return true;
}
return super.onOptionsItemSelected(item);
}

Enable Jack compiler for Java 8 features

Modify in build.gradle

1
2
3
4
5
6
7
8
9
10
11
12
13
android {
defaultConfig{
jackOptions{
enabled true
}
}
}

#after buildTypes:
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

Communication usage scenarios

  • Acknowledgement
  • Confirmation
  • Notification

Toast Message

  • Short, momentary test message
  • not receive focus
  • quick, informative to acknowledge
  • display for amount of time

Create a Toast message

1
2
Toast t = Toast.makeText(this, "This is a toast", toastDuration);
//t.setDuration(toastDuration)

Position Toast on screen

1
2
t.setGravity(Gravity.CENTER, 0, 0);
//t.setGravity(Gravity.BOTTOM, 0, 0);

Show the Toast message

1
t.show();

CustomToast

1
2
3
4
5
6
7
8
9
10
LayoutInflater inflater = getLayoutInflater();
View layout = inflater.inflate(R.layout.custom_toast_layout, (ViewGroup)findViewById(R.id.customToastLayout));

TextView tv = (TestView)layout.findViewById( R.id.customToastLayout );
tv.setText("This is a toast");

Toast t = new Toast(getApplicationContext());
t.setDuration(toastDuration);
t.setView(layout);
t.show();

Snackbar Messages

  • Simliar to Toasts
  • Quick messages to acknowledge some action
  • can show different amout of time
  • Appear at bottom of the screen
  • Can specify a clickable action

Create a Snackbar

1
Snackbar sb = Snackbar.make(findViewById(R.id.myCoordinatorLayout), "This is a snackbar", Snackbar.LENGTH_LONG);

Set Snackbar action

1
2
3
4
5
6
sb.setAction("My Action", new View.OnClickListener(){
@Override
public void onClick(View view){
Toast.makeText(getApplicationContext(), "Snackbar Action Tap!", Toast.LENGTH_SHORT).show();
}
});

Show the Snackbar

1
sb.show();

Notice

  • Need to add design appcompat in dependencies (build.gradle file)
  • Layout use coordinatorLayout when need to swipe the snackbar feature

Dialogs

  • Stop current program flow
  • Require the user to take action
  • Maintain the user’s current context

simple dialog example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
//Create an alertDialog.Builder instance
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
//set builder properties
builder.setTitle("Peas Preference");
builder.setMessage("Do you like sugar snap peas?");

builder.setPositiveButton("Sure!", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.i(TAG, "Positive button clicked");
mHost.onPositiveResult(SimpleDialogFragment.this);
}
});
builder.setNegativeButton("No way!", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.i(TAG, "Negative button clicked");
mHost.onNegativeResult(SimpleDialogFragment.this);
}
});
builder.setNeutralButton("Not Sure", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.i(TAG, "Neutral button clicked");
mHost.onNeutralResult(SimpleDialogFragment.this);
}
});
//return the created dialog
return builder.create();
}

Allow user to tap and cancel the dialog

1
2
3
4
5
//user cancel the dialog
@Override
public void onCancel(DialogInterface dlg) {
super.onCancel(dlg);
Log.i(TAG, "Dialog cancelled");

Not allow user to cancel

setCancelable() to make the dialog non-cancelable

1
simpleDialog.setCancelable(false);

ShowDatePicker Dialog Example

1
2
3
4
5
6
7
8
9
10
11
12
// Get a calendar instance
Calendar cal = Calendar.getInstance();
// Create a DatePickerDialog
DatePickerDialog datePicker = new DatePickerDialog(this, new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
Log.i(TAG, String.format("Date Chosen -- day: %d, month: %d, year: %d", dayOfMonth, monthOfYear, year));
}
}, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
// Set the title and show the dialog
datePicker.setTitle("Choose a Date");
datePicker.show();

SetItem to Dialog Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private final String TAG = "AUC_COMPLEX";
private final String[] colors = {"Red", "Blue", "Green", "Yellow"};

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// NOTE: setMessage doesn't work here because the list takes up the content
// area. Use the setTitle method to set a descriptive prompt
builder.setTitle("What Is Your Favorite Color?");
// The setItems function is used to create a list of content
builder.setItems(colors, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.i(TAG, String.format("Color chosen: %s", colors[which]));
}
});
// Single-choice dialogs don't need buttons because they
// auto-dismiss when the user makes a choice
return builder.create();
};

CustomDialog Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Create the custom layout using the LayoutInflater class
LayoutInflater inflater = getActivity().getLayoutInflater();
View v = inflater.inflate(R.layout.custom_dialog_layout, null);
// Build the dialog
builder.setTitle("Please enter your name")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.i(TAG, "OK Clicked");
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener @Override public void onClick(DialogInterface dialog, int which) {
Log.i(TAG, "Cancel clicked");
}
})
.setView(v);
return builder.create();
}

Notification

ref

  • Display outside of the normal app
  • Trigger parts when clicked
  • Various forms
  • Aciton individually
  • appear on Lock screen

New Activity

1
2
3
4
5
6
class AboutMe : AppCompatActivity() { 
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_about_me) //create a xml and add acitivity to mainifest
}
}
1
2
3
4
5
//other Activity class
bigButton.setOnClickListener {
d("daniel","button was pressed")
startActivity(Intent(this, AboutMe::class.java))
}

getSharedPreferences

1
2
3
4
5
6
7
8
9
10
11
12
val sharedPrefs = getSharedPreferences("production", Context.MODE_PRIVATE) //name
val isSignedIn = sharedPrefs.getBoolean("is_signed_in", false) // key, defValue

if(!isSignedIn){
} else {
}

//to edit
with(sharedPrefs.edit()){
putBoolean("is_signed_in", true)
commit()
}

RecyclerView

Type

  • Linear Layout
  • Grid Layout
  • Staggered Grid Layout

Data Class

1
2
3
4
5
data class Story(
val title: String,
val text: String,
val author: String
)

Adapter

Hold data in to the list

Data Model

Generate -> Constructor / Getter and Setter / toString()

Parse a Json Using Volley

UI

ref

Rename in XML

shift + f6

ViewGroup

  • FameLayout
  • LinearLayout
  • RelativeLayout
  • GridView
  • ListView
  • CoordinatorLayout
  • AppBarLayout
  • DrawerLayout
  • RecyclerView, replace GridView / ListView

DP and SP

ref

String Display

1
2
3
4
5
<TextView
android:text="aaaaaaaaaaaaaaaaaaaaaaaaaaa"
android:maxLines="1"
android:ellipsize="end"
/>

String Movement

1
2
3
4
5
<TextView
android:id="@+id/textView"
android:text="aaaaaaaaaaaaaaaaaaaaaaaaaaa"
android:scrollbars="vertical"
/>
1
2
textView tv = (TextView) findViewById(R.id.textView);
tv.setMovementMethod(new ScrollingMovementMethod());

TextInputLayout

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<android.support.design.widget.TextInputLayout
android:id="@+id/textInputLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

<EditText
android:id="@+id/editName"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:ems="10"
android:hint="Name"
android:inputType="textPersonName" />

</android.support.design.widget.TextInputLayout>

<android.support.design.widget.TextInputLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textInputLayout">

<EditText
android:id="@+id/editPassword"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:ems="10"
android:hint="Password"
android:inputType="textPassword" />

</android.support.design.widget.TextInputLayout>

Toast

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

//Toast toast = new Toast(context);
// toast.setDuration(Toast.LENGTH_LONG);

// LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// View view = inflater.inflate(R.layout.your_custom_layout, null);
// toast.setView(view);
// toast.show();

//--------------------------------

// String text = "Hello toast!";
// int duration = Toast.LENGTH_SHORT;

// Toast toast = Toast.makeText(this, text, duration);
// toast.show();


public void onClick(View view) {
String name = "Vince";
String password = "Password";
String message = String.format("name=%s, password=%s", name, password);
Toast.makeText(this,message, Toast.LENGTH_SHORT).show();
}

input Layout setError

1
2
3
4
5
6
7
8
9
10
11
TextInputLayout textInputLayoutName = findViewById(R.id.textInputLayoutName);
EditText editName2 = findViewById(R.id.editTextName);
String inputName = textInputLayoutName.getEditText().getText().toString().trim();
// String inputName2 = editName2.getText().toString().trim();
if(inputName.isEmpty()){
textInputLayoutName.setError("Name is empty");
editName2.setError("Name is empty");
Toast.makeText(this,"Name is empty", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this,inputName, Toast.LENGTH_SHORT).show();
}

Spinner

1
2
<Spinner
android:id="@+id/spinner"/>
1
2
3
4
5
6
7
<resources>
<string-array name="spinner">
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
</resources>
1
2
3
4
5
Spinner spin = findViewById(R.id.spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.spinner, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spin.setAdapter(adapter);
spin.setOnItemSelectedListener(this);

Add Tabs to the Action Bar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Override
public void onCreate(Bundle savedInstanceState) {
final ActionBar actionBar = getActionBar();
...

// Specify that tabs should be displayed in the action bar.
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

// Create a tab listener that is called when the user changes tabs.
ActionBar.TabListener tabListener = new ActionBar.TabListener() {
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
// show the given tab
}

public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
// hide the given tab
}

public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
// probably ignore this event
}
};

// Add 3 tabs, specifying the tab's text and TabListener
for (int i = 0; i < 3; i++) {
actionBar.addTab(
actionBar.newTab()
.setText("Tab " + (i + 1))
.setTabListener(tabListener));
}
}
1
2
3
4
5
6
7
viewPager = findViewById(R.id.main_viewPager);
tabLayout = findViewById(R.id.tabLayout);
tabLayout.setupWithViewPager(viewPager); //link together

//adapter
fragAdapter = new fragAdapter(getSupportFragmentManager());
viewPager.setAdapter(fragAdapter);
1
2
3
4
5
private String[] tabTitles = new String[]{"Tab1", "Tab2", "Tab3"};
@Override
public CharSequence getPageTitle(int position) {
return tabTitles[position];
}

Tab select listener

1
2
3
4
5
6
7
8
9
10
11
12
13
14
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
}

@Override
public void onTabUnselected(TabLayout.Tab tab) {
}

@Override
public void onTabReselected(TabLayout.Tab tab) {

}
});

Tab Add Icon

  • [how to add the icon for swipeable tabs] (https://stackoverflow.com/questions/21528687/how-to-add-the-icon-for-swipeable-tabs)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //An array containing your icons from the drawable directory
    final int[] ICONS = new int[]{
    R.drawable.icon_1,
    R.drawable.icon_2,
    R.drawable.icon_3
    };

    //Get reference to your Tablayout
    TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
    tabLayout.setupWithViewPager(mViewPager);

    tabLayout.getTabAt(0).setIcon(ICONS[0]);
    tabLayout.getTabAt(1).setIcon(ICONS[1]);
    tabLayout.getTabAt(2).setIcon(ICONS[2]);

SoftKeywordCover EditText

Android soft keyboard covers edittext field

manifest.xml

1
2
3
4
5
<activity
android:name=".Activities.InputsActivity"
...
android:windowSoftInputMode="adjustPan"
/>

Splash Screen

The (Complete) Android Splash Screen Guide

AutoCompleteTextView

AutoCompleteTextView - Android Studio Tutorial

1
2
3
4
<AutoCompleteTextView
...
android:completionThreshold="1"
/>

1
2
3
4
5
6
7
8
9
private static final String[] ZIPCODES = new String[]{
"90001", "90002", "91001", "91003", "92000"
};

protected void onCreate(Bundle savedInstanceState){
AutoCompleteTextView textView = (AutoCompleteTextView) getView().findViewById(R.id.textView);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, ZIPCODES);
textView.setAdapter(adapter);
}

AddListener

setOnCheckedChangeListener

1
2
3
4
5
6
7
8
9
10
CheckBox cb = (CheckBox) view.findViewById(R.id.cb);
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
} else {
}

}
});

addTextChangedListener

android on Text Change Listener

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
EditText editText = (AutoCompleteTextView) view.findViewById(R.id.editText);
editText.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
}

@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.length() != 0){
}
}
});

setOnClickListener

1
2
3
4
5
6
7
8
9
ToggleButton toggleButton = (ToggleButton) findViewById(R.id.toggle1);
toggleButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (((ToggleButton) v).isChecked())
DisplayToast("Toggle button is On");
else
DisplayToast("Toggle button is Off");
}
});

Start A new Activity

Send

1
2
3
Intent myIntent = new Intent(getBaseContext(), Result.class);
myIntent.putExtra("key", "Value"); //Optional parameters
this.startActivity(myIntent);

Receive

1
2
3
4
5
6
7
8
9
10
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.newActivity);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

Intent intent = getIntent();
String value = intent.getStringExtra("key"); //if it's a string you stored.
d("value",value);
}

Up back button

1
getSupportActionBar().setDisplayHomeAsUpEnabled(true);

Will perform as back

1
2
3
4
5
6
7
8
9
10
11
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.newActivity);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}

@Override
public boolean onSupportNavigateUp(){
finish();
return true;
}

Volley / Picasso

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
VolleyLog.DEBUG = true;

JsonObjectRequest req = new JsonObjectRequest(Request.Method.GET, "http://ip.jsontest.com/", null,
new Response.Listener<JSONObject>()
{
@Override
public void onResponse(JSONObject response) {
// display response
try {
d("Response", response.getString("ip"));
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener()
{
@Override
public void onErrorResponse(VolleyError error) {
d("Error.Response", error.toString());
}
}
);

Visiblity

  • xxx.setVisibility(View.GONE); none
  • xxx.setVisibility(View.VISIBLE); show
  • xxx.setVisibility(View.INVISIBLE); Hide

Prograss Bar

Android ProgressBar Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="23dp"
android:layout_marginTop="20dp"
android:indeterminate="false"
android:max="100"
android:minHeight="50dp"
android:minWidth="200dp"
android:progress="1" />

<ProgressBar
android:id="@+id/progressBar_cyclic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="50dp"
android:minWidth="50dp"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />

Toggle Button Customized with Image

Android: Create a toggle button with image and no text

Preference

how to use getSharedPreferences in android

1
2
3
4
5
6
7
8
9
10
SharedPreferences userDetails = context.getSharedPreferences("userdetails", MODE_PRIVATE);

Editor edit = userDetails.edit();
edit.putString("username", username.getText().toString().trim());
edit.putString("password", password.getText().toString().trim());
edit.apply();

String userName = userDetails.getString("username", "");
String password = userDetails.getString("password", "");
//getBoolean, long, float

GSON - How Android SharedPreferences save/store object

Set image background and tint its color

1
2
android:src="@drawable/image"
android:backgroundTint="#B7B2B0"

OR

1
2
3
ImageView iv = findViewById(R.id.iv);
iv.setBackgroundResource(R.drawable.image);
iv.getBackground().setColorFilter(Color.parseColor("#B7B2B0"), PorterDuff.Mode.MULTIPLY);

CATALOG
  1. 1. Register in Android Manifest
  2. 2. Setting adb to global
    1. 2.0.1. Windows:
    2. 2.0.2. Mac
  • 3. Permission Example
  • 4. Launcher Icon Assets
  • 5. Setting Activity
  • 6. Enable Jack compiler for Java 8 features
  • 7. Communication usage scenarios
    1. 7.1. Toast Message
      1. 7.1.1. Create a Toast message
      2. 7.1.2. Position Toast on screen
      3. 7.1.3. Show the Toast message
      4. 7.1.4. CustomToast
    2. 7.2. Snackbar Messages
      1. 7.2.1. Create a Snackbar
      2. 7.2.2. Set Snackbar action
      3. 7.2.3. Show the Snackbar
      4. 7.2.4. Notice
    3. 7.3. Dialogs
      1. 7.3.1. simple dialog example
        1. 7.3.1.1. Allow user to tap and cancel the dialog
        2. 7.3.1.2. Not allow user to cancel
      2. 7.3.2. ShowDatePicker Dialog Example
      3. 7.3.3. SetItem to Dialog Example
      4. 7.3.4. CustomDialog Example
    4. 7.4. Notification
    5. 7.5. New Activity
    6. 7.6. getSharedPreferences
    7. 7.7. RecyclerView
      1. 7.7.1. Type
      2. 7.7.2. Data Class
      3. 7.7.3. Adapter
      4. 7.7.4. Link adapter to the recyclerView
    8. 7.8. Data Model
    9. 7.9. Parse a Json Using Volley
    10. 7.10. UI
      1. 7.10.1. Rename in XML
      2. 7.10.2. ViewGroup
      3. 7.10.3. DP and SP
      4. 7.10.4. String Display
        1. 7.10.4.1. String Movement
      5. 7.10.5. TextInputLayout
      6. 7.10.6. Toast
      7. 7.10.7. input Layout setError
      8. 7.10.8. Spinner
      9. 7.10.9. Add Tabs to the Action Bar
        1. 7.10.9.1. Tab select listener
        2. 7.10.9.2. Tab Add Icon
      10. 7.10.10. SoftKeywordCover EditText
      11. 7.10.11. Splash Screen
      12. 7.10.12. AutoCompleteTextView
      13. 7.10.13. AddListener
        1. 7.10.13.1. setOnCheckedChangeListener
        2. 7.10.13.2. addTextChangedListener
        3. 7.10.13.3. setOnClickListener
      14. 7.10.14. Start A new Activity
      15. 7.10.15. Up back button
      16. 7.10.16. Volley / Picasso
      17. 7.10.17. Visiblity
      18. 7.10.18. Prograss Bar
      19. 7.10.19. Toggle Button Customized with Image
      20. 7.10.20. Preference
      21. 7.10.21. Set image background and tint its color