Documente Academic
Documente Profesional
Documente Cultură
Intermediate
Ahmad Arif Faizin
What will we learn?
- Building UI (Responsive Design)
- AsyncTask (JSON Parsing)
- RecyclerView
- Intent
- Lifecycle
- Preferences
- SQLite
- Content Provider
- Background Task (Notification & Sync)
“ The master has failed
more times than the
”
beginner has even tried.
Sunshine Project Exercise
Sunshine Project
https://github.com/udacity/ud851-Sunshine
Toys Project
https://github.com/udacity/ud851-Exercises
Flow
1. Impot.ExerciseProject();
2. Shift*2 (TODO);
3. for (i=0; i<TODO.size();i++){TODO.execute();}
4. while (!Succed){try();}
5. Import.NextExerciseProject
LESSON 1
Make Sunshine Project
Exercise 1 - Create Layout
Exercise 1.1 - Create Layout
Flow
Flow
Exercise 1.2 - DisplayToyList
Add an ID
teks.SetText(“Halo”); teks.append(“Halo”);
teks.SetText(“Akhirat”); teks.append(“Akhirat”);
Output : Output :
“Akhirat” “HaloAkhirat”
Exercise 1.3 - Add Scrolling View
NOW IS YOUR
TIME...
>>Create Layout Sunshine Project
S.01-01
S.01-02
S.01-03
LESSON 2
Connect to Internet
Logging
https://api.github.com/search/repositories?q=android
&sort=stars
Make URLHTTP Request
T02.04-Exercise-
ConnectingToTheInternet
Add Permission
<uses-permission android:name="android.permission.INTERNET"/>
JSON Object
{ "key" : value}
JSON Array
[value, value, value]
EXAMPLE OF JSON FORMAT
NOW IS YOUR
TIME...
>>Create Networking
Get API Key
Get Open Weather API Key
https://www.openweathermap.org/appid
Example Query:
http://api.openweathermap.org/data/2.5/forecast/daily?q=ambarawa&
mode=json&units=metric&cnt=7&APPID=93a3696714297ee5a9f6548
6aa8cb824
Source : http://stackoverflow.com/questions/16902716/comparison-of-android-
networking-libraries-okhttp-retrofit-and-volley
LESSON 3
RecyclerView
UI Evolution
UI Evolution
RecyclerView
Nice References ;
https://wirasetiawan29.wordpress.com/2016/03/04/viewholder-di-android/
https://medium.com/@ocittwo/recyclerview-dan-adapternya-ce6332a0833
RecyclerView vs ListView
+ ViewHolder Pattern
+ LayoutManager (Linear, Grid, Staggered)
+ Item animators and item decorators
+ More explicit click listeners
Quiz
Quiz Answer
RecyclerView
Source :
https://medium.com/@ocittwo/recyclerview-dan-adapternya-ce6332a0833
T03.01-
Exercise-RecyclerViewLayout
1. Add Dependency in build.gradle(Module:app) >sync now
compile 'com.android.support:recyclerview-v7:25.3.1'
2. Add RecyclerView in xml with ID
T03.02-
Exercise-ViewHolder
1. Add Dependency in build.gradle(Module:app) >sync now
compile 'com.android.support:recyclerview-v7:25.3.1'
2. Add RecyclerView in xml with ID
3. Add item_list.xml design
4. Add Adapter.java
Make ViewHolder Class extends RecyclerView.ViewHolder
RecyclerView
Source :
https://medium.com/@ocittwo/recyclerview-dan-adapternya-ce6332a0833
RecyclerView
Source :
https://medium.com/@ocittwo/recyclerview-dan-adapternya-ce6332a0833
T03.03-
Exercise-RecyclerViewAdapter
4. Add Adapter.java
- Make ViewHolder Class extends RecyclerView.ViewHolder
- Make Adapter Class Extends
RecylerView.Adapter<RecyclerView.ViewHolder>
- Implement method
- onCreateViewHolder > untuk inflate layout_item
- onBindViewHolder > untuk proses tiap-tiap komponen
- getItemCount > jumlah list data
T03.04-Exercise-
WiringUpRecyclerView
1. Add Dependency in build.gradle(Module:app) >sync now
compile 'com.android.support:recyclerview-v7:25.3.1'
2. Add RecyclerView in xml with ID
3. Add item_list.xml design
4. Add Adapter.java then setAdapter
5. Add LayoutManager then setLayoutManager
T03.07-Exercise-
RecyclerViewClickHandling
1. Make ListItemClickListener
2. Implement OnClickListener in ViewHolder
My Way
1. Tambahkan pada Constructor Adapter
(int[] data, Context context)
2. Sehingga saat manggil Adapter jadi Adapter(dataAngka,this);
3. holder.cardview.setOnClickLister
NOW IS YOUR
TIME...
>>Create RecyclerView
S03.01-Exercise-RecyclerView
S03.02-Exercise-ClickHandling
LESSON 4
Intent
New Activity
Create Activity
Klik kanan pada package > new > activity > blank activity > OK
Intent pindah =
new Intent (MainActivity.this, TujuanActivity.class);
context , class tujuan
startActivity(pindah);
PutExtra
Intent pindah =
new Intent (MainActivity.this, TujuanActivity.class)
pindah.putExtra(“key1”,”value1”);
pindah.putExtra(“key2”,2);
startActivity(pindah);
GetExtra
http://openweathermap.org/appid
Format
”Key”,”Value”
T06.01-SetupTheActivity
T06.02-PreferenceFragment
How to use
Method 1
public static final String PREFS_NAME = "AOP_PREFS";
SharedPreferences pref= getSharedPreferences(PREFS_NAME,
Context.MODE_PRIVATE);
Method 2
SharedPreferences pref=
PreferenceManager.getDefaultSharedPreferences(context)
How to Use
How to Use
How to Input
SharedPreferences pref =
getApplicationContext().getSharedPreferences("MyChar", 0);
Delete TABLE
DROP TABLE weather;
Basic Database
Basic Database
Insert row into TABLE
INSERT INTO weather VALUES(2,'20140626',17,21,0,1031);
INSERT INTO weather VALUES(3,'20140627',18,22,0,1055);
INSERT INTO weather VALUES(4,'20140628',18,21,10,1070);
Basic Database
Show Data from TABLE
SELECT * FROM weather;
SELECT * FROM weather WHERE date == 20140626;
SELECT _id,date,min,max FROM weather WHERE date >
20140625 AND date < 20140628;
SELECT * FROM weather WHERE min >= 18 ORDER BY max
ASC;
Basic Database
Update row in TABLE
UPDATE weather SET min = 0, max = 100 where date >=
20140626 AND date <= 20140627;
}
}
Basic Database
SQLiteDbHelper
MovieDbHelper dbHelper;
@Override
public boolean onCreate() {
Context context = getContext();
dbHelper = new MovieDbHelper(context);
return true;
}
.
.
.
.
Basic Database
Basic Database
2. Android Manifest
<application>
.
.
.
.
<provider
android:name=".data.MovieContentProvider"
android:authorities="id.co.imastudio.popmov"
android:exported="false" />
</application>
Basic Database
Basic Database
3. DefineURI
ALL FILM
content://id.co.imastudio.recyclerview/listfilm
FILM WITH ID
content://id.co.imastudio.recyclerview/listfilm/#
Basic Database
Basic Database
4. Create URI
public class MovieContract {
public static final String AUTHORITY = "id.co.imastudio.popmov";
public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + AUTHORITY);
public static final String PATH_TASKS = "listfilm";
return uriMatcher;
}
Basic Database
Basic Database
Basic Database
Basic Database
Basic Database
Basic Database
MovieContentProvider-Query
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[]
selectionArgs, @Nullable String sortOrder) {
final SQLiteDatabase db = dbHelper.getReadableDatabase();
int match = sUriMatcher.match(uri);
Cursor retCursor;
switch (match) {
case ALL_FILM:
retCursor = db.query(MovieContract.MovieEntry.TABLE_NAME,
projection, selection, selectionArgs, null, null, sortOrder);
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
retCursor.setNotificationUri(getContext().getContentResolver(), uri);
return retCursor;
}
MovieContentProvider-Insert
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
final SQLiteDatabase db = dbHelper.getWritableDatabase();
int match = sUriMatcher.match(uri);
Uri returnUri; // URI to be returned
switch (match) {
case ALL_FILM:
long id = db.insert(MovieContract.MovieEntry.TABLE_NAME, null, contentValues);
if ( id > 0 ) {
returnUri = ContentUris.withAppendedId(MovieContract.MovieEntry.CONTENT_URI, id);
} else {
throw new android.database.SQLException("Failed to insert row into " + uri);
}
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return returnUri;
MovieContentProvider-Delete
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
final SQLiteDatabase db = dbHelper.getWritableDatabase();
int numRowsDeleted;
if (null == selection) selection = "1";
switch (sUriMatcher.match(uri)) {
case ALL_FILM:
numRowsDeleted = dbHelper.getWritableDatabase().delete(
MovieContract.MovieEntry.TABLE_NAME,
selection,
selectionArgs);
db.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" + MovieContract.MovieEntry.TABLE_NAME + "'");
break;
case FILM_WITH_ID:
numRowsDeleted = db.delete(MovieContract.MovieEntry.TABLE_NAME, MovieContract.MovieEntry.COLUMN_ID + " = ?",
new String[]{String.valueOf(ContentUris.parseId(uri))});
db.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" + MovieContract.MovieEntry.TABLE_NAME + "'");
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
Insert Database
private void tambahkedatabase() {
ContentValues cv = new ContentValues();
cv.put(MovieContract.MovieEntry.COLUMN_ID, dataId);
cv.put(MovieContract.MovieEntry.COLUMN_JUDUL, dataJudul);
cv.put(MovieContract.MovieEntry.COLUMN_POSTER, dataPoster);
Log.d(TAG, "onResponse: "+ cv.get(MovieContract.MovieEntry.COLUMN_POSTER));
Uri uri = getContentResolver().insert(MovieContract.MovieEntry.CONTENT_URI, cv);
Toast.makeText(DetailActivity.this, "Uri :" + uri, Toast.LENGTH_SHORT).show();
}
Delete Database
private void hapusdaridatabase() {
getContentResolver().delete(MovieContract.MovieEntry.CONTENT_URI.buildUpon().appendPath(String.va
lueOf(dataId)).build(), null, null);
}
Basic Database
Basic Database
Basic Database
Basic Database
Using Loader to Load Data
getSupportLoaderManager().initLoader(ID_FILM_LOADER, null, this);
-----
@Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle bundle) {
switch (loaderId) {
case ID_FILM_LOADER:
Uri forecastQueryUri = FilmContract.FilmEntry.CONTENT_URI;
return new CursorLoader(this, forecastQueryUri, null, null, null, null);
default:
throw new RuntimeException("Loader Not Implemented: " + loaderId);
}
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
if(data.getCount()>0) {
initAdapter(getMoviesFromCursor(data));
} else {
Toast.makeText(getActivity(), "Tidak Ada Favorite", Toast.LENGTH_LONG).show();
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
}
getMoviesFromCursor
private ArrayList<MovieModel> getMoviesFromCursor(Cursor cursor) {
ArrayList<MovieModel> movies = new ArrayList<>();
if (cursor != null) {
/*Log.e("cursor length","->"+cursor.getCount());
Log.e("column length","->"+cursor.getColumnCount());*/
if (cursor.moveToFirst()){
do{
MovieModel movie = new MovieModel();
movie.setId(cursor.getInt(cursor.getColumnIndex(MovieContract.MovieEntry.COLUMN_ID)));
movie.setJudul(cursor.getString(cursor.getColumnIndex(MovieContract.MovieEntry.COLUMN_JUDUL)));
movie.setPoster(cursor.getString(cursor.getColumnIndex(MovieContract.MovieEntry.COLUMN_POSTER)));
movies.add(movie);
}while(cursor.moveToNext());
}
}
return movies;
}
LESSON 10
Background Task
Notification
private NotificationManager mNotifyManager;
private int NOTIFICATION_ID = 0;
----
//dalam onCreate
mNotifyManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
----
private void tampilinNotification() {
}
Notification + Intent Masuk App
private void tampilinNotification() {
//masuk aplikasi
Intent notificationIntent = new Intent(this, TabActivity.class);
PendingIntent notificationPendingIntent = PendingIntent.getActivity(this,
NOTIFICATION_ID, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
Notification + Action View Intent
private void tampilinNotification() {
//masuk web
Intent learnMoreIntent = new Intent(Intent.ACTION_VIEW, Uri
.parse("http://www.idn.id"));
PendingIntent learnMorePendingIntent = PendingIntent.getActivity
(this,NOTIFICATION_ID,learnMoreIntent,PendingIntent.FLAG_ONE_SHOT);
----
//If the Toggle is turned on, set the repeating alarm with a 15 minute interval
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
triggerTime, repeatInterval, notifyPendingIntent);
}
Alarm Manager Check
boolean alarmUp = (PendingIntent.getBroadcast(this, NOTIFICATION_ID, notificationIntent,
PendingIntent.FLAG_NO_CREATE) != null);
if (alarmUp){
Log.d(TAG, "setInexactRepeatingAlarm: Alarm tiap 30 detik nyala");
}
Make AlarmReceiver
1. Create New > Other > Receiver
<receiver
android:name=".MyAlarmReceiver"
android:enabled="true"
android:exported="false">
</receiver>
}
}
FilmIntentService
public class FilmIntentService extends IntentService {
public FilmIntentService() {
super("FilmIntentService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
FilmSyncTask.syncFilm(this);
}
}
---------- Manifest
<service
android:name=".sync.FilmIntentService"
android:exported="false" />
FilmSyncUtils
public class FilmSyncUtils {
----
FilmSyncUtils.startImmediateSync(this);
Basic Database
Basic Database
FilmFirebaseJobService
public class FilmFirebaseJobService extends JobService {
private AsyncTask<Void, Void, Void> mFetchWeatherTask;
@Override
public boolean onStartJob(final JobParameters jobParameters) {
mFetchWeatherTask = new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
Context context = getApplicationContext();
FilmSyncTask.syncFilm(context);
<service
return null;
android:name=".sync.FilmFirebaseJobService"
}
android:exported="false">
@Override
<intent-filter>
protected void onPostExecute(Void aVoid) {
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE"/>
jobFinished( jobParameters, false);
</intent-filter>
}
</service>
};
mFetchWeatherTask.execute();
return true;
}
@Override
public boolean onStopJob(JobParameters jobParameters) {
if (mFetchWeatherTask != null) {
mFetchWeatherTask.cancel(true);
}
return true;
}
}
FilmFirebaseJobService
static void scheduleFirebaseJobDispatcherSync(@NonNull final Context context) { private static final int SYNC_INTERVAL_HOURS = 3;
private static final int SYNC_INTERVAL_SECONDS = (int)
Driver driver = new GooglePlayDriver(context); TimeUnit.HOURS.toSeconds(SYNC_INTERVAL_HOURS);
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(driver); private static final int SYNC_FLEXTIME_SECONDS =
SYNC_INTERVAL_SECONDS / 3;
Job syncSunshineJob = dispatcher.newJobBuilder() private static boolean sInitialized;
.setService(FilmFirebaseJobService.class) private static final String SUNSHINE_SYNC_TAG =
.setTag(SUNSHINE_SYNC_TAG) "sunshine-sync";
.setConstraints(Constraint.ON_ANY_NETWORK)
.setLifetime(Lifetime.FOREVER)
.setRecurring(true)
.setTrigger(Trigger.executionWindow(
SYNC_INTERVAL_SECONDS,
SYNC_INTERVAL_SECONDS + SYNC_FLEXTIME_SECONDS))
.setReplaceCurrent(true)
.build();
dispatcher.schedule(syncSunshineJob);
}
Notification Manager
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context)
.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
.setSmallIcon(R.mipmap.ic_launcher_round)
.setContentTitle("Data Film Anyar")
.setContentText("didelok gan!")
.setAutoCancel(true);
notificationBuilder.setContentIntent(resultPendingIntent);
notificationManager.notify(12234, notificationBuilder.build());
Notification Manager
Notification Manager
Notification Manager
Notification Manager
Notification Manager
Notification Manager
Notification Manager
FINAL PROJECT
Let's do it!
Final Project
- Grid Layout
- Sort by Popular , Top Rated, and Favorit
- Detail Screen (title, release date, movie poster, vote average,
and plot synopsis, trailer, and review)
- Mark it as a Favorite.
- Networking in background thread
- Content provider to save Favorit offline
Final Project
save app state and restores it via
onSaveInstanceState/onRestoreInstanceState.
For example,
When a list item is selected, it remains selected on rotation.
When an activity is displayed, the same activity appears on
rotation.
User text input is preserved on rotation.
Maintains list items positions on device rotation.
Final Project
You must make sure your app does not crash when there is no
network connection! You can see this StackOverflow post on
how to do this. If your app crashes when there is no network
connection, you will not pass the project.
Final Project ++
++
+Extend the favorites ContentProvider to store the movie
poster, synopsis, user rating, and release date, and display them
even when offline.
+ Implement sharing functionality to allow the user to share the
first trailer’s YouTube URL from the movie details screen.
Final Project
https://docs.google.com/document/d/1ZlN1fUsCSKuInLECcJkslI
qvpKlP7jWL2TP9m6UiA6I/pub?embedded=true#h.7sxo8jefdfll
http://stackoverflow.com/questions/1560788/how-to-check-
internet-access-on-android-inetaddress-never-times-out
From : Ambarawa
Phone : 085740482440
About Me
FB : fb.me/faizinarif
Instagram : arif_faizin
Github : github.com/arifaizin
Education :
• SDN Kupang 01 Ambarawa
• SMPN 2 Paciran Lamongan / PPSD
• SMAN 1 Ambarawa Ahmad
• Universitas Diponegoro
• Pesantren Programmer ARIF
Now :
IMASTUDIO SEMARANG Faizin
IMAKIDZ