Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android Application Development

Android Application Development

Android Application Development - Some Kotlin updates on 2020

Jussi Pohjolainen

October 14, 2016
Tweet

More Decks by Jussi Pohjolainen

Other Decks in Technology

Transcript

  1. Android Architecture Written in Java Higher level services UI elements

    Access data from another apps Access to non- code resources Lifecycle of Apps Display alerts C Libraries Core libraries and VM Kernel
  2. Linux Kernel on Android • Has standard Linux kernel with

    kernel enhancements to support Android • No standard GNU C (glibc) Library support • Uses custom libc (bionic libc) because of performance and licensing issues • No native windowing system • Does not include full set of standard Linux utilities • To access shell, use adb shell command
  3. Distribution • You have several options for distribution • .apk

    files can be installed via memory card, web sites, e-mail • App stores • Several stores available • Google Play Store • Amazon App Store • GetJar App Store • Samsung Apps • Nokia Store
  4. Google Play (Android Market) • Google Play is an online

    software store developed by Google • Music, Books, Magazines, Movies and Apps • Preinstalled on some Android devices • To publish, developer must pay ~17€ (Visa, Visa Electron) • Developer gets 70% of the app price
  5. Tools • SDK Tools (Google) • Standalone command line tools

    for building android apps • IDE • Android Studio (Google) • This will install also SDK Tools on startup • Eclipse (requires plugin) • IntelliJ Idea
  6. SDK Tools • SDK tools are all you need •

    Contains all necessary command line tools for building and running your apps • When SDK tools are downloaded and installed, you must • Install Android Platform • Configure emulator
  7. Android Studio • Installs SDK Tools • Mac: /Users/<user>/Library/Android/sdk •

    Win: /Users/<user>/sdk • Features • GitHub integration • Build apps for phones, TV, Google Glass • Better virtual device manager • Layout editor • Built on top of IntelliJ IDEA
  8. New Project 15 Use APIs that are not available for

    older platforms. This is depricated and androidx library should be used for new projects.
  9. build.gradle • Project\app\build.gradle • Specific for app module • Module

    dependencies can be found from here • Project\build.gradle • Top – level build file, common for all modules 16
  10. Template: Java import androidx.appcompat.app.AppCompatActivity import android.os.Bundle public class MainScreen extends

    AppCompatActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } } Creates layout from xml-file
  11. Template: Kotlin import androidx.appcompat.app.AppCompatActivity import android.os.Bundle class MainActivity : AppCompatActivity()

    { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } } Creates layout from xml-file
  12. Modification: Java import android.app.Activity; import android.os.Bundle; import android.widget.TextView; public class

    Main extends AppCompatActivity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tv = new TextView(this); tv.setText("Hello, Android"); setContentView(tv); } }
  13. Modification: Kotlin package fi.organization.justfortesting import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.TextView

    class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val tx = TextView(this) tx.text = "Hello World" setContentView(tx) } }
  14. UI: By Coding or XML • You can code your

    UI or you can use XML – files • Using XML – files is the preferred way • File res/layout/foo.xml contains the basic template for your UI
  15. Using the XML file import android.app.Activity; import android.os.Bundle; public class

    Main extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } } Name of your xml- file(main.xml) R – class. Generated for you Inner class
  16. XML and R - class • XML file will be

    compiled to a Java object • Reference to that object is made through R – class • R – class is generated automatically for you
  17. R – class in Java public final class R {

    public static final class attr { } public static final class drawable { public static final int icon=0x7f020000; } public static final class layout { public static final int main=0x7f030000; } public static final class string { public static final int app_name=0x7f040001; public static final int hello=0x7f040000; } } • R – class is an index to all your resources • Short way of referencing to resources • Never edit this file by hand!
  18. XML - file <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> ConstrainLayout helps you to build complex UI:s without nested layouts
  19. XML – file, with LinearLayout <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> </LinearLayout> Reference to res/values/strings.xml
  20. Two Widgets and Event Handling: Java public class Main extends

    Activity implements OnClickListener { private Button clickMe; private TextView textView; private LinearLayout layout; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); clickMe = new Button(this); clickMe.setText("Click Me!"); clickMe.setOnClickListener(this); textView = new TextView(this); textView.setText("Some Text"); layout = new LinearLayout(this); layout.addView(clickMe); layout.addView(textView); setContentView(layout); } public void onClick(View v) { textView.setText("Clicked!"); } }
  21. Two Widgets and Event Handling: Kotlin class MainActivity : AppCompatActivity(),

    OnClickListener { lateinit var btn : Button lateinit var txt : TextView lateinit var layout : LinearLayout override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) btn = Button(this) btn.text = "Click me" txt = TextView(this) txt.text = "some text" layout = LinearLayout(this) layout.addView(btn) layout.addView(txt) btn.setOnClickListener(this) setContentView(layout) } override fun onClick(view: View?) { txt.text = "clicked" } }
  22. Two Widgest and Event Handling via XML <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="@string/hello_world" /> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/textView1" android:layout_centerHorizontal="true" android:text="Change text" /> </RelativeLayout>
  23. R – class updates automatically public final class R {

    public static final class attr { } public static final class drawable { public static final int ic_action_search=0x7f020000; public static final int ic_launcher=0x7f020001; } public static final class id { public static final int button1=0x7f070001; public static final int menu_settings=0x7f070002; public static final int textView1=0x7f070000; } public static final class layout { public static final int activity_main_screen=0x7f030000; } public static final class menu { public static final int activity_main_screen=0x7f060000; } public static final class string { public static final int app_name=0x7f040000; public static final int hello_world=0x7f040001; public static final int menu_settings=0x7f040002; public static final int title_activity_main_screen=0x7f040003; } public static final class style { public static final int AppTheme=0x7f050000; } }
  24. .. And the Code public class Main extends Activity implements

    OnClickListener { private Button clickMe; private TextView textView; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); clickMe = (Button) findViewById(R.id.button1); textView = (TextView) findViewById(R.id.textView1); clickMe.setOnClickListener(this); } public void onClick(View v) { textView.setText("Clicked!"); } }
  25. .. And the Code in Kotlin class MainActivity : AppCompatActivity()

    { lateinit var btn : Button lateinit var txt : TextView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) btn = findViewById<Button>(R.id.button1) txt = findViewById<TextView>(R.id.textView1) btn.setOnClickListener() { txt.text = "clicked" } } }
  26. About Delegation Event Model • Separation between application and UI

    code • Example: • somebutton.setOnClickListener(OnClickListener); • Source: somebutton • Listener: some object that implements OnClickListener • There is a easier way to do basic event handling..
  27. Listeners in XML <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/button1"

    android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 1" android:onClick="clicked"/> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 2" android:onClick="clicked"/> </LinearLayout>
  28. And the Java Code public class EventHandlingDemo extends Activity {

    /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } public void click(View source) { switch ( source.getId() ) { case R.id.button1: // do something break; case R.id.button2: // do something break; } } }
  29. And Kotlin class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState:

    Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } fun clicked(view: View) { when(view.id) { R.id.button1 -> Log.d("TAG", "button 1") R.id.button2 -> Log.d("TAG", "button 2") } } } 38
  30. Reading and Writing Logs • Log is a logging class

    for printing stuff to logcat • Common methods: • v(String, String) - verbose • d(String, String) - debug • i(String, String) - info • w(String, String) - warning • e(String, String) – error • Example • Log.d(“MainScreen”, “Just printing stuff”); • logging
  31. Filtering Output • Log message contains • Tag – short

    String, example "MainScreen" • Priority – following chars from lowest to highest priority: • v(erbose) – lowest priority • d(ebug) • i(nfo) • w(arning) • e(rror) • f(atal) • s(ilent) – highest priority, nothing is printed
  32. Filtering Output • Example output • D/MainScreen( 903): User clicked

    some view object: android.widget.Button@411fe148 • Priority level is D and tag is MainScreen
  33. Restricting output • To restrict output, use filter expressions •

    Format • tag : priority • priority is the minimum level of priority to report • Example • adb logcat • tag1:priority1 // show this and.. • tag2:priority2 // this.. • *:S // Set all other tags silent
  34. Real World Usage • Example • $ adb logcat MainActivity:D

    *:S • D/MainScreen( 903): User clicked some view object: android.widget.Button@411fe148 • Display output from MainScreen tag with priority debug or above and restrict everything else
  35. App Fundamentals • Android app lives in its own world

    • Own process, app files only visible to the app • Apps can make use of other apps, information sharing, moving between apps • Apps are build using Android components • Every app holds a application description file (AndroidManifest.xml) • In the file you define the android components
  36. Components • Android app is built using components • Activity:

    User visible Window • Service: Background service (no UI) • Broadcast Receiver: receiving broadcasts from apps and system services • Content provider: Provides content to apps • Components are separate building blocks that can be accessed by other apps! • Components are usually declared in application manifest
  37. Manifest <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="fi.organization.justfortesting"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher"

    android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.JustForTesting"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
  38. Activities • An activity is a single, focused thing that

    the user can do • Equivalent to Frame or Window in GUI toolkits • Subclass of Activity – class • One app may have one or several activities • Each activity is given a default window to draw in • Window consists of views (widgets)
  39. Activity Stack • Android keeps navigation history of activities the

    user has visited: Activity Stack or the Back Stack • Pressing Back displays the previous Activity! • User cannot go further than the last visit of home
  40. Activity Lifecycle: States • Resumed • App is in foreground

    and user can interact with it • Paused • Partially obscure by another activity. • Stopped • not visible, in background. All member variables are retained, cannot execute code. • Other states • Created and Started – system quickly moves from them to the next state!
  41. Lifecycle Methods public class Activity extends ApplicationContext { protected void

    onCreate(Bundle savedInstanceState); protected void onStart(); protected void onRestart(); protected void onResume(); protected void onPause(); protected void onStop(); protected void onDestroy(); } // The derived class must invoke these: super.onCreate(…), // super.onStart()..
  42. • onCreate() • Create the user interface • onStart() •

    When visible to user • onResume() • Activity is visible again, initialize fields, register listeners, bind to services • onPause() • Activity still partially visible, but most often is an indication that the user is leaving the activity and it will soon enter the stopped state. Release resources, save app data, unregister listeners, unbind services • onStop() • Activity is no longer visible to user. Time or CPU intensive shut-down operations like writing information to database
  43. Intro to Intents • Intents are message-passing mechanism that lets

    you declare your intentation than an action be performed with a particular piece of data • Interaction between any android component • Uses • Start new activities • Broadcast messages • Start new services
  44. Explicit vs Implicit Intents • Explicit • Open explicitly certain

    Activity • Internal messaging between your app • Designated target class • Implicit • External messaging between apps • Open some Activity with certain service • you don’t know which activity of which app…
  45. Explicit Intent // Java Intent intent = new Intent(this, SecondActivity.class);

    startActivity(intent) // Kotlin val intent = Intent(this, SecondActivity::class.java) startActivity(intent)
  46. "Importance Hierarchy" • When running out of memory, what to

    kill? 1. Background Process – When task is not visible to user 2. Service Process – killed only if memory is needed for foreground and visible processes 3. Visible Process – killed only if keep foreground processes alive 4. Foreground Process – killed only as last resort
  47. State Information • Think about following situation: 1. User opens

    app and Activity 1 opens. User is prompt a name in EditText. User writes his/her name. 2. User navigates from Activity 1 to Activity 2 3. User presses back button and Activity 1 is opened again • Is the name still there?
  48. How to Store State Information • Store state: • onSaveInstanceState(Bundle)

    • Read state • onRestoreInstanceState(Bundle) • This will store data only temporarily: for app lifetime! • Data will be held in memory until the app is closed!
  49. Store // Java @Override public void onSaveInstanceState(Bundle savedInstanceState) { String

    text = textfield.getText().toString(); savedInstanceState.putString("someKey", text); super.onSaveInstanceState(savedInstanceState); } // Kotlin override fun onSaveInstanceState(outState: Bundle) { var text = textfield.text.toString() outState.putString("someKey", text) super.onSaveInstanceState(outState) }
  50. Load // Java @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState);

    String strValue = savedInstanceState.getString("someKey"); if (strValue != null) { textfield.setText(strValue); } } // Kotlin override fun onRestoreInstanceState(savedInstanceState: Bundle) { super.onRestoreInstanceState(savedInstanceState) val strValue : String? = savedInstanceState.getString("someKey") if(strValue != null) { textfield.text = strValue } }
  51. Explicit Intent: Sending Data // Java Intent intent = new

    Intent(this, SecondActivity.class); intent.putExtra("key", "value"); startActivity(intent); // Kotlin val intent = Intent(this, SecondActivity::class.java) intent.putExtra("key", "value") startActivity(intent)
  52. Explicit Intent: Receiving the Information: Java public class SecondActivity extends

    AppCompatActivity { @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(R.layout.main); Bundle extras = getIntent().getExtras(); if (extras != null){ String value1 = extras.getString("key"); } ....
  53. Explicit Intent: Receiving the Information: Kotlin class SecondActivity: AppCompatActivity() {

    override fun onCreate(bundle: Bundle?) { super.onCreate(bundle); setContentView(R.layout.main); val extras = getIntent().getExtras(); if (extras != null) { val value1 = extras.getString("key"); } ....
  54. Getting Results Back: Java class GettingResultsBack extends Activity { private

    static final int REQUEST_CODE = 10; public void clickButton(View v) { if (v == settings) { Intent intent = new Intent(this, SecondActivity.class); startActivityForResult(intent, REQUEST_CODE); } } protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE) { if (resultCode == RESULT_OK) { Bundle bundle = data.getExtras(); String result = bundle.getString("somevalue"); } } } }
  55. Getting Results Back: Kotlin class GettingResultsBack: AppCompatActivity() { private val

    REQUEST_CODE = 10; fun clickButton(v: View) { if (v == settings) { val intent = new Intent(this, SecondActivity::class.java); startActivityForResult(intent, REQUEST_CODE); } } protected fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (requestCode == REQUEST_CODE) { if (resultCode == RESULT_OK) { val value = data?.extras.getString("somevalue"); } } } }
  56. Explicit Intent: Getting results Back: Java @Override public void onBackPressed()

    { Intent intent = new Intent(); number = phoneNumber.getText().toString(); intent.putExtra("phonenumber", number); setResult(RESULT_OK, intent); super.onBackPressed(); }
  57. Explicit Intent: Getting results Back: Kotlin override fun onBackPressed() {

    val intent = Intent() intent.putExtra("name", result) setResult(RESULT_OK, intent); super.onBackPressed() }
  58. Implicit Intents • Implicit Intents are mechanism that lets open

    anonymous application’s components • Android will at run time resolve the best class suited to performing the action • Your app will use other app’s functionality without knowing exactly which application! • Various native apps provide components that can be called implicitly
  59. Implicit Intent’s Pieces • Primary pieces of information in Intent’s

    are 1. Action • The general action to be performed, for example ACTION_DIAL, ACTION_VIEW 2. Data • The data to operate on expressed in Uri • Example action/data pairs • ACTION_VIEW, content://contacts/people/1 • ACTION_VIEW, content://contacts/people/ • ACTION_DIAL, tel://123456 • I want to view (action) a webpage (URI)
  60. Using Implicit Intents: Java Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:123456"));

    startActivity(intent); Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://.."); startActivity(intent); Intent Filter's name Data
  61. Lot of Native Android Actions • All the String constants

    can be found from Intent class. These are native actions. • Activity • ACTION_ANSWER (=“android.intent.action.ANSWER”) • ACTION_CALL • ACTION_BUG_REPORT • ACTION_POWER_USAGE_SUMMARY • … • Broadcast • ACTION_BATTERY_CHANGED • ACTION_BATTERY_LOW • ACTION_BOOT_COMPLETED • ACTION_AIRPLANE_MODE_CHANGED • ACTION_CAMERA_BUTTON • ...
  62. public void clicked(View button) { ... case R.id.button1: intent =

    new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.tamk.fi")); startActivity(intent); break; case R.id.button2: intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:(+358)12345789")); startActivity(intent); break; case R.id.button3: intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:(+358)12345789")); startActivity(intent); break; case R.id.button4: intent = new Intent(Intent.ACTION_VIEW, Uri.parse("geo:60.123,60.1434?z=19")); startActivity(intent); break; case R.id.button5: intent = new Intent(Intent.ACTION_VIEW, Uri.parse("geo:0,0?q=kauppakadun rauta")); startActivity(intent); break; case R.id.button6: intent = new Intent("android.media.action.IMAGE_CAPTURE"); startActivityForResult(intent, 0); break; case R.id.button7: intent = new Intent(Intent.ACTION_VIEW, Uri.parse("content://contacts/people/")); startActivity(intent); break; case R.id.button8: intent = new Intent(Intent.ACTION_EDIT, Uri.parse("content://contacts/people/1")); startActivity(intent); break; }
  63. Intent Filters • How does Android know which application (and

    component) handles the request? • Intent Filters are used to register components as being capable of performing an action on particular kind of data • Tell Android that your app can service request from other apps • How? Use application’s manifest file and add inter-filter tag
  64. Using Intent Filter • Intent action • Name of the

    action being serviced. Should be unique, so use Java package naming conventions • Intent type / data • type of data given to component (MIME type) • Intent category • Additional info about the component that should handle the action. CATEGORY_BROWSABLE, CATEGORY_PREFERENCES...
  65. Implementing Own Intent Filter <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="fi.organization.demos”>

    <uses-sdk android:minSdkVersion="8" /> <uses-permission android:name="android.permission.INTERNET"></uses-permission> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".PlaySound" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter> <action android:name="fi.organization.demos.PLAYSOUND" /> <data android:scheme="http" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> </application> </manifest> Our own Intent filter for activity PlaySound
  66. Opening the Activity (App A): Java intent = new Intent("fi.organization.demos.PLAYSOUND",

    Uri.parse("http://www….fi/music.mp3")); startActivity(intent);
  67. The Activity (App B): Java public class PlaySound extends Activity

    { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Intent i = getIntent(); Uri uri = i.getData(); if(uri != null) { MediaPlayer mp = MediaPlayer.create(this, uri); mp.start(); } } }
  68. Implementing a Browser <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="fi.organization.justfortesting"> <uses-permission

    android:name="android.permission.INTERNET"></uses-permission> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.JustForTesting"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="https"/> </intent-filter> </activity> </application> </manifest>
  69. Client class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?)

    { super.onCreate(savedInstanceState) val btn = Button(this) btn.text = "Browse" btn.setOnClickListener() { startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.com"))) } setContentView(btn) } }
  70. Browser class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?)

    { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val webView = findViewById<WebView>(R.id.myWebView); webView.settings.javaScriptEnabled = true val uri : Uri? = this.intent.data if(uri != null) { webView.loadUrl(uri.toString()); } else { webView.loadUrl("https://www.google.com") } } } 93
  71. Why Layouts? • UI is built on top of layout

    • Android diverse ecosystem • Several different resolutions and densities! • Layout helps to create layout for different screen sizes
  72. Width and Height • Fixed • 42dp, 17px, etc •

    Match the parent’s size • “As big as my parent” • MATCH_PARENT (in older version FILL_PARENT) • Best fit • “As big as needed for my content” • WRAP_CONTENT
  73. MATCH_PARENT vs FILL_PARENT • MATCH_PARENT or FILL_PARENT: View requests to

    be as big as its parent! • FILL_PARENT is depricated, use MATCH_PARENT • They both have same value, they do the same • Why Change? FILL_PARENT is confusing
  74. wrap_content <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"

    tools:context="exercises.company.fi.serviceexample.MainActivity"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 1" android:onClick="onButtonClick"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 2" android:onClick="onButtonClick"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 3" android:onClick="onButtonClick"/> </LinearLayout>
  75. layout_width = match_parent <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"

    android:layout_height="match_parent" android:orientation="vertical" tools:context="exercises.company.fi.serviceexample.MainActivity"> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button 1" android:onClick="onButtonClick"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button 2" android:onClick="onButtonClick"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button 3" android:onClick="onButtonClick"/> </LinearLayout>
  76. layout_height = match_parent <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"

    android:layout_height="match_parent" android:orientation="vertical" tools:context="exercises.company.fi.serviceexample.MainActivity"> <Button android:layout_width="match_parent" android:layout_height="match_parent" android:text="Button 1" android:onClick="onButtonClick"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button 2" android:onClick="onButtonClick"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button 3" android:onClick="onButtonClick"/> </LinearLayout> This is big as parent!
  77. layout_height = match_parent <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"

    android:layout_height="match_parent" android:orientation="vertical" tools:context="exercises.company.fi.serviceexample.MainActivity"> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button 1" android:onClick="onButtonClick"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button 2" android:onClick="onButtonClick"/> <Button android:layout_width="match_parent" android:layout_height="match_parent" android:text="Button 3" android:onClick="onButtonClick"/> </LinearLayout> This is NOT as big as parent! LinearLayout honors requests of it's child views but cannot guarantee them. The height of the third button is consequence of position!
  78. layout_weight <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"

    tools:context="exercises.company.fi.serviceexample.MainActivity"> <Button android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="0.33" android:text="Button 1" android:onClick="onButtonClick"/> <Button android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="0.33" android:text="Button 2" android:onClick="onButtonClick"/> <Button android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="0.33" android:text="Button 3" android:onClick="onButtonClick"/> </LinearLayout> Improve layout efficiency by setting heigth to 0
  79. layout_weight <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"

    tools:context="exercises.company.fi.serviceexample.MainActivity"> <Button android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="0.5" android:text="Button 1" android:onClick="onButtonClick"/> <Button android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="0.5" android:text="Button 2" android:onClick="onButtonClick"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button 3" android:onClick="onButtonClick"/> </LinearLayout>
  80. layout_weight <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"

    tools:context="exercises.company.fi.serviceexample.MainActivity"> <Button android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:text="Button 1" android:onClick="onButtonClick"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button 2" android:onClick="onButtonClick"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button 3" android:onClick="onButtonClick"/> </LinearLayout>
  81. Common Layouts • LinearLayout • Views in line, either vertically

    or horizontally • RelativeLayout • Define positions of each other child view relative to each other and screen boundaries • TableLayout • Rows and Columns • FrameLayout • FrameLayout is designed to display a single item at a time. You can have multiple elements within a FrameLayout but each element will be positioned based on the top left of the screen. Elements that overlap will be displayed overlapping. • AbsoluteLayout (Depricated) • Use coordinates • And others…
  82. Defining Layout • Portrait mode: • res/layout/main.xml • Landscape mode:

    • res/large-layout-land/main.xml • Each Activity can have it's own layout • setContentView(R.layout.main);
  83. Example of Layout <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent"

    android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/hello"/> </LinearLayout>
  84. Common Attributes Attribute Description Notes layout_width Specifies the width of

    the View or ViewGroup layout_height Specifies the height of the View or ViewGroup layout_marginTop Specifies extra space on the top side of the View or ViewGroup layout_marginBottom Specifies extra space on the bottom side of the View or ViewGroup layout_marginLeft Specifies extra space on the left side of the View or ViewGroup layout_marginRight Specifies extra space on the right side of the View or ViewGroup layout_gravity Specifies how child Views are positioned Only in LinearLayout or TableLayout layout_weight Specifies the ratio of Views Only in LinearLayout or TableLayout
  85. Example of Layout with Gravity and Weight <?xml version="1.0" encoding="utf-8"?>

    <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button A" /> <Button android:layout_width="wrap_content" android:layout_height="0dip" android:text="Button B" android:layout_gravity="right" android:layout_weight="0.5" /> <Button android:layout_width="match_parent" android:layout_height="0dip" android:text="Button C" android:layout_weight="0.5" /> </LinearLayout>
  86. <?xml version="1.0" encoding="utf-8"?> <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:stretchColumns="1" tools:context="fi.tamk.myapplication.MainActivity"> <TableRow> <TextView android:text="E-mail:" /> <EditText android:id="@+id/email" /> </TableRow> <TableRow> <TextView android:text="Password:" /> <EditText android:id="@+id/password" android:password="true" /> </TableRow> <TableRow> <TextView /> <CheckBox android:id="@+id/rememberMe" android:text="Remember Me" /> </TableRow> <TableRow> <TextView /> <Button android:id="@+id/signIn" android:text="Log In"/> </TableRow> </TableLayout> Children under TableRow are width MATCH_PARENT and height WRAP_CONTENT Define the column that will expand to take rest of the available space TableRow width is MATCH_PARENT and height WRAP_CONTENT
  87. TableLayout and ShrinkColumns <?xml version="1.0" encoding="utf-8"?> <TableLayout> <TableRow> <Button android:text="1"/>

    <Button android:text="2"/> <Button android:text="3"/> <Button android:text="4"/> <Button android:text="5"/> </TableRow> </TableLayout>
  88. TableLayout and ShrinkColumns <?xml version="1.0" encoding="utf-8"?> <TableLayout android:shrinkColumns="*"> <TableRow> <Button

    android:text="1"/> <Button android:text="2"/> <Button android:text="3"/> <Button android:text="4"/> <Button android:text="5"/> </TableRow> </TableLayout>
  89. TableLayout and Weight <?xml version="1.0" encoding="utf-8"?> <TableLayout > <TableRow> <Button

    android:text="1" android:layout_weight="1" android:layout_width="0dp"/> <Button android:text="2" android:layout_weight="2" android:layout_width="0dp"/> <Button android:text="3" android:layout_weight="3" android:layout_width="0dp"/> <Button android:text="4" android:layout_weight="4" android:layout_width="0dp"/> <Button android:text="5" android:layout_weight="5" android:layout_width="0dp"/> </TableRow> </TableLayout>
  90. TableLayout and Weight <?xml version="1.0" encoding="utf-8"?> <TableLayout > <TableRow> <Button

    android:text="1" android:layout_weight="1" android:layout_width="0dp"/> <Button android:text="2" android:layout_weight="1" android:layout_width="0dp"/> <Button android:text="3" android:layout_weight="1" android:layout_width="0dp"/> <Button android:text="4" android:layout_weight="1" android:layout_width="0dp"/> <Button android:text="5" android:layout_weight="1" android:layout_width="0dp"/> </TableRow> </TableLayout>
  91. RelativeLayout • RelativeLayout lays out elements based on their relationships

    with one another, and with the parent container. • It’s possible to put TextView center of the screen and other Views related to that
  92. <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="fi.tamk.myapplication.MainActivity"> <EditText android:hint="username" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_above="@id/password" android:layout_centerHorizontal="true"/> <EditText android:hint="password" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_above="@id/signIn" android:inputType="textPassword" android:id="@+id/password" android:layout_centerHorizontal="true"/> <Button android:id="@+id/signIn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Log In" android:layout_centerInParent="true"/> </RelativeLayout>
  93. FrameLayout <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="fi.tamk.myapplication.MainActivity"> <ImageView android:src="@mipmap/ic_launcher" android:layout_height="match_parent" android:layout_width="match_parent"/> <TextView android:text="Hello World!" android:textSize="24sp" android:textColor="#000000" android:layout_height="match_parent" android:layout_width="match_parent" android:gravity="center"/> </FrameLayout>
  94. ConstraintLayout • New layout style coming in next versions of

    Android • Available in Android Studio 2.2 preview • Very similar to iOS constraints
  95. The Buttons in layout/main.xml ... <TableRow android:id="@+id/TableRow01" ...> <Button android:id="@+id/Button07"

    style="@style/myButton" android:text="7" /> <Button android:id="@+id/Button08" style="@style/myButton" android:text="8" /> <Button android:id="@+id/Button09" style="@style/myButton" android:text="9" /> <Button android:id="@+id/ButtonDivide" style="@style/myButton" android:text="/" /> </TableRow> ...
  96. Styles in values/styles.xml <resources> <!-- Base application theme. --> <style

    name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style> <style name="myButton" parent="@android:style/TextAppearance"> <item name="android:textSize">30sp</item> <item name="android:textColor">#000000</item> <item name="android:layout_height">match_parent</item> <item name="android:layout_weight">1</item> </style> </resources>
  97. Some Common Widgets • TextView • Label • EditText •

    Editable text • ListView • View group that manages a group of Views. • Spinner • TextView associated with ListView. Let's you select an item from a list. • Button • Standard push button • CheckBox • Standard checkbox • RadioButton • Standard radiobutton • See documentation how to use these!
  98. activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="fi.tamk.myapplication.MainActivity"> <ListView android:id="@+id/list" android:layout_height="match_parent" android:layout_width="match_parent"> </ListView> </LinearLayout>
  99. Activity public class MainActivity extends AppCompatActivity { @Override protected void

    onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView listView = (ListView) findViewById(R.id.list); // Context context, int resource, int textViewResourceId, ArrayAdapter<String> myAdapter = new ArrayAdapter(this, R.layout.list_item, R.id.myTextView); myAdapter.add("A"); myAdapter.add("B"); myAdapter.add("C"); myAdapter.add("D"); listView.setAdapter(myAdapter); } }
  100. Activity: using loop public class MainActivity extends AppCompatActivity { @Override

    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView listView = (ListView) findViewById(R.id.list); // Context context, int resource, int textViewResourceId, ArrayAdapter<String> myAdapter = new ArrayAdapter(this, R.layout.list_item, R.id.myTextView); int FIRST = (int) 'A'; int LAST = (int) 'Z'; for(int i=FIRST; i<=LAST; i++) { String line = "" + (char) i; myAdapter.add(line); } listView.setAdapter(myAdapter); } }
  101. Activity: using Array public class MainActivity extends AppCompatActivity { final

    String [] ALPHABET = {"A", "B", "C"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView listView = (ListView) findViewById(R.id.list); ArrayAdapter<String> myAdapter = new ArrayAdapter(this, R.layout.list_item, R.id.myTextView, ALPHABET); listView.setAdapter(myAdapter); } }
  102. Activity: using toString public class MainActivity extends AppCompatActivity { class

    Point { int x; int y; public Point(int x, int y) { this.x = x; this.y = y; } public String toString() { return "(x = " + x + ", y = " + y + ")"; } } final Point [] points = {new Point(0,0), new Point(1,1), new Point(2,2)}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView listView = (ListView) findViewById(R.id.list); ArrayAdapter<Point> myAdapter = new ArrayAdapter(this, R.layout.list_item, R.id.myTextView, points); listView.setAdapter(myAdapter); } }
  103. ListActivity public class MainActivity extends ListActivity { private String TAG

    = "MainActivity"; private final String[] COUNTRIES = { "Afghanistan", "Albania", "Algeria" }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setListAdapter(new ArrayAdapter(this, R.layout.list_item, COUNTRIES)); ListView lv = getListView(); lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { TextView tv = (TextView) view; String text = tv.getText().toString(); Toast.makeText(MainActivity.this, text, Toast.LENGTH_LONG).show(); } }); } }
  104. ListView vs RecycledView • RecycledView is more advanced version of

    ListView • RecycledView • Reuses cells while scrolling up/down • This is done by using View Holder. This is optional in ListView, in RecycledView it's default. • Animates common list actions • Manual Data source • Instead of using XAdapter classes, you will have to build a custom adapter (RecyclerView.adapter) 136
  105. RecyclerView • It's efficient, only number of views in memory

    while data can be large • Uses ViewHolder pattern to improve performance • Use it when elements change in runtime based on user action or network events • Has a layout manager for positioning items and default animations for common operations • You have to specify adapter and layout manager • It's part of separate library, add • compile 'com.android.support:recyclerview-v7:23.4.0'
  106. Layout Manager • Layout manager positions item views inside a

    RecyclerView • reuse is handled also • Three built-in layout managers • LinearLayoutManager • vertical or horizontal list • GridLayoutManager • items in a grid • StaggeredGridLayoutManager • items in a staggered list 138
  107. Using RecyclerView • Add RecyclerView support library to gradle build

    file • compile 'com.android.support:recyclerview-v7:23.4.0' • Create model class • this can be whatever class, usually uses some kind of List, for example ArrayList • Create RecyclerView in your Layout file (activity_main.xml) • <android.support.v7.widget.RecyclerView android:id="" ... /> • Create Custom Row Layout (item.xml) • <TextView .../> • Create Custom Adapter Class • Role is to convert and object at a position into a list row item to be inserted • The adapter class should contain inner ViewHolder class that holds all the views in one row • In addition to this, three primary methods • onCreateViewHolder – inflate the item layout and create the holder • onBindViewHolder – set the view attributes based on the data • getItemCount – return number of items 139
  108. activity_main.xml <?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:id="@+id/my_recycler_view" android:scrollbars="vertical" tools:context="fi.sovelto.recycledview"> </android.support.v7.widget.RecyclerView> 140
  109. Activity Example public class MainActivity extends AppCompatActivity { private RecyclerView

    mRecyclerView; private LinearLayoutManager mLayoutManager; private MyAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view); // use this setting to improve performance if you know that changes // in content do not change the layout size of the RecyclerView mRecyclerView.setHasFixedSize(true); // use a linear layout manager mLayoutManager = new LinearLayoutManager(this); mRecyclerView.setLayoutManager(mLayoutManager); ArrayList<String> text = new ArrayList<String>(); text.add("hello"); text.add("world"); mAdapter = new MyAdapter(text); mRecyclerView.setAdapter(mAdapter); } } 141
  110. 143 /** * Custom adapter is mandatory. Create class that

    extends * RecyclerView.Adapter<X extends RecyclerView.ViewHolder> */ public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> { // The model private ArrayList<String> model; // Provide a suitable constructor (depends on the kind of dataset) public MyAdapter(ArrayList<String> model) { this.model = model; } // Return the size of your dataset (invoked by the layout manager) @Override public int getItemCount() { return model.size(); } // Inflate the data row layout and return it inside of View Holder @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { ... } // Replace the contents of a data row (invoked by the layout manager) @Override public void onBindViewHolder(MyViewHolder holder, int position) { ... } public void add(String item) { model.add(item); notifyItemInserted(model.size()-1); } public void remove(String item) { int pos = model.indexOf(item); model.remove(pos); notifyItemRemoved(pos); } } // Provides a direct access to all views in one data row // This is used to cache the view within the item layout // for fast access class MyViewHolder extends RecyclerView.ViewHolder { // Each data item is just a TextView in this case public TextView textView; // Also constructor must be implemented. The argument here is the // root layout of the data item. From this lookup is done for each // subview public MyViewHolder(View dataRow) { super(dataRow); textView = (TextView) dataRow.findViewById(R.id.myTextView); } }
  111. 144 /** * Custom adapter is mandatory. Create class that

    extends * RecyclerView.Adapter<X extends RecyclerView.ViewHolder> */ public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> { ... // Inflate the data row layout and return it inside of View Holder @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // create a new data row View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); // pass it to the view holder and return a view holder MyViewHolder vh = new MyViewHolder(v); return vh; } // Replace the contents of a data row (invoked by the layout manager) @Override public void onBindViewHolder(MyViewHolder holder, int position) { // - get element from your dataset at this position // - replace the contents of the view with that element final String name = model.get(position).toString(); holder.textView.setText(name); holder.textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { remove(name); } }); } }
  112. About Menus • Common UI component in many types of

    apps • Beginning from Android 3.0 (API Level 11) android devices may not hold a dedicated menu – button! • Use instead ActionBar • Hopefully implementing ActionBar is really simple and 99% same than menus
  113. AppCompatActivity • AppCompatActivity is a base class for Activities and

    it's found from Android Support AppCompat Library • Support for Action Bar Features from API LEVEL 7 -> • Provides implementation for ActionBar
  114. Adding Callback methods public class TestActivity extends AppCompatActivity { @Override

    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); } // Modify menu items dynamically. Disable/enable menu items. @Override public boolean onPrepareOptionsMenu(Menu menu) { } // Create your menu here @Override public boolean onCreateOptionsMenu(Menu menu) { } // When menu item is selected @Override public boolean onOptionsItemSelected(MenuItem item) { } }
  115. menu/mainmenu.xml <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:title="A" app:showAsAction="ifRoom"

    android:id="@+id/clickMe"></item> <item android:title="B" app:showAsAction="ifRoom"></item> <item android:title="C" app:showAsAction="ifRoom"></item> <item android:title="D" app:showAsAction="ifRoom"></item> <item android:title="E" app:showAsAction="ifRoom"></item> <item android:title="F" app:showAsAction="ifRoom"></item> </menu>
  116. Event Handling in Menus // Modify menu items dynamically. Disable/enable

    menu items. @Override public boolean onPrepareOptionsMenu(Menu menu) { MenuItem m = menu.findItem(R.id.clickMe); m.setEnabled(false); return true; } // Create your menu here @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.mainmenu, menu); return true; } // When menu item is selected @Override public boolean onOptionsItemSelected(MenuItem item) { super.onOptionsItemSelected(item); switch (item.getItemId()) { case (R.id.clickMe): Toast.makeText(this, "click", Toast.LENGTH_LONG).show(); return true; } return false; }
  117. Notications • Toast Notification • Brief message • Toast •

    Dialog Notification • Activity-related notification • AlertDialog, DatePickerDialog, TimePickerDialog • Status Bar Notification • Persistent reminder
  118. Notications • Toast Notification • Brief message • Toast •

    Dialog Notification • Activity-related notification • AlertDialog, DatePickerDialog, TimePickerDialog • Status Bar Notification • Persistent reminder
  119. Toast • Simple Feedback about an operation in a small

    popup • No user response • Also very good for debugging purposes!
  120. Toast: Example Toast toast = Toast.makeText(this, "Message saved as draft.",

    Toast.LENGTH_SHORT); toast.show(); Toast.makeText(this, "One liner", Toast.LENGTH_SHORT).show();
  121. Dialogs • A dialog is a small window that prompts

    the user to make a decision or enter additional information
  122. Dialogs • You can use subclasses of Dialog: • AlertDialog

    • DatePickerDialog • TimePickerDialog
  123. DialogFragment • DialogFragment class helps you to manage correctly lifecycle

    events such as back- button pressing or rotating the screen • Also allows reusing of dialog's UI as an embeddable component in larger UI • DialogFragment is available from API Level 11 -> • Support Library also available for older devices. • Extend DialogFragment, implement newInstance, onCreate, and onCreateView for custom dialogs
  124. Example private void showMyDialog(String text) { MyDialogFragment dialog = MyDialogFragment.newInstance(text);

    dialog.show(getSupportFragmentManager(), "dialog"); } public static class MyDialogFragment extends DialogFragment { public static MyDialogFragment newInstance(String text) { MyDialogFragment frag = new MyDialogFragment(); Bundle args = new Bundle(); args.putString("text", text); frag.setArguments(args); return frag; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { String text = getArguments().getString("text"); // Use the Builder class for convenient dialog construction AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setMessage(text) .setPositiveButton("Ok", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { } }) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // User cancelled the dialog } }); // Create the AlertDialog object and return it return builder.create(); } }
  125. Notifications • Notification is a message you can display to

    the user outside of your app's normal UI. • When issuing notification, it appears as an icon in the notification area • To see more details, user opens the notification drawer.
  126. Status Bar Notification • Two versions • Normal view •

    Big view (4.1 ->) • If your app is working in the background, give status bar notifications
  127. Normal View • Normal view appears in area up to

    64dp tall • Holds 1) Content title, 2) Large icon, 3) Content text, 4) Content info, 5) Small icon, 6) Time notification was issued
  128. Big View • Big View appears when notification is expanded

    • Available 4.1 -> • Difference: 7) Details area
  129. The Basics • Specify your nofication using NotificationCompat.Builder object •

    Use NotificationCompat.Builder.build() for building the notification object • call notify() when needed • Notification must contain: 1) small icon, 2) title and 3) detail text • Service can launch status bar notification!
  130. Building the Notification public void displayNotification(String text) { // Create

    notification. Use compat library for backward compatibility. NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this); mBuilder.setSmallIcon(R.mipmap.ic_launcher); mBuilder.setContentTitle("User Selection"); mBuilder.setContentText(text); Notification notification = mBuilder.build(); NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); int mId = 1; // mId allows you to update the notification later on. mNotificationManager.notify(mId , notification); }
  131. Notification Actions • Although optional, you should provide one action

    to notification • Allows user to go to your app from the notification • Starting an activity when the user clicks the notification is the most common scenario • NotificationManager is different app from your app and it needs special permissions to open your activity. • Instead of using Intent, you use PendingIntent. • See: http://developer.android.com/guide/topics/ui/notifiers/notifications.html
  132. About Fragments • Fragments are “subactivity”; modular section inside the

    activity. • You can add and remove fragments at runtime • Fragment has it’s own UI (.xml file) • Feature that came in API Level 11 -> need to have support library if targeting older devices
  133. Creating a Fragment • Subclass of Fragment • Implement lifecycle

    methods that are similar to Activity’s. • onCreate, onStart, onPause, onStop.. • Implement at least • onCreate • Initialize essential components • onCreateView • Return View – object that is the root of your fragment’s layout • onPause • User is leaving the fragment
  134. Example Fragment: MainActivity.java public class MainActivity extends Activity { @Override

    public void onCreate(Bundle b) { super.onCreate(b); setContentView(R.layout.main); } }
  135. Example Fragment: main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"

    android:orientation="horizontal" > <fragment android:id="@+id/fragment1" android:name="com.example.fragmentexample.LeftFragment" android:layout_width="0dp" android:layout_weight="0.5" android:layout_height="match_parent" /> <fragment android:id="@+id/fragment2" android:name="com.example.fragmentexample.RightFragment" android:layout_width="0dp" android:layout_weight="0.5" android:layout_height="match_parent" /> </LinearLayout>
  136. Example Fragment: LeftFragment.java public class LeftFragment extends Fragment { public

    View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Button tv = new Button(getActivity()); tv.setText("left!"); return tv; } }
  137. Example Fragment: RightFragment.java public class RightFragment extends Fragment { public

    View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Button tv = new Button(getActivity()); tv.setText("right!"); return tv; } }
  138. Fragment may hold XML too! public class RightFragment extends Fragment

    { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Let’s remove these // Button tv = new Button(getActivity()); // tv.setText("right!"); // return tv; // Creates Java object from the given XML file. View view = inflater.inflate(R.layout.right_fragment, // The xml file container, false); return view; } }
  139. FragmentManager • FragmentManager class provides methods that allow you to

    add, remove and replace fragments to on activity at runtime. • Don’t add fragments to .xml, but perform transaction in Java • See: • https://developer.android.com/training/basics/fragments/fragment- ui.html
  140. Communication Between Fragments • Build each Fragment UI as separate!

    • Do Fragment -> Fragment communication through Activity • Fragment A -> Activity • Use your own interface, activity can be whatever • Activity -> Fragment B • Use FragmentManager to get a reference to Fragment B and call it’s public methods
  141. public class ButtonFragment extends Fragment { // Helper interface for

    communicating with Activity public interface OnButtonClickedListener { public void buttonClicked(); } // Host Activity is here private OnButtonClickedListener callback; // When creating this fragment, host activity must be given and it must // implement OnButtonClickedListener interface. Method is called when fragment has // been associated with activity. The Activity is passed here! @Override public void onAttach(Context activity) { super.onAttach(activity); callback = (OnButtonClickedListener) activity; } public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Creates Java object from the given XML file. View view = inflater.inflate(R.layout.button_fragment, // The xml file container, false); Button sent = (Button) view.findViewById(R.id.button1); // When button is clicked, call activity's buttonClicked method sent.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { callback.buttonClicked(); } }); return view; } }
  142. Activity public class MainActivity extends Activity implements ButtonFragment.OnButtonClickedListener { @Override

    public void onCreate(Bundle b) { super.onCreate(b); // Holds ButtonFragment setContentView(R.layout.main); } // This is called when button is pressed in the fragment! @Override public void buttonClicked() { } }
  143. Use layout/ directories • layout/main.xml • One dim layout (holds

    Fragment A) • layout-land/main.xml • Two dim layout (holds Fragment A + B) • layout-large/main.xml • Two dim layout (holds Fragment A + B)
  144. public class MainActivity extends Activity implements ButtonFragment.OnButtonClickedListener { @Override public

    void onCreate(Bundle b) { super.onCreate(b); // Holds either two-dim or on-dim layout! hold either // 1) left-pane or // 2) left-pane and right-pane setContentView(R.layout.main); } // This is called when button is pressed in the fragment! @Override public void buttonClicked() { // Let's get a reference to the right fragment RightPaneFragment rightPaneFragment = (RightPaneFragment) getFragmentManager() .findFragmentById(R.id.right_fragment); // If it's not accessible, we are in one-dim layout if (rigthPaneFragment == null) { startNewActivity(); } else { updateRightPane(); } } private void startNewActivity() { Intent showContent = new Intent(this, RightActivityPane.class); // This activity holds RightPaneFragment startActivity(showContent); } private void updateRightPane(RightPaneFragment rightPaneFragment) { rightPaneFragment.doSomething(); } }
  145. Services • A facility for the application to tell the

    system about something it wants to be doing in the background • background music • fetching data over network. • file i/o • .. • Activity may be frozen when user moves to another Activity. Service can go on in the background.
  146. About Services • Service is NOT a separate process or

    thread • Provides two features • Tell the system, that we want to do something in the background. (startService()) • Even if the app closes! • The ability to expose functionality to other apps (bindService()) • Service is a simple class, you must implement separate threads by yourself. • Modify the Manifest – file!
  147. Started and Bounded Service • Started Service • Service is

    started when an app component calls startService() • Service can run in background forever. Usually started service performs a single operation and does not return to caller • When operation is done, the service should stop itself • Bounded Service • Service is bounded when app component binds to it by calling bindService() • Bound service may interact with the service (not just start and stop). • Bound Service is run only as long as app is bound to the service • Service can be both, run indefinately and allow bounding
  148. Example of Service public class MyService extends Service { /*

    If client is binded to service, this method is called. Your implementation must return an object that implements IBinder interface. If you don't need this, just return null. */ @Override public IBinder onBind(Intent arg0) { return null; } @Override public void onDestroy() { } /* When Activity calls startService(..), this method is invoked. Service is started and it's running until stopService or stopSelf() is called */ @Override public int onStartCommand(Intent intent, int flags, int startId) { return START_STICKY; } @Override public void onCreate() { } }
  149. Example: Java public class MainActivity extends Activity implements OnClickListener{ @Override

    public void onClick(View v) { if (v == startService) { Intent intent = new Intent(this, MyService.class); startService(intent); } else if (v == stopService) { Intent intent = new Intent(this, MyService.class); stopService(intent); } } }
  150. Example: Kotlin class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState:

    Bundle?) { super.onCreate(savedInstanceState) val layout = LinearLayout(this) val start = Button(this) val stop = Button(this) layout.addView(start) layout.addView(stop) setContentView(layout) val intent = Intent(this, MyService::class.java) start.setOnClickListener() { startService(Intent(intent)) } stop.setOnClickListener() { stopService(Intent(intent)) } } } 193
  151. Example: Thread and Java class MyService extends Service implements Runnable

    { private boolean isRunning; private final static String TAG = "MyService"; private Thread thread; @Override public IBinder onBind(Intent arg0) { return null; } @Override public void onDestroy() { isRunning = false; } @Override public void public int onStartCommand(Intent intent, int flags, int startId) { if(!isRunning) thread.start(); return START_STICKY; } @Override public void onCreate() { isRunning = false; thread = new Thread(this); } @Override public void run() { isRunning = true; while(isRunning) { try { Log.d(TAG, "Service running..."); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
  152. Example: Mediaplayer and Kotlin class MyService: Service() { private var

    mp : MediaPlayer? = null override fun onBind(p0: Intent?): IBinder? { return null } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { mp = MediaPlayer.create(this, R.raw.mysound) mp?.start() return START_STICKY } override fun onDestroy() { Log.d("TAG", "Destroy") mp?.stop() } } 195
  153. Example <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="fi.tamk" android:versionCode="1" android:versionName="1.0"> <application

    android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".CallMe" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:enabled="true" android:name=".MyService" /> </application> </manifest>
  154. IntentService • IntentService has separate thread built in! • Class

    inherites IntentService, overrides onHandleIntent() • Everything is done on separate thread • Cannot directly interact with UI • Stops itself when work is done • No way to stop it using code like stopSelf
  155. Example public class RSSPullService extends IntentService { @Override protected void

    onHandleIntent(Intent workIntent) { // Gets data from the incoming Intent String dataString = workIntent.getDataString(); ... // Do work here, based on the contents of dataString ... } }
  156. About Bound Services • Create bound service, if you want

    to • Interact with the service from activities or other components • Expose some of app’s functionality to other apps (IPC) • To create bound service, implement onBind() • A bound service typically lives only while it serves another application component and does not run in the background indefinitely
  157. Creating a Bound Service • Private Service for your own

    app • Extend Binder class • Example: music application that needs to bind an activity to its own service that's playing music in the background. • Service for other apps (work across processes) • Use a Messenger
  158. Extending Binder • If your service is private to your

    app, you can use Binder • Binder? Defines programming interface that clients can use • Binder can • Contain public method that the client can call • Return the Service object itself, so all the public methods from the service is available
  159. How? • Service • Create the Binder object in your

    Service • Return the object in onBind() method • Client • Receive Binder object from onServiceConnected - method
  160. public class MyService extends Service { private static final String

    TAG = "MyService"; private IBinder mBinder; @Override public IBinder onBind(Intent intent) { Log.d(TAG, "onBind()"); // Returns IBinder, which "wraps" MyService inside.. return mBinder; } @Override public void onDestroy() { Log.d(TAG, "onDestroy()"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStart()"); return START_STICKY; } @Override public void onCreate() { Log.d(TAG, "onCreate()"); mBinder = new LocalBinder(this); } public double getRandomNumber() { return Math.random(); } } import android.os.Binder; // Binder is a base class for a remotable object. // Binder implements IBinder which has several methods. public class LocalBinder extends Binder { private MyService service; public LocalBinder(MyService service) { this.service = service; } // Let's add our own method that binded activities // can invoke. In this case, we will create a method // that returns the whole service object so it's possible // to invoke all the services methods, like "someMethod". public MyService getService() { return this.service; } }
  161. Client • Client can bind to service by calling bindService()

    • bindService() – method needs ServiceConnection object, which monitors the connection of the service • bindService() returns immediately, but ServiceConnection’s onServiceConnected is called to deliver the Binder to the client
  162. public class MainActivity extends AppCompatActivity { private ServiceConnection connectionToService; private

    boolean isBounded = false; private MyService myService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); connectionToService = new MyServiceConnection(); } @Override protected void onStart() { super.onStart(); // Bind to LocalService Intent intent = new Intent(this, MyService.class); // Create the service as long as binding exists bindService(intent, connectionToService, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); if (isBounded) { unbindService(connectionToService); isBounded = false; } } public void onButtonClick(View v) { if (isBounded) { double num = myService.getRandomNumber(); Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show(); } } class MyServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { // We've bound to LocalService, cast the IBinder and get LocalService instance LocalBinder binder = (LocalBinder) service; myService = binder.getService(); isBounded = true; } @Override public void onServiceDisconnected(ComponentName name) { isBounded = false; } } }
  163. Broadcast Receivers • A broadcast receiver is a component that

    does nothing but receive and react to broadcast announcements • Your app can • 1) Receive and react to system services (example: battery low) • 2) Receive and react to other apps broadcast announcements • 3) Initiate broadcasts to other apps
  164. Registering • To register Broadcast Receiver, you can • 1)

    Dynamically register with registerReceiver (in code) • 2) Statically public receiver and <register> tag in AndroidManifest.xml • Note: if you are doing this dynamically and you are working in local, you don't have modify manifest – file.
  165. 1. Registering in Code public class Main extends Activity {

    MyBroadCastReceiver s; IntentFilter filter; @Override public void onResume() { super.onResume(); filter = new IntentFilter("android.intent.action.TIME_TICK"); s = new MyBroadCastReceiver(); registerReceiver(s, filter); } @Override public void onPause() { super.onPause(); unregisterReceiver(s); } }
  166. BroadcastReceiver public class MyBroadCastReceiver extends BroadcastReceiver { @Override public void

    onReceive(Context context, Intent intent) { Log.d("MyBroadCastReceiver", "Time Tick"); } }
  167. 2. Registering Broadcast Receiver in Manifest <?xml version="1.0" encoding="utf-8"?> <manifest

    xmlns:android="http://schemas.android.com/apk/res/android" package="fi.tamk" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".Main" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".MyBroadCastReceiver" android:enabled="true"> <intent-filter> <action android:name="android.intent.action.TIME_TICK" /> </intent-filter> </receiver> </application> </manifest>
  168. Sending Broadcast • Broadcast is sent using Intent and sendBroadcast

    • Example: Intent intent = new Intent("fi.company.DETECTION"); sendBroadcast(intent);
  169. LocalBroadCastManager • Helper class for registering and sending broadcasts of

    Intents to local objects within your process • data won't leave the app (private data) • more efficient • Example • LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this); manager.sendBroadcast(new Intent("..."));
  170. 4. Content Providers • A content provider makes a specific

    set of the application's data available to other applications • => Share data to other apps • Any app with appropriate permission, can read and write the data. • Many native databases are available via the content providers, for example Contact Manager • Files, SQL database • Common interface for querying the data
  171. build.gradle apply plugin: 'com.android.application' android { compileSdkVersion 23 buildToolsVersion '23.0.2'

    defaultConfig { applicationId "com.example.j..." minSdkVersion 10 targetSdkVersion 23 versionCode 1 versionName "1.0" } } Should work from android 2.3.3 -> Can't be installed on older devices Your app is tested with this SDK.
  172. Support Library • Set of code libraries that provide backward

    compatibility Library Description V4 support library Designed for android 1.6 ->. For example fragments V7 support library Designed for android 2.2 -> requires V4 V7 appcompat library Support for actionbar and material design user interface V7 cardview and recyclerview Support for the widgets
  173. Example Usage: ActionBar import android.os.Build; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import

    android.os.Bundle; import android.util.Log; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ActionBar actionBar = getSupportActionBar(); actionBar.setSubtitle("hello"); actionBar.setTitle("Hello World"); } }
  174. Check version runtime public class Main2Activity extends Activity { @Override

    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // ObjectAnimator was added from API LEVEL 11 (Honeycomb) -> TextView tv = (TextView) findViewById(R.id.textView); ObjectAnimator anim = ObjectAnimator.ofFloat(tv, "alpha", 0f, 1f); anim.setDuration(1000); anim.start(); } } }
  175. Location Services and Maps • Android provides location framework that

    your app can use to determine • Device’s location • Listening for updates • Google maps external library available for displaying and managing maps
  176. Location Services • By using LocationManager you are able to

    • Query for the list of LocationProviders for the last known location • Register for updates of the user’s current location • Register for given Intent to be fired if the device comes within given proximity of given lat/long
  177. Obtaining User Location • Location can be determined via GPS

    and/or cell tower + Wi-Fi signals • GPS is accurate, but needs outdoors, fix is slower and it uses more battery. • To request location, you use LocationManager - class
  178. class Something extends Activity implements LocationListener { public void initializeLocation()

    { // Acquire a reference to the system Location Manager LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); // Register the listener with the Location Manager to receive location updates locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this); } public void onLocationChanged(Location location) { // Called when a new location is found by the network location provider. // doSomething(location); } public void onStatusChanged(String provider, int status, Bundle extras) {} public void onProviderEnabled(String provider) {} public void onProviderDisabled(String provider) {} } Can be also GPS_PROVIDER Control the frequency which listener receives updates; min time and min distance
  179. Requesting User Permissions • When using API LEVEL 23 permission

    model has changed! • You must add permissions in order to get user location • ACCESS_COARSE_LOCATION • If you use NETWORK_PROVIDER • ACCESS_FINE_LOCATION • If you use GPS_PROVIDER or NETWORK_PROVIDER
  180. Getting Last Known Location • First location can take time.

    Use cached location! • Location lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER );
  181. System Permissions • Basic Android app has no permissions associated

    by default • To make use of protected features of the device, include <uses-permission> in manifest • Example • <uses-permission android:name="android.permission.RECEIVE_SMS" />
  182. Normal vs Dangerous permissions • Normal permission • Small risk

    to user's privacy or device operation • System automatically grants these permissions • Designated as PROTECTION_NORMAL • ACCESS_WIFI_STATE, VIBRATE, NFC, BLUETOOTH • Dangerous permission • System asks from user to grant these • Happens either • install time (device is <= API 22 or target 22 or lower) • prompting from user (device => API 23 AND target => 23)
  183. Using Normal Permission public class MainActivity extends AppCompatActivity { @Override

    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override protected void onResume() { super.onResume(); // java.lang.SecurityException: Requires VIBRATE permission! Vibrator v = (Vibrator) this.getSystemService(Context.VIBRATOR_SERVICE); v.vibrate(500); } }
  184. Adding permission <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="exercises.tieturi.fi.permissions"> <uses-permission android:name="android.permission.VIBRATE"/>

    <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
  185. Dangerous Permission <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="exercises.tieturi.fi.permissions"> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

    <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
  186. Target apply plugin: 'com.android.application' android { compileSdkVersion 23 buildToolsVersion "23.0.1"

    defaultConfig { applicationId "exercises.tieturi.fi.permissions" minSdkVersion 19 targetSdkVersion 23 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.1.1' } Target is set to 23
  187. public class MainActivity extends AppCompatActivity { private LocationManager locationManager; @Override

    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); // THIS WILL THROW AN SECURITY EXCEPTION locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, new Listener()); } class Listener implements LocationListener { @Override public void onLocationChanged(Location location) { Log.d("MainActivity", "latitude = " + location.getLatitude()); Log.d("MainActivity", "latitude = " + location.getLongitude()); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } } }
  188. Show the Dialog... final int PERMISSION_REQUEST_ID = 0; public void

    buttonPressed(View view) { // Let's check do we have permission // Will return either PackageManager.PERMISSION_GRANTED or PackageManager.PERMISSION_DENIED int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION); if(permissionCheck == PackageManager.PERMISSION_DENIED) { String [] listOfPermissions = {Manifest.permission.ACCESS_FINE_LOCATION}; ActivityCompat.requestPermissions(this, listOfPermissions, PERMISSION_REQUEST_ID); } else { ... } }
  189. Handle Result @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[]

    grantResults) { if(requestCode == PERMISSION_REQUEST_ID) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { try { locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, new Listener()); } catch(SecurityException e) { e.printStackTrace(); } } else { Toast.makeText(MainActivity.this, "Location Denied", Toast.LENGTH_SHORT) .show(); } } }
  190. UI Thread • When Android app is launched one thread

    is created. This thread is called Main Thread or UI Thread • UI Thread is responsible for dispatching events to widgets • Avoid doing time consuming tasks in UI Thread since it leads to app that does not respond quickly
  191. Testing UI Responsivess public class ThreadExample extends Activity implements OnClickListener

    { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Button button = new Button(this); button.setText("Do Time Consuming task!"); setContentView(button); button.setOnClickListener(this); } @Override public void onClick(View v) { try { for (int i = 0; i < 10; i++) { System.out.println(i); Thread.sleep(10000); } } catch (InterruptedException e) { e.printStackTrace(); } } }
  192. Testing Separate Thread public class MainActivity extends AppCompatActivity implements View.OnClickListener,

    Runnable { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Button button = new Button(this); button.setText("Do Time Consuming task!"); setContentView(button); button.setOnClickListener(this); } @Override public void onClick(View v) { Thread thread = new Thread(this); thread.start(); } @Override public void run() { try { for(int i=0; i<10; i++) { System.out.println(i); Thread.sleep(10000); } } catch (InterruptedException e) { e.printStackTrace(); } } }
  193. How about influencing the UI? public class MainActivity extends AppCompatActivity

    implements View.OnClickListener, Runnable { private Button button; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); button = new Button(this); button.setText("Do Time Consuming task!"); setContentView(button); button.setOnClickListener(this); } ... @Override public void run() { try { for(int i=0; i<10; i++) { button.setText("Iteration: " + i); Thread.sleep(10000); } } catch (InterruptedException e) { e.printStackTrace(); } } }
  194. Why? • Android UI Toolkit is not thread safe •

    If you want to manipulate UI, you must do it inside the UI thread • How do you do it then? You can use • Activity.runOnUiThread(Runnable) • View.post(Runnable) • View.postDelayed(Runnable, long) • …
  195. Activity.runOnUiThread(Runnable) • The given action (Runnable) is executed immediately if

    current thread is UI thread • If current thread is NOT UI thread, the action (Runnable) is posted to event queue of the UI Thread
  196. Example of RunOnUiThread public class MainActivity extends AppCompatActivity implements View.OnClickListener,

    Runnable { @Override public void onClick(View v) { Thread thread = new Thread(this); thread.start(); } @Override public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } runOnUiThread(new Update()); } class Update implements Runnable { // This action is posted to event queue public void run() { button.setText("Finished!"); } } }
  197. View.post(Runnable), View.postDelayed(Runnable, Long) • These methods are from view and

    are use for updating the view • Action (Runnable) is placed on Message Queue • Runnable action runs on UI Thread • postDelayed method for delayed action
  198. Using post public class MainActivity extends AppCompatActivity implements View.OnClickListener, Runnable

    { private Button button; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); button = new Button(this); button.setText("Do Time Consuming task!"); setContentView(button); button.setOnClickListener(this); } ... @Override public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } button.post(new Update()); } class Update implements Runnable { public void run() { button.setText("Finished!"); } } }
  199. Using Anonymous Inner Classes public class MainActivity extends AppCompatActivity implements

    View.OnClickListener { private Button button; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); button = new Button(this); button.setText("Do Time Consuming task!"); setContentView(button); button.setOnClickListener(this); } int iteration = 0; @Override public void onClick(View v) { new Thread(new Runnable() { public void run() { try { for(int i=0; i<10; i++) { iteration = i; button.post(new Runnable() { public void run() { button.setText("Iteration = " + iteration); } }); Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } } This can be really confusing...
  200. AsyncTask • Goal: take care thread management for you •

    Use it by subclassing it: class MyTask extends AsyncTask • Override onPreExecute(), onPostExecute() and onProgressUpdate() • Invokes in UI Thread • Override doInBackground() • Invokes in worker thread
  201. Example (Google SDK) private class DownloadFilesTask extends AsyncTask<URL, Integer, Long>

    { protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize = 0; for (int i = 0; i < count; i++) { totalSize += Downloader.downloadFile(urls[i]); publishProgress((int) ((i / (float) count) * 100)); } return totalSize; } protected void onProgressUpdate(Integer... progress) { setProgressPercent(progress[0]); } protected void onPostExecute(Long result) { showDialog("Downloaded " + result + " bytes"); } } new DownloadFilesTask().execute(url1, url2, url3); Params, Progress, Result
  202. Example public class MainActivity extends AppCompatActivity implements View.OnClickListener { @Override

    public void onClick(View v) { new MyBackgroundTask().execute(10); } class MyBackgroundTask extends AsyncTask<Integer, Integer, Integer> { protected Integer doInBackground(Integer... ints) { int max = ints[0]; int i=0; try { for(i=0; i<max; i++) { System.out.println("doInBackground!"); publishProgress(new Integer(i)); Thread.sleep(1000); } } catch(Exception e) { e.printStackTrace(); } return i; } protected void onProgressUpdate(Integer... iteration) { button.setText("Iteration = " + iteration[0].intValue()); } protected void onPostExecute(Integer result) { button.setText("Finished with result of: " + result); } } }
  203. HTTP Client • Android includes two HTTP clients • Apache

    HttpClient (DefaultHttpClient) • HttpURLConnection • Apache HttpClient • Large and flexible API, stable and few bugs • Google: "it's difficult to improve without breaking backward compatibility. Android team is not actively working on Apache Http Client" • HttpURLConnection • Lightweight HTTP Client for most apps. • Recommendation
  204. Classes • ConnectivityManager • Answers queries about the state of

    the network connectivity • NetworkInfo • Describes the status of the network
  205. Check Network Connection public void onClick(View v) { ConnectivityManager connMgr

    = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); if (networkInfo != null && networkInfo.isConnected()) { Log.d("TAG", "CONNECTED"); } else { Log.d("TAG", "DISCONNECTED"); } }
  206. HttpURLConnection: read private String downloadUrl(String myUrl) throws IOException { InputStream

    in = null; try { URL url = new URL(myUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); in = conn.getInputStream(); // Convert the InputStream into a string int myChar; String result = ""; while((myChar = in.read()) != -1) { result += (char) myChar; Log.d("r", "" + (char) myChar); } return result; } finally { if(in != null) { Log.d("tag", "closing"); in.close(); } } }
  207. JSON? • JavaScript Object Notation • Open standard format for

    transmitting attribute-value pairs • Replacing XML • Media-type: "application/json"
  208. JSON Example { "firstName": "John", "lastName": "Smith", "isAlive": true, "age":

    25, "address": { "streetAddress": "21 2nd Street", "city": "New York", "state": "NY", "postalCode": "10021-3100" }, "phoneNumbers": [ { "type": "home", "number": "212 555-1234" }, { "type": "office", "number": "646 555-4567" } ], "children": [], "spouse": null }
  209. JSON Parsing JSONObject jsonObject1 = new JSONObject("{key: 'value'}"); String value1

    = jsonObject1.getString("key"); JSONObject jsonObject2 = new JSONObject("{key: 2.3}"); double value2 = jsonObject2.getDouble("key"); JSONArray jsonArray3 = new JSONArray("[{key1: true}, {key2: 2}]"); boolean value3 = jsonArray3.getJSONObject(0).getBoolean("key1"); JSONObject jsonObject4 = new JSONObject("{key1: [1,2,3]}"); int value4 = jsonObject4.getJSONArray("key1").getInt(2);
  210. Android XML Parsing • To parse xml you have •

    1) org.xmlpull.v1.XmlPullParser • http://www.xmlpull.org/ • Pull • 2) javax.xml.parsers.SAXParser • http://sax.sourceforge.net/ • Pull • 3) org.w3c.dom • http://www.w3.org/DOM/ • Tree oriented • SAXParser can be found from other frameworks also. XmlPullParser is recommend for Android
  211. Example SAX SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp = spf.newSAXParser();

    XMLReader xr = sp.getXMLReader(); DataHandler dataHandler = new DataHandler(); xr.setContentHandler(dataHandler); InputSource inputSource = new InputSource( new StringReader( "<foo>Hello World!</foo>" ) ); xr.parse(inputSource);
  212. Example SAX public class DataHandler extends DefaultHandler { @Override public

    void startDocument() throws SAXException { } @Override public void endDocument() throws SAXException { } @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { } @Override public void endElement(String namespaceURI, String localName, String qName) throws SAXException { } @Override // Receive notification of character data inside an element. public void characters(char ch[], int start, int length) { System.out.println(new String(ch, start, length)); } }
  213. XmlPullParser Example XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser xpp = factory.newPullParser();

    xpp.setInput( new StringReader( "<foo>Hello World!</foo>" ) ); int eventType = xpp.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) { if(eventType == XmlPullParser.START_DOCUMENT) { System.out.println("Start document"); } else if(eventType == XmlPullParser.START_TAG) { System.out.println("Start tag "+xpp.getName()); } else if(eventType == XmlPullParser.END_TAG) { System.out.println("End tag "+xpp.getName()); } else if(eventType == XmlPullParser.TEXT) { System.out.println("Text "+xpp.getText()); } eventType = xpp.next(); } System.out.println("End document");
  214. Android Graphics • Custom 2D Graphics • android.graphics.drawable package •

    OpenGL ES 1.0 high performance 3D graphics • javax.microedition.khronos.opengles package • We will concentrate on the 2D graphics
  215. Drawables • A Drawable is a general abstraction for “something

    that can be drawn” • BitmapDrawable, ShapeDrawable, LayerDrawable … • How to define and instantiate Drawable? 1. Use image saved to project resources OR 2. XML file that defines drawable properties OR 3. In Java
  216. 1. Use image saved to project resources • Supported types:

    PNG (preferred), JPG (acceptable) and GIF (discoured) • Add the file to res/drawable • Refer using the R – class • Use it from Java or XML
  217. Screen Sizes • Android supports different screen sizes • Simplifying

    developer’s work: • 4 generalized sizes: small, normal, large, xlarge • 4 generalized densities: ldpi, mdpi, hdpi, xhdpi
  218. Screen sizes and Resolutions • xlarge screens are at least

    960dp x 720dp • large screens are at least 640dp x 480dp • normal screens are at least 470dp x 320dp • small screens are at least 426dp x 320dp
  219. Resources res/layout/my_layout.xml // layout for normal screen size res/layout-small/my_layout.xml //

    layout for small screen size res/layout-large/my_layout.xml // layout for large screen size res/layout-large-land/my_layout.xml // layout for large screen size in landscape mode res/layout-xlarge/my_layout.xml // layout for extra large screen size res/drawable-lhdpi/my_icon.png // image for low density res/drawable-mdpi/my_icon.png // image for medium density res/drawable-hdpi/my_icon.png // image for high density res/drawable-nodpi/composite.xml // density independent resource
  220. Displaying Image using Java public class MainActivity extends AppCompatActivity {

    @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.activity_main); ImageView imageview = new ImageView(this); imageview.setImageResource(R.mipmap.ic_launcher); setContentView(imageview); } } mip-map/ is reserved for launcher icons
  221. Or use it via the XML <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"

    android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="fi.tamk.drawing.MainActivity"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/ic_launcher" /> </LinearLayout>
  222. Drawing on a View • If no significant frame-rate speed

    needed, draw to custom View • Extend View and define onDraw – method • onDraw() is called automatically • Redraw: invalidate() • Inside onDraw(), Canvas is given
  223. Simple 2D Drawing: View public class CustomDrawableView extends View {

    public CustomDrawableView(Context context, AttributeSet attr) { super(context, attr); } protected void onDraw(Canvas canvas) { // Paint class holds style information Paint myPaint = new Paint(); myPaint.setStrokeWidth(3); myPaint.setColor(Color.BLACK); canvas.drawCircle(200, 200, 50, myPaint); } }
  224. ShapeDrawable • With ShapeDrawable, one can draw primitive 2D shapes

    • ArcShape, OvalShape, RoundRectShape, PathShape, RectShape • ShapeDrawable takes Shape object and manages it into screen • Shapes can be defined in XML
  225. Shape Drawable in Java public class CustomDrawableView extends View {

    private ShapeDrawable mDrawable; public CustomDrawableView(Context context, AttributeSet attr) { super(context, attr); int x = 10; int y = 10; int width = 300; int height = 300; mDrawable = new ShapeDrawable(new OvalShape()); mDrawable.getPaint().setColor(0xff74AC23); mDrawable.setBounds(x, y, x + width, y + height); } protected void onDraw(Canvas canvas) { mDrawable.draw(canvas); } }
  226. Shape Drawable in XML <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="fi.tamk.drawing.MainActivity"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/myshapes" /> </LinearLayout>
  227. About Animation • 1) View Animation • Any View object

    to perform tweened animation and frame by frame animation • Tween animation calculates animation given information: start, end, size, rotation and other • Frame by frame: series of drawables one after another • 2) Property Animation System (Android 3.x) • “Animate almost anything” • Define animation to change any object property over time, whether in screen or not
  228. Differences • View + Less time to setup + Less

    code to write - Only View objects - Only certain aspects to animate (scaling, rotating..) - View itself is not modified when animating • Property animation system + Animating also non View objects + Animating any property of any object - More work
  229. About View Animation • View animation can be 1) tween

    or 2) frame by frame animation • Tween animation • Can perform series of simple transformations (position, size, rotation, transparency) on View object • In XML or in code • Frame animation • Sequence of different images • In XML or in code
  230. 1) Tween animation • Preferred way: Define in XML •

    Animation xml is stored in res/anim directory • Root element can be: alpha, scale, translate, rotate or set that holds groups of these elements
  231. Tween Animation: XML <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@[package:]anim/interpolator_resource" android:shareInterpolator=["true"

    | "false"] > <alpha android:fromAlpha="float" android:toAlpha="float" /> <scale android:fromXScale="float" android:toXScale="float" android:fromYScale="float" android:toYScale="float" android:pivotX="float" android:pivotY="float" /> <translate android:fromXDelta="float" android:toXDelta="float" android:fromYDelta="float" android:toYDelta="float" /> <rotate android:fromDegrees="float" android:toDegrees="float" android:pivotX="float" android:pivotY="float" /> <set> ... </set> </set>
  232. Tween Animation: Java public class MainActivity extends AppCompatActivity { @Override

    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ImageView v = (ImageView) findViewById(R.id.imageView); Animation myAnimation = AnimationUtils.loadAnimation(this, R.anim.myanimation); v.startAnimation(myAnimation); } }
  233. Basic Definitions • <alpha> • fade-in or fade-out animations. •

    <scale> • Resizing animation. • <translate> • Vertical and or horizontal movement. • <rotate> • A rotation of an animation
  234. Example of Translate <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromXDelta="0"

    android:fromYDelta="0" android:toXDelta="0" android:toYDelta="100%p" android:duration="700" android:repeatCount="1" android:repeatMode="reverse" /> </set> Start from 0,0 End to 0, 100% from parent Duration is 700 Repeat in reverse one time
  235. Alpha <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <alpha android:fromAlpha = "1"

    android:toAlpha = "0" android:duration = "1000" android:repeatMode = "reverse" android:repeatCount= "1" /> </set>
  236. <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <alpha android:fromAlpha = "1" android:toAlpha

    = "0" android:duration = "1000" android:repeatMode = "reverse" android:repeatCount= "1" /> <rotate android:fromDegrees = "0" android:toDegrees = "360" android:pivotX = "50%" android:pivotY = "50%" android:duration = "1000" android:repeatMode = "reverse" android:repeatCount = "1" /> <scale android:fromXScale = "1" android:fromYScale = "1" android:toXScale = "6" android:toYScale = "6" android:pivotX = "50%" android:pivotY = "50%" android:duration = "1000" android:repeatMode = "reverse" android:repeatCount = "1" /> </set>
  237. Interpolation • Interpolation is an animation modifier defined in xml

    • Rate of change in animation • Accelerate, bounce…
  238. Example of Interpolation <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/bounce_interpolator"> <translate

    android:fromXDelta="0" android:fromYDelta="0" android:toXDelta="0" android:toYDelta="30%p" android:duration="700" android:repeatMode="reverse" android:repeatCount="1"/> </set>
  239. Different Interpolations Interpolator class Resource ID AccelerateDecelerateInterpolator @android:anim/accelerate_decelerate_i nterpolator AccelerateInterpolator

    @android:anim/accelerate_interpolator AnticipateInterpolator @android:anim/anticipate_interpolator AnticipateOvershootInterpolator @android:anim/anticipate_overshoot_in terpolator BounceInterpolator @android:anim/bounce_interpolator CycleInterpolator @android:anim/cycle_interpolator DecelerateInterpolator @android:anim/decelerate_interpolator LinearInterpolator @android:anim/linear_interpolator OvershootInterpolator @android:anim/overshoot_interpolator
  240. 2) Frame Animation • Create XML file that consists of

    sequence of different images • Root-element: <animation-list> and series of child elements <item>
  241. Example <?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@drawable/a1" android:duration="200"

    /> <item android:drawable="@drawable/a2" android:duration="200" /> <item android:drawable="@drawable/a3" android:duration="200" /> <item android:drawable="@drawable/a4" android:duration="200" /> <item android:drawable="@drawable/a5" android:duration="200" /> <item android:drawable="@drawable/a6" android:duration="200" /> <item android:drawable="@drawable/a7" android:duration="200" /> <item android:drawable="@drawable/a8" android:duration="200" /> </animation-list>
  242. Property Animation • Extend animation beyond Views! • Also limited

    scope: move, rotate, scale, alpha. That’s it. • With Property Animation, you can animate almost anything • Changes the object itself • Animating values over time
  243. ValueAnimator • To animate values 1.0 – 0.0 • ValueAnimator

    anim = ValueAnimator.ofFloat(1, 0); anim.setDuration(5000); anim.start(); • It animates, but nothing can be seen. Add listener! • anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator animation) { float value = (float) animation.getAnimatedValue(); button.setAlpha(value); } });
  244. ObjectAnimator: animate objects! MyPoint myobject = new MyPoint(0,0); // Animate

    myobject’s x-attribute from default value // to 20! ObjectAnimator anim2 = ObjectAnimator.ofFloat(myobject, "x", 20); anim2.setDuration(2500); anim2.start(); Assumes that myobject has getX() and setX(int x) methods1
  245. View class in Honeycomb • In Honeycomb, View class has

    several set/get methods.. For example • setAlpha (float alpha) • float getAlpha () • So by using Object Animator, you can animate the alpha (transparency) for every view!
  246. AnimatorSet • Choreograph multiple animations • Play several animations together

    • playTogether(Animator…) • Play animations one after another • playSequentially(Animator…) • Or combination of above • with(), before(), after() methods
  247. ObjectAnimator alpha = ObjectAnimator.ofFloat(v, "alpha", 0.0f); alpha.setRepeatCount(ObjectAnimator.INFINITE); alpha.setRepeatMode(ObjectAnimator.REVERSE); alpha.setDuration(1000); ObjectAnimator

    mover = ObjectAnimator.ofFloat(v, "x", 0, 500f); mover.setRepeatCount(ObjectAnimator.INFINITE); mover.setDuration(5000); mover.setRepeatMode(ObjectAnimator.REVERSE); AnimatorSet set = new AnimatorSet(); set.playTogether(alpha); set.playTogether(mover); set.start();
  248. Android N for Developers • Multi-window support • Java 8

    features • Data Saver • Vulkan API • Quick Settings Tile API
  249. Multi-window • Handheld: two apps can run side by side

    • Does not change activity life-cycle • The activity user uses is topmost. All other activities are on paused state • Recommendation, video apps should still continue even in pause • Can be split-screen or freeform. • Manufacturers of larger devices can enable freeform in addtion to split-screen • Can open activities next to each other • Drag & Drop support available
  250. Configuration • If target is Android N, you can set

    to Activity's manifest • android:resizeableActivity=true • Example layout • <activity android:name=".MyActivity"> <layout android:defaultHeight="500dp" android:defaultWidth="600dp" android:gravity="top|end" android:minimalHeight="450dp" android:minimalWidth="300dp" /> </activity>
  251. Helper methods in Activity • isInMultiWindowMode() • If in multi-window

    or not • onMultiWindowChanged() • entering or leaving multi-window mode
  252. Launching Activities • It's possible to launch a new activity

    to the second window • Use flag • Intent.FLAG_ACTIVITY_LAUNCH_TO_ADJACENT
  253. Java 8 and Android N • Lambda Expressions • Default

    and Static methods • Method references • ... 333