Android fortsättning TDDD80 Mobila och sociala applikationer
2018-02-24 Krav labb A2 + A3 Scrollbar lista + detalj-vy Stor skärm - liten skärm Rotation Nätverksanrop Hämta data från server Hantera JSON
Scrollbar lista + detalj-vy
2018-02-24 Uppgift Scrollbar lista + detalj-vy Stor skärm - liten skärm
2018-02-25 Uppgift Scrollbar lista + detalj-vy Stor skärm - liten skärm
2018-02-25 Bred skärm eller roterat (landscape)
2018-02-25 Använd två Activities?
2018-02-25 Nackdelar Activities är speciella, eftersom de har direktkontakt med Android Kan inte läggas två på samma skärm Kan inte läggas inne i varandra
2018-02-25 Vill ha flyttbara, återanvändbara skärmbitar
2018-02-25 Mål Återanvända både layout Layout klickhantering Beteende datahantering
2018-02-24
2018-02-24
2018-02-24 MainActivity Direktkontakt med Android OS Kan anropas utifrån (från andra appar) Navigering mellan fragment/skärmar Starta med ListFragment Hantera klick Starta upp nytt DetailsFragment
2018-02-24 Fragments Visning av information Datahantering Ska inte veta om vilka andra fragment som finns på skärmen just nu Eftersom detta kan variera Ska bara veta om MainActivity Mer generellt Context
2018-02-25 Klickhantering ListFragment visas på skärmen En list-item klickas i ListFragment Kan inte meddela DetailsFragment direkt Skicka klick uppåt till MainActivity
2018-02-25 Uppåt-kommunikation MyListFragment: @Override public void onlistitemclick(listview l, View v, int position, long id) { // call the callback method on the context // that this fragment is currently attached to mycontext.onitemselected(l, v, position, id); } Vad händer om mycontext (dvs. MainActivity) inte har en metod som heter onitemselected?
2018-02-26 Lösning Kräv att Context (MainActivity) som fragmentet kopplas till implementerar ett interface som definieras av fragmentet M.a.o. definiera ett interface i MyListFragment: MyListFragment.ItemSelectedListener
2018-02-25 MyListFragment.ItemSelectedListener I MyListFragment: // Want to be able to call this method on the context // that this list fragment is attached to public interface ItemSelectedListener { public void onitemselected(listview l, View v, int position, long id); }
2018-02-26 Fragmentet dubbelkollar // Fragmentet håller på att kopplas till MainActivity @Override public void onattach(context context) { super.onattach(context); if (context instanceof ItemSelectedListener) { mycontext = (ItemSelectedListener) context; } Har context implementerat gränsnittet? } else { throw new ClassCastException(context.toString() + " must implement "); Lagra en referens
2018-02-24 Fragment
2018-02-24
2018-02-24 MainActivity Innehåller en FrameLayout som platshållare Lägg i MyListFragment vid oncreate
2018-02-24 MainActivity Innehåller en FrameLayout som platshållare Lägg i MyListFragment vid oncreate
2018-02-24 Vid klick Byt innehållet i FrameLayout till MyDetailsFragment Namn: Kalle Petterson Epost: kalle123@gmail.com Namn: Elinor Karlström Epost: ella97@telia.se Svarade: Kalle
2018-02-24 Stora skärmar En huvud FrameLayout En details FrameLayout Twitter medlemmar: Namn: Kalle Petterson Epost: kalle123@gmail.com Namn: Elinor Karlström Epost: ella97@telia.se Svarade: Kalle
2018-02-24 Att lägga i ett fragment i ramen detailsfragment = new MyDetailsFragment(); FragmentTransaction transaction = getsupportfragmentmanager().begintransaction(); transaction.replace(r.id.frame, detailsfragment); transaction.addtobackstack(null); transaction.commit();
2018-02-24 Att skicka med information // implicit way of sending arguments to the fragment Bundle args = new Bundle(); String groupname = myadapter.getitem(position).tostring(); args.putstring("groupname", groupname); detailsfragment.setarguments(args); I fragmentet: this.groupname = args.getstring("groupname");
2018-02-24 Adapter: matar listan med data
2018-02-24 Adaptern matar listan med data data MyGroups getview MyListFragment listitem adapter MyAdapter GET http:// /grupper server
2018-02-26 MyListAdapter @Override public View getview(int position, View convertview, ViewGroup parent) { // convertview -> textview } textview.settext((mygroups.getitem(position).tostring())); return textview; Referens till data-klassen MyGroups.. Kan vara null!
2018-02-25 MyListAdapter Återanvänd gammal View @Override public View getview(int position, View convertview, ViewGroup parent) { if (convertview == null) { textview = (TextView) myinflater.inflate(itemlayoutfileid, parent, false); } else { textview = (TextView) convertview; }
2018-02-24 MyDetailsFragment direktkontakt med server Twitter medlemmar: Namn: Kalle Petterson Epost: kalle123@gmail.com data MyGroupMembers Namn: Elinor Karlström Epost: ella97@telia.se Svarade: Kalle GET /medlemmar/twitter MyDetailsFragment(Twitter) server
2018-02-25 UI:t måste vara responsivt Appen måste reagera på användarinput inom 5 sekunder (helst 100-200 ms) Annars får användaren en "Application Not Responding" (ANR) dialog
2018-02-25 Trådar Main thread (UI thread) Reseverat för användarinteraktion Visa info Reagera på klick, etc. Cache thread Temporär lagring av hämtade data Worker thread (1, 2, 3,.) För tungt/långsamt arbete i bakgrunden
Hämta data från servern
2018-02-25 Nätverksanrop Volley Googles egna bibliotek http://developer.android.com/training/volley/ind ex.html https://github.com/google/volley/releases AndroidAsyncHttp Populärt bibliotek http://loopj.com/android-async-http/ f
2018-02-25 build.gradle (app) dependencies { compile 'com.android.volley:volley:1.0.0' compile 'com.google.code.gson:gson:2.8.2' }
2018-02-24 Volley
2018-02-25 Volley erbjuder bas-klassen Request Definiera egen klass MyGsonRequest Utgå från exemplet på Android developer pages: https://developer.android.com/training/volley/re quest-custom.html Använd Googles Java bibliotek för JSON: Gson https://github.com/google/gson/blob/master/us erguide.md
2018-02-25 Nätverksanrop Nätverksanrop t.ex. i MyListAdapter: Skapa request = new MyGsonRequest( ) Lägg till request:et i en kö Nätverksanropet sker automagiskt på separat tråd Svar kommer i din lyssnare på main (UI) thread
2018-02-24 Skapa request request = new MyGsonRequest<>( Method.GET http://.../grupper, MyGroups.class, null, // no headers null, // no body, // olika call-backs, dvs. lyssnare) Packa upp JSONresponsen till ett objekt av klassen MyGroups requestqueue.add(request); // don't wait for response
2018-02-24 T.ex. i MyListAdapter request = new MyGsonRequest<>( // method, URL, etc. new Response.Listener<MyGroups>() { @Override public void onresponse(mygroups response) { updategroups(response); } }, Skickar även med lyssnare (callback när respons finns) private void updategroups(mygroups response) { groups = response; notifydatasetchanged(); // broadcast: nya data är tillgängliga! }
2018-02-25 Sekvensdiagram MyListFragment MyAdapter server GET /grupper updategroups() notifydatasetchanged() getview()
2018-02-25 Skicka JSON, vid t.ex. inloggning headers = new HashMap<String, String>(); headers.put( content-type, application/json ); payload = new mylogindata(useremail, userpassword); body = gson.tojson(payload); request = new GsonRequest<>(Method.POST,, headers, body, ); requestqueue.add(request);
2018-02-25 Ta emot token request = new GsonRequest<>( Method.POST, mytokenholder.class, headers, body, ); Packa upp serverresponse till objekt av den här klassen Response { "access_token": server-generated.jwt.here", "token_type": Bearer", "expires_in": 3600 }
2018-02-26 Skicka token i headers headers = new HashMap<String, String>(); headers.put( Authorization, Bearer + accesstoken); request = new GsonRequest<>(, headers, ); requestqueue.add(request);
GsonRequest Bygger ihop requests packar upp response
2018-02-25 GsonRequest public class GsonRequest<T> extends Request<T> { private final Gson gson = new Gson(); public GsonRequest(int method, String url, Class<T> clazz, ) { super(method, url, ); } this.clazz = clazz; Referens till data-klassen MyGroups, el. MyGroupMembers
2018-02-25 GsonRequest (uppackning av response) @Override protected Response<T> parsenetworkresponse(networkresponse response) { try { json = new String(response.data, // encoding info from headers); return Response.success( gson.fromjson(json, clazz), // get response code from headers); }
2018-02-24 Biblioteket Gson Googles egna bibliotek för att parsa JSON direkt till Java objekt Man anger att man vill ha objekt av typen MyGroups.class när man skapar ett request Gson sköter nerpackning och uppackning av data Packar upp data till Java Beans!
2018-02-24 Java Beans Null-konstruktor Var. namn matchar JSON-nycklarna Finns getters och setters för alla var. Möjliggör automatisk uppackning av JSON till objektet
2018-02-24 Mer om GsonRequest (med kodexempel) https://developer.android.com/training/volley/requ est-custom.html
www.liu.se
2018-02-25 ViewModel (ny arkitekturkomponent) Nuvarande problem med ViewModel Hanterar inte fragment lifecycle Detach / attach Utvecklare behöver vara medveten om när onstop p.g.a. rotation, när risk för senare ondestroy Eftersom förra hanteras av ViewModel, men inte senare Funkar inte med Gson Blir därför jobbigare JSON-hantering