6. Course and Schedule
Day 1
● Fragment
● Libraries
Day 2
● Firebase Cloud Messaging
● Places
Day 3
● Media Playback
● Widget
Day 4
● Espresso
● Publishing Your
App
9. Final Project
● Original work
● Past project is fine
● Sky's the limit
● Containing 2 or more course material
● APK and Documentation / Source code
● Sent to rwpramono@gmail.com
● Due Date is 2 week after last meeting
12. Memory Leak
● Every app needs memory as a resource to do its work
● Android runtime triggers Garbage Collection (GC) when memory runs
short to reclaim memory by cleaning up objects that are no longer
useful
● What if the object is not used anymore in the program but its memory
cannot be released by the Garbage Collector ?
13. Memory Leak
● Memory leak causing more frequent GC events
● GC events makes rendering of UI and processing of events will stop
● Potentially more than 16ms drawing window
14. Memory Leak Effects
● No response to an input event (such as key press or screen touch
events) within 5 seconds
● A BroadcastReceiver hasn't finished executing within 10 seconds
● The system will eventually refuse to allocate more memory for your
app
21. Anonymous classes
● Use static Handler class
@Override
protected void onDestroy() {
mLeakyHandler.removeMessages(MESSAGE_ID);
super.onDestroy();
}
22. Static Context and View object
public class MyActivity extends AppCompatActivity {
private static Context sContext;
. . . . .
}
23. Static Context and View object
● Avoid static to Android components like context, activities,
services and views
● Use WeakReference if needed
● Use Application context instead of the Activity context
● Set null in onDestroy() callback
24. Leak Canary
● Created by Pierre-Yves Ricau (Square Inc)
● Very easy to use
● Tracks objects for memory leaks
27. Job Scheduling
● Running some background tasks outside the scope of an application’s
life-cycle become mainstream
● But they’re expensive
● Scheduling this work intelligently can improve your app’s performance,
along with aspects of system health such as battery life
28. Job Scheduling
● AlarmManager (Time specific)
● Firebase JobDispatcher (API level >=9 + Google Play Service)
● JobScheduler (API Level >=21)
● 3rd party Evernote Android-Job (API Level >=14)
29. AlarmManager
● AlarmManager provides access to system-level alarm services
● Registered alarms are retained while the device is asleep but will be cleared if
it is power off and rebooted
● Does not provide more robust execution conditions like device is idle, network
is available or charging detect
31. Firebase JobDispatcher
● This library will also works when running (using AlarmManager) device do not
have Google play services installed and wants to schedule a job in the
application
● Network State
○ NETWORK_TYPE_NONE
○ NETWORK_TYPE_ANY
○ NETWORK_TYPE_UNMETERED,
○ NETWORK_TYPE_NOT_ROAMING
○ NETWORK_TYPE_METERED
● Charging State
● Idle State
33. JobScheduller
The job implementation consists of the following three steps:
● JobInfo: Sets the conditions under which the job will run
● JobService: implements the necessary action when the job is
executed
● Grants permission of your sub-class of JobService for job execution
android.permission.BIND_JOB_SERVICE
34. JobScheduller - JobInfo
● Connected network type
● Charging status
● Device idle state
● Updating the content provider
● Clip data
● Execution cycle
● Minimum latency
● Deadline setting
● Retry Policy
● Whether the current condition is maintained when rebooting
35. JobScheduller - JobInfo
class JobSchedulerSample {
private static final int JOB_ID_UPDATE = 0x1000;
static void setUpdateJob(Context context) {
JobInfo job = new JobInfo.Builder(JOB_ID_UPDATE,
new ComponentName(this, SyncJobService.class)
)
.setRequiresStorageNotLow(true)
.setRequiredNetworksCapabilities(JobInfo.NETWORK_TYPE_UNMETERED)
.setRequiresCharging(true)
.build();
JobService mJobService = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
mJobService.scheduleJob(job);
}
}
36. JobScheduller - JobService
● JobService has an easy structure that can handle the operation start,
finish and notifying the end of the job by calling at any time if
necessary
● onStartJob()
onStartJob()Return true if it need more time to finish your work such
as AsyncTask or Thread thing, and false if the action is finished at this
method
● onStopJob()
Returning true re-schedule the job that are currently running. False to
prevent this job from being scheduled again
37. JobScheduller - JobService
public class SyncJobService extends JobService {
@Override
public void onCreate() {
. . . . .
}
@Override
public boolean onStartJob(final JobParameters params) {
return mDownloader.hasPendingArtworkDownload();
}
@Override
public boolean onStopJob(JobParameters params) {
return !mDownloader.isFinished();
}
}
44. Old days
● Lots boilerplate code
● No direct object mapping
● Difficult to implement database migration
● Difficult to test
● Possible long main thread database operation
46. Room
Room implementation consists of the following steps:
● Update the gradle dependencies
● Update model classes to entities
● Create Data Access Objects (DAOs)
● Create the database
48. Create an Entity
@Entity
public class Product {
@PrimaryKey(autoGenerate = true)
private int uid;
@ColumnInfo(name = "name")
private String name;
@ColumnInfo(name = "image_url")
private String imageUrl;
// getters and setters
}
public class Warehouse {
String name;
@Embedded
Product product;
}
@Entity
Defines the table name of the database (case-insensitive)
@PrimaryKey
autoGenerate = true / false
@ColumnInfo
Defines the column name of the current table
@Ignore
Ignores the marked element from Room's processing logic
@Embeded
Works like weak entity
@ForeignKey
Relation with another entity
https://developer.android.com/reference/android/arch/persis
tence/room/package-summary.html
49. Create a Data Access Object
@Dao
public interface CountryDao {
@Query("SELECT * FROM Country")
LiveData<List<Country>> getAll();
@Query("SELECT * FROM Country where name LIKE :name")
Country findByName(String name);
@Query("SELECT COUNT(*) from Country")
int countCountries();
@Insert
void insertAll(Country... countries);
@Delete
void delete(Country country);
}
● Room allows that by providing observable queries
which will notify when the data in the database is
changed/updated.
● The SQL query is checked at the compile time itself
● Support multiple tables
50. Create a Database
@Database(entities = {Country.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
private static AppDatabase INSTANCE;
public abstract CountryDao countryDao();
public static AppDatabase getAppDatabase(Context
context) {
if (INSTANCE == null) {
INSTANCE =
Room.databaseBuilder(context.getApplicationContext(),
AppDatabase.class, "country-database").build();
}
return INSTANCE;
}
public static void destroyInstance() {
INSTANCE = null;
}
}
● The database instance is expensive.
● It is recommended to keep it in a singleton or
dependency injector
● entities: defines the related entities of the current
database. If you have more than one, you can
separate by comma.
● version: defines the database version
52. ViewModel
Designed to store the UI related
data and this component is lifecycle
aware which allows it to survive the
configuration change automaticallyArchitecture Components
53. ViewModel
● Manage the data for the UI
● Communication between Activity / Fragment
● Retains the data during the configuration change
● Never ever access your view hierarchy or hold a reference back to the
Activity or the Fragment
59. Create ViewModel Class
public class CouponViewModel extends ViewModel{
private Coupon coupon;
private CouponRepository couponRepository = new
CouponRepository();
public Coupon getCoupon() {
if(coupon == null){
coupon = couponRepository.getTopCoupon();
}
return coupon;
}
}
This class holds the model object defined in Room / Model
Class and it contains methods to handle UI events which
apply business logic and fetch data and finally set model
63. LiveData
● Ensures your UI matches your data state & Up to date
● No memory leaks
● No crashes due to stopped activities
● No more manual lifecycle handling
65. ViewModel
● If the Lifecycle is destroyed, the observer is
removed automatically
● If the Lifecycle is not in an active state
(STARTED or RESUMED), the observer isn't
called even if the value changes.
67. Create LiveData Class
public class CouponViewModel extends ViewModel{
private Coupon coupon;
private CouponRepository couponRepository = new
CouponRepository();
public Coupon getCoupon() {
if(coupon == null){
coupon = couponRepository.getTopCoupon();
}
return coupon;
}
}
● Make sure to store LiveData objects that update the
UI in ViewModel objects
68. Observe LiveData objects
// Get the ViewModel.
mModel =
ViewModelProviders.of(this).get(NameViewModel.class);
// Create the observer which updates the UI.
final Observer<String> nameObserver = new
Observer<String>() {
@Override
public void onChanged(@Nullable final String
newName) {
// Update the UI, in this case, a TextView.
mNameTextView.setText(newName);
}
};
// Observe the LiveData, passing in this activity
as the LifecycleOwner and the observer.
mModel.getCurrentName().observe(this,
nameObserver);
● LiveData delivers updates only when data changes,
and only to active observers
● Only receives an update if the value has changed
since the last time it became active
69. Updating LiveData objects
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String anotherName = "John Doe";
mModel.getCurrentName().setValue(anotherName);
}
});
● setValue(T) method to update the LiveData object
from the main thread / UI thread
● postValue(T) method to update the LiveData object in
background thread