from newbie to

78
Wifi: campus-guest Password: payitforward Wifi? +

Upload: vitali-pekelis

Post on 12-Apr-2017

24 views

Category:

Software


0 download

TRANSCRIPT

Page 1: From newbie to

Wifi: campus-guestPassword: payitforward

Wifi?+

Page 2: From newbie to

Yonatan LevinGoogle Developer Expert

parahalllevin.yonatan

Page 3: From newbie to

>100 Cities > 30M usersRuby, Go, Python, Microservices

Ooooops...

Page 4: From newbie to

Making genetic tests accessible

Page 5: From newbie to

> 2000 members Largest Android Active Community

Page 6: From newbie to

Jonathan Yarkoni

Android Developer & Advocate Ironsource

Android Academy Staff

Yonatan Levin

Android Google Developer

Expert

Britt Barak

Android LeadFigure8

Yossi Segev

Android Developer

Colu

Shahar Avigezer

Android DeveloperHello Heart

Page 7: From newbie to

Community Mentors

Page 8: From newbie to

What Do We Do?

●Android Fundamentals - NOW

● Android UI / UX - 29/1 !

● Community Hackathon - 9/3 !!!

●Android Performance

●Mentors Program●Active community

Page 9: From newbie to

From Newbie to ...

Page 10: From newbie to
Page 11: From newbie to

Disclaimer: It’s my personal opinion

Page 12: From newbie to

It’s all about “from Junior to Senior”

Page 13: From newbie to

github.com/parahall/star_wars_movies

Page 14: From newbie to

<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:background="@android:color/background_dark" android:orientation="vertical" tools:context="com.academy.android.starwarsmovies.MainActivity" >

<ImageView android:layout_width="match_parent" android:layout_height="100dp" android:layout_gravity="center_horizontal" android:src="@drawable/logo" />

<ProgressBar android:id="@+id/pb_am_loading" android:layout_width="match_parent" android:layout_height="match_parent" />

<ListView android:id="@+id/lv_am_movie_list" android:layout_width="match_parent" android:layout_height="match_parent" />

</LinearLayout>

Page 15: From newbie to

<?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="wrap_content" android:background="@android:color/background_dark" android:orientation="horizontal" android:padding="16dp" >

<ImageView android:layout_marginTop="8dp" android:id="@+id/iv_im_movie_poster" android:layout_width="70dp" android:layout_height="98dp" android:scaleType="fitXY" />

<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="8dp" android:layout_marginStart="8dp" android:orientation="vertical" > <TextView android:id="@+id/tv_im_movie_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:textColor="@android:color/background_light" android:textSize="16sp" android:textStyle="bold" />

<TextView android:id="@+id/tv_im_movie_description" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:textColor="@android:color/background_light" android:textSize="12sp" />

<TextView android:id="@+id/tv_im_movie_date" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:textColor="@android:color/background_light" android:textStyle="italic" />

</LinearLayout>

</LinearLayout>

Page 16: From newbie to

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);

listView = (ListView) findViewById(R.id.lv_am_movie_list); listView.setVisibility(View.GONE); progressBar = (ProgressBar) findViewById(R.id.pb_am_loading); progressBar.setVisibility(View.VISIBLE); StarWarsAsyncTask asyncTask = new StarWarsAsyncTask(); asyncTask.execute();}

Page 17: From newbie to
Page 18: From newbie to

private class StarWarsAsyncTask extends AsyncTask<Void, Void, ArrayList<StarWarsMovie>> {

@Override protected ArrayList<StarWarsMovie> doInBackground(Void... params) { ... }

@Override protected void onPostExecute(ArrayList<StarWarsMovie> starWarsMovies) { … } }

Page 19: From newbie to

[

{

"name": "Star wars",

"description": "The Imperial Forces, under orders from cruel Darth Vader,

hold Princess Leia hostage in their efforts to...",

"imageUrl": "http://cdn.collider.com/wp-content/uploads/star-wars-movie-

poster.jpg",

"releaseDate": "May 25, 1977"

},

{

"name": "Empire Strikes Back",

"description": "Luke Skywalker, Han Solo, ….",

"imageUrl" :

"https://cdn-images-1.medium.com/max/800/1*q6sBOxkTz7RXOimTLnGrjg.jpeg",

"releaseDate": "May 17, 1980"

},

{ ...

Page 20: From newbie to

@Override protected ArrayList<StarWarsMovie> doInBackground(Void... params) { String json = ResourcesUtil.loadJson(MainActivity.this); ArrayList<StarWarsMovie> moviesList = null; JSONArray array = new JSONArray(json); moviesList = new ArrayList<>(array.length()); for (int i = 0; i < array.length(); i++) { JSONObject jsonObject = array.getJSONObject(i); String name = jsonObject.getString("name"); String description = jsonObject.getString("description"); String imageUrl = jsonObject.getString("imageUrl"); String releaseDate = jsonObject.getString("releaseDate");

SimpleDateFormat format = new SimpleDateFormat("MMM d, yyyy"); Date date = format.parse(releaseDate); ImageLoader imgLoader = new ImageLoader(getApplicationContext()); Bitmap bitmap = imgLoader.displayImage(imageUrl);

moviesList.add(new StarWarsMovie(name, description, bitmap, date)); } return moviesList; }

Page 21: From newbie to

public static String loadJson(Context context) { StringBuilder jsonString = new StringBuilder(); URL url = new URL("https://api.starwars.com/movies"); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); InputStream in = new BufferedInputStream(urlConnection.getInputStream());

BufferedReader reader = new BufferedReader(new InputStreamReader(in));

String line; while ((line = reader.readLine()) != null) { jsonString.append(line); } return jsonString.toString();}

Page 22: From newbie to

@Override protected void onPostExecute(ArrayList<StarWarsMovie> starWarsMovies) { progressBar.setVisibility(View.GONE); listView.setVisibility(View.VISIBLE); MovieAdapter movieAdapter = new MovieAdapter(MainActivity.this, starWarsMovies); listView.setAdapter(movieAdapter); } }

Page 23: From newbie to

private class MovieAdapter extends ArrayAdapter<StarWarsMovie> { public MovieAdapter(Context context, ArrayList<StarWarsMovie> users) { super(context, 0, users); }

@Override public View getView(int position, View convertView, ViewGroup parent) { StarWarsMovie starWarsMovie = getItem(position); if (convertView == null) { convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_movie, parent, false); } TextView tvName = (TextView) convertView.findViewById(R.id.tv_im_movie_name); TextView tvDescription = (TextView) convertView.findViewById(R.id.tv_im_movie_description); TextView tvDate = (TextView) convertView.findViewById(R.id.tv_im_movie_date); ImageView ivPoster = (ImageView) convertView.findViewById(R.id.iv_im_movie_poster);

tvName.setText(starWarsMovie.getName()); tvDescription.setText(starWarsMovie.getDescription());

SimpleDateFormat format = new SimpleDateFormat("MMM d, yyyy"); tvDate.setText(format.format(starWarsMovie.getReleaseDate())); ivPoster.setImageBitmap(starWarsMovie.getImageBitmap());

return convertView; } }

Page 24: From newbie to

Wake Up!VIEWHOLDER!!!!!

Page 25: From newbie to

Is it only the problem here?

Page 26: From newbie to

@Override protected ArrayList<StarWarsMovie> doInBackground(Void... params) { String json = ResourcesUtil.loadJson(MainActivity.this); ArrayList<StarWarsMovie> moviesList = null; JSONArray array = new JSONArray(json); moviesList = new ArrayList<>(array.length()); for (int i = 0; i < array.length(); i++) { JSONObject jsonObject = array.getJSONObject(i); String name = jsonObject.getString("name"); String description = jsonObject.getString("description"); String imageUrl = jsonObject.getString("imageUrl"); String releaseDate = jsonObject.getString("releaseDate");

SimpleDateFormat format = new SimpleDateFormat("MMM d, yyyy"); Date date = format.parse(releaseDate); ImageLoader imgLoader = new ImageLoader(getApplicationContext()); Bitmap bitmap = imgLoader.displayImage(imageUrl);

moviesList.add(new StarWarsMovie(name, description, bitmap, date)); } return moviesList; }

Page 27: From newbie to

Memory Cache File Cache Load from the internet

Page 28: From newbie to

public class ImageLoader {

MemoryCache memoryCache = new MemoryCache();

FileCache fileCache;

ExecutorService executorService;

public ImageLoader(Context context) {

fileCache = new FileCache(context);

executorService = Executors.newFixedThreadPool(5);

}

Page 29: From newbie to

public class ImageLoader {

public Bitmap displayImage(String url) {

Bitmap bitmap = memoryCache.get(url);

if (bitmap == null) {

bitmap = getBitmap(url);

memoryCache.put(url, bitmap);

}

return bitmap;

}

Page 30: From newbie to

private Bitmap getBitmap(String url) { File f = fileCache.getFile(url);

//from SD cache Bitmap b = decodeFile(f); if (b != null) return b;

//from web Bitmap bitmap = null; URL imageUrl = new URL(url); HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection(); conn.setConnectTimeout(30000); conn.setReadTimeout(30000); conn.setInstanceFollowRedirects(true); InputStream is = conn.getInputStream(); OutputStream os = new FileOutputStream(f); Utils.CopyStream(is, os); os.close(); bitmap = decodeFile(f); return bitmap; }

Page 31: From newbie to

What if image too large?

Page 32: From newbie to

//decodes image and scales it to reduce memory consumption

private Bitmap decodeFile(File f) {

try {

//decode image size

BitmapFactory.Options o = new BitmapFactory.Options();

o.inJustDecodeBounds = true;

BitmapFactory.decodeStream(new FileInputStream(f), null, o);

//Find the correct scale value. It should be the power of 2.

final int REQUIRED_SIZE = 70;

int width_tmp = o.outWidth, height_tmp = o.outHeight;

int scale = 1;

while (true) {

if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE) break;

width_tmp /= 2;

height_tmp /= 2;

scale *= 2;

}

//decode with inSampleSize

BitmapFactory.Options o2 = new BitmapFactory.Options();

o2.inSampleSize = scale;

return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);

} catch (FileNotFoundException e) {

}

return null;

}

Page 33: From newbie to

And it’s just a beginning…

Page 34: From newbie to
Page 35: From newbie to

Source: http://konmik.com/post/introduction_to_model_view_presenter_on_android/

Page 36: From newbie to

Source: http://konmik.com/post/introduction_to_model_view_presenter_on_android/

Complex tasks are split into simpler tasks and are easier to solve.

Smaller objects, less bugs, easier to debug.Testable.

Page 37: From newbie to

MvpView

MainActivityView

Implements

BasePresenter<T extends MvpView>

Extends

interface abstract

Generic of type

Of Type

Activity

Implements Uses

Creates

ServiceMainPresenter

Page 38: From newbie to

This was changed

Page 39: From newbie to

public class StarWarsService extends IntentService {

@Override protected void onHandleIntent(Intent intent) { if (intent != null) { String json = ResourcesUtil.loadJson(this); ArrayList<StarWarsMovie> moviesList = null; JSONArray array = new JSONArray(json); moviesList = new ArrayList<>(array.length()); for (int i = 0; i < array.length(); i++) { JSONObject jsonObject = array.getJSONObject(i); String name = jsonObject.getString("name"); String description = jsonObject.getString("description"); String imageUrl = jsonObject.getString("imageUrl"); String releaseDate = jsonObject.getString("releaseDate"); SimpleDateFormat format = new SimpleDateFormat("MMM d, yyyy"); Date date = format.parse(releaseDate); ImageLoader imgLoader = new ImageLoader(getApplicationContext()); Bitmap bitmap = imgLoader.displayImage(imageUrl); moviesList.add(new StarWarsMovie(name, description, bitmap, date)); }...

Page 40: From newbie to

public class StarWarsService extends IntentService {

@Override protected void onHandleIntent(Intent intent) { ... Intent response = new Intent(); response.setAction(MainPresenter.LOAD_COMPLETE_ACTION); response.putExtra(MainPresenter.DATA_KEY, moviesList); LocalBroadcastManager.getInstance(this).sendBroadcast(response); } }}

Page 41: From newbie to

public interface MvpView {

public Context getAppContext();

public Context getActivityContext();

}

public interface MainActivityView extends MvpView {

ListView getListView();

ProgressBar getProgressBar();

}

Page 42: From newbie to

public abstract class BasePresenter<T extends MvpView> { HandlerThread thread; Looper looper; Handler handler; private T mView;

public void attachView(T t) { thread = new HandlerThread(getClass().getName(),

android.os.Process.THREAD_PRIORITY_BACKGROUND); thread.start(); looper = thread.getLooper(); mView = t; }

public void detachView() { mView = null; if (handler != null) { handler.removeCallbacksAndMessages(null); handler = null; } if (thread != null) thread.quit(); }

}

Page 43: From newbie to

public abstract class BasePresenter<T extends MvpView> {

public T getView() { return mView; }

public boolean isViewAttached() { return mView != null; }

}

Page 44: From newbie to

Show me THE PRESENTER!

Page 45: From newbie to

public class MainPresenter extends BasePresenter<MainActivityView> {

@Override public void attachView(MainActivityView mainActivityView) { super.attachView(mainActivityView); registerLoadDataReceiver();

if (isCacheAvailable()) { updateView(getView().getAppContext(), getView(), movieList); } else { Intent serviceIntent = new Intent(getView().getAppContext(), StarWarsService.class); getView().getAppContext().startService(serviceIntent); } }

Page 46: From newbie to

public class MainPresenter extends BasePresenter<MainActivityView> {

@Override public void detachView() { unRegisterLoadDataReceiver(); Intent serviceIntent = new Intent(getView().getAppContext(), StarWarsService.class); getView().getAppContext().stopService(serviceIntent); super.detachView(); }

Page 47: From newbie to

private void updateView(Context context, MainActivityView activityView, ArrayList<StarWarsMovie> list) {

MovieAdapter movieAdapter = new MovieAdapter(context, list); activityView.getListView().setAdapter(movieAdapter);

activityView.getProgressBar().setVisibility(View.GONE); activityView.getListView().setVisibility(View.VISIBLE);}

Page 48: From newbie to

public class MainPresenter extends BasePresenter<MainActivityView> {

private void registerLoadDataReceiver() { movieDataReceiver = new StarWarsMovieDataReceiver(); LocalBroadcastManager.getInstance(getView().getAppContext()) .registerReceiver(movieDataReceiver, new IntentFilter(LOAD_COMPLETE_ACTION)); }

private void unRegisterLoadDataReceiver() { if (movieDataReceiver != null) { LocalBroadcastManager.getInstance(getView().getAppContext()) .unregisterReceiver(movieDataReceiver); }}

Page 49: From newbie to

private class StarWarsMovieDataReceiver extends BroadcastReceiver {

@Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(LOAD_COMPLETE_ACTION)) {

if (isViewAttached()) { MainActivityView activityView = getView(); movieList = (ArrayList<StarWarsMovie>) intent.getSerializableExtra(DATA_KEY); updateView(context, activityView, movieList); } } }}

Page 50: From newbie to

Activity?

Page 51: From newbie to

public class MainActivity extends AppCompatActivity implements MainActivityView {

... public static MainPresenter mainPresenter;

@Override protected void onCreate(Bundle savedInstanceState) { ... ... if (mainPresenter == null) { mainPresenter = new MainPresenter(); } mainPresenter.attachView(this); }

@Override protected void onDestroy() { super.onDestroy(); mainPresenter.detachView(); if (isFinishing()) mainPresenter = null; }

@Override public Context getAppContext() { return getApplicationContext(); }

@Override public Context getActivityContext() { return this; }

@Override public ListView getListView() { return listView; }

@Override public ProgressBar getProgressBar() { return progressBar; }}

ATTENTION!

Page 52: From newbie to

public class MainActivity extends AppCompatActivity implements MainActivityView {

@Override public Context getAppContext() { return getApplicationContext(); }

@Override public Context getActivityContext() { return this; }

@Override public ListView getListView() { return listView; }

@Override public ProgressBar getProgressBar() { return progressBar; }}

Page 53: From newbie to

Questions ?

Page 54: From newbie to

There are other ways to retain presenter

Page 55: From newbie to

- Let him go (Not so user friendly)

- Static (Could be issue with multiple

instance)

- Fragments - setRetainInstance(true) (what

about nested fragments)?

- Loaders (Tricky when onLoaderFinished()

called within lifecycle)

- Static map. Nucleus.

Page 56: From newbie to

Questions ?

Page 57: From newbie to

We can do more. It’s just a beginning

Page 58: From newbie to
Page 59: From newbie to

compile 'com.squareup.retrofit2:retrofit:2.1.0'

compile 'com.squareup.retrofit2:converter-gson:2.1.0'

Page 60: From newbie to

public interface StarwarsApi {

@GET("/movies/{movie_id}")

Call<StarWarsMovie> getMovie(@Path("movie_id") int id);

@GET("/movies")

Call<ArrayList<StarWarsMovie>> listMovies();

}

Page 61: From newbie to

public static ArrayList<StarWarsMovie> getStarWarsMovies() {

ArrayList<StarWarsMovie> moviesList = null; Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.starwars.com/") .addConverterFactory( GsonConverterFactory.create(new GsonBuilder().setDateFormat("MMM d, yyyy").create())) .build();

StarwarsApi starwarsApi = retrofit.create(StarwarsApi.class);

Call<ArrayList<StarWarsMovie>> arrayListCall = starwarsApi.listMovies(); Response<ArrayList<StarWarsMovie>> listResponse = arrayListCall.execute(); moviesList = listResponse.body(); return moviesList;}

Page 62: From newbie to

Memory Cache File Cache Load from the internet

Page 63: From newbie to
Page 64: From newbie to

ImageLoader imgLoader = new ImageLoader(getApplicationContext());

Bitmap bitmap = imgLoader.displayImage(imageUrl);

compile 'com.github.bumptech.glide:glide:3.7.0'

bitmap =

Glide.with(getApplicationContext()).load(imageUrl).asBitmap().into(100,

100).get();

Page 65: From newbie to

More read

https://futurestud.io/tutorials/glide-getting-started

https://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en

Page 66: From newbie to

findViewById no more

Page 67: From newbie to

compile 'com.jakewharton:butterknife:8.4.0'

annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'

Page 68: From newbie to

public class MainActivity extends AppCompatActivity implements MainActivityView {

private @BindView(R.id.lv_am_movie_list) ListView listView; private @BindView(R.id.pb_am_loading) ProgressBar progressBar;

@Override protected void onCreate(Bundle savedInstanceState) { …

listView = (ListView) findViewById(R.id.lv_am_movie_list);

progressBar = (ProgressBar) findViewById(R.id.pb_am_loading);

ButterKnife.bind(this); listView.setVisibility(View.GONE); progressBar.setVisibility(View.VISIBLE);

}

Page 69: From newbie to

static class ViewHolder {

@BindView(R.id.tv_im_movie_name) TextView tvName;

@BindView(R.id.tv_im_movie_description) TextView tvDescription;

@BindView(R.id.tv_im_movie_date) TextView tvDate;

@BindView(R.id.iv_im_movie_poster) ImageView ivPoster;

public ViewHolder(View view) {

ButterKnife.bind(this, view);

}

}

Page 70: From newbie to

private class MovieAdapter extends ArrayAdapter<StarWarsMovie> {

public View getView(int position, View convertView, ViewGroup parent)

{

if (convertView == null) {

convertView =

LayoutInflater.from(getContext()).inflate(R.layout.item_movie, parent,

false);

holder = new ViewHolder();

holder.tvName = (TextView)

convertView.findViewById(R.id.tv_im_movie_name);

holder.tvDescription = (TextView)

convertView.findViewById(R.id.tv_im_movie_description);

holder.tvDate = (TextView)

convertView.findViewById(R.id.tv_im_movie_date);

holder.ivPoster = (ImageView)

convertView.findViewById(R.id.iv_im_movie_poster);

convertView.setTag(holder);

...

Page 71: From newbie to

Can we do better?

Page 72: From newbie to

Json Parsing

Page 73: From newbie to

public class StarWarsMovie {

private String name;

private String description;

private BitmapString imageBitmapUrl;

private Date releaseDate;

}

compile 'com.google.code.gson:gson:2.8.0'

Page 74: From newbie to

@Override protected void onHandleIntent(Intent intent) {

if (intent != null) {

...

Gson gson = new GsonBuilder().setDateFormat("MMM d,

yyyy").create();

ArrayList<StarWarsMovie> moviesList =

gson.fromJson(json, new TypeToken<ArrayList<StarWarsMovie>>() {

}.getType());

}

}

Page 75: From newbie to

private class MovieAdapter extends ArrayAdapter<StarWarsMovie> {

@NonNull @Override public View getView(int position, View

convertView, ViewGroup parent) {

...

Glide.with(getContext())

.load(starWarsMovie.getImageUrl())

.placeholder(R.drawable.placeholder)

.into(holder.ivPoster);

return convertView;

}

Page 76: From newbie to
Page 77: From newbie to

Our performance course- LeakCanary- Retrofit- Dagger- Parceler- EventBus- RxJava (why not)- Retrolambda- Kotlin?

Page 78: From newbie to

Britt BreakOR