• úvod
  • témata
  • události
  • tržiště
  • diskuze
  • nástěnka
  • přihlásit
    registrace
    ztracené heslo?
    LWEEKAndroid development
    Diskuse o vývoji aplikací pro platformu Android.
    -----------------
    Tipy, Triky, Postřehy, Začátečnický help, Nápady na nové aplikace.

    Oficiální developerská stránka: http://developer.android.com
    Něco málo v češtině na WiKi android fora: http://wiki.androidforum.cz/index.php/Programov%C3%A1n%C3%AD
    Článek na Zrojáku: http://zdrojak.root.cz/clanky/vyvoj-pro-android-ii/

    Docela zajímavé tutoriály přímo od vývojářů ze Sony Ericsson:

    na tvorbu vlastního View adapteru
    http://blogs.sonyericsson.com/developerworld/2010/05/20/android-tutorial-making-your-own-3d-list-part-1/

    zajímavý nápad na zoomování jedním prstem - aneb vytváření gest
    http://blogs.sonyericsson.com/developerworld/2010/05/18/android-one-finger-zoom-tutorial-part-1/
    rozbalit záhlaví
    ADAMH
    ADAMH --- ---
    DRIZDIK: 1) No těžko říct zda ano a jak to zjistit, čekal bych od templatu vytvoření aplikace že bude funkční ve stavu v jakém je vytvořen.
    2) jediné co jsem našel jako asi správné je action element v "mobile_navigation.xml" ale nastavit tam back button nevidím, návody na to nejsou, je to asi relativně nové
    DRIZDIK
    DRIZDIK --- ---
    ADAMH:
    1) očekávám že přes to máš ještě nějaký layout, který ti zachytává dotyky
    2) dvě možnosti .. bud používáš jen fragmenty a zpět je backstack pop (všechno ostatní si musíš dělat manuálně), případně používáš navigation component, kde si v tom grafu určuješ, jak se má navigace v jednotlivých přechodech chovat
    ADAMH
    ADAMH --- ---
    Zeptal bych se znova, pokud bude mít ještě někdo chuť odpovedět.

    1) v čisté nové aplikaci bez jakéhokoli zásahu mě v emulátoru ani v mobilu nereaguje aplikace na touch v menu (navigation drawer) s navcontrolerem, divny, ze pokud si v emulatoru otevru to menu mysi a pak klikam na šipky na klávesnici nahoru a dolu a dám enter tak se ten fragment změní, ale klasickej dotyk nic, co tam schází?

    2) chtěl bych to dělat správně, ale např jsem narazil, že nevím jak určit jaký fragment se má aktivovat po zmačknutí tlačítka zpět, předpokládal bych že to jde přes XML "mobile_navigation.xml" , overidovat onBackPressed v activitě se mě moc nechce , když jedu na fragmenty

    To by bylo asi prozatím vše.
    ADAMH
    ADAMH --- ---
    DRIZDIK: No když se človek podívá na cízí aplikace, tak tam často také ty fragmenty nenajde. Nejsem ani tak junior, jen spíše samouk. Mám appku s 1M staženími a dělal jsem i s libgdx což také nezkouší každý. Když se človek podívá na nejstahovanější či hodně stahované aplikace vidí tam ještě dnes zvěrstva typu žádosti o přístupu k fotaku či uložisti a to jen proto, že developer neumi používat fileprovider (když chce sdilet screenshot) či intenty.

    Rád se přiučím, nemám problém se zeptat, problém je v tom , že jen málo lidi co poradí to dělá správně. A to je vlastně to co píšeš v poslední větě :)
    DRIZDIK
    DRIZDIK --- ---
    ADAMH: Ale tvoje obtíže by ti měli dát nahlédnout do toho jak dělat správnou architekturu. Activita nebo Fragment je jen View a nemělo by zastupovat funkci modelu. Plus aktivita a fragment ti mohou kdykoliv umřít, když uživatel otočí displej nebo dá appku na pozadí. Ale nic si z toho nedělej, postupně budeš potkávat zdrojáky, kde zjistít, že ani lidé, kteří se prezentují jako velmi seniorní, to nevědí :-)
    ADAMH
    ADAMH --- ---
    JOHNY_G: No jasny, staticka je ale oproti těm bežným statickým objektům má vnitřní hodnoty. Zkousel jsem teď hledat další příklady in-memory singletonu a zdá se, že destroy nikdo neřeší. Tj nenašel jsem tam žádnou zmínku že by ho někdo definoval a ani příklad co by to mělo obsahovat. Takto to bude asi funkční a stabilní.
    JOHNY_G
    JOHNY_G --- ---
    No ta instance právě statická je. Proto bys tam měl přidat ještě alespoň ten destroy, který tu referenci vynuluje, až ji nebudeš potřebovat :-). Lepší je mít nějaký robustnější dependency management, který ti ten životní cyklus uřídí v rámci definovaného scopu a s efektivnější thread safety, ale připadalo mi, že to není tvůj případ :-). Tohle by měl snad přinejhorším požrat garbage collector, až Android tu aplikaci zcela ukončí.
    ADAMH
    ADAMH --- ---
    JOHNY_G: Ja ty sharedpreference pouzivam zpravidla na data co se maji ulozit z nastaveni a pri dalsim spusteni appky nacist. Necekal bych ze je pouziju jen na proste predavani dat v ramci jedne aplikace a jednoho spusteni, podobne i sqlite se me zda takova naddimenzovana.

    JOHNY_G: Tohle zacina byt zajimavejsi. To ze funguje bez predani instance (tj to co jsem doted resil ze jsem musel do kazdeho fragmentu instanci objektu nejak predat) a vypada jako staticky a pritom neni je elegantni, vyzkousim, diky.
    JOHNY_G
    JOHNY_G --- ---
    Ten in-memory singleton může být asi takhle triviální. Má to své mouchy (slušelo by se doimplementovat alespoň destroy(), když už nic jiného), ale už v této podobě to bude daleko robustnější než křížové reference aktivity a fragmentů :-).
    public class DataRepository {
        private String name;
        private String email;
    
        private static DataRepository instance;
    
        public static synchronized DataRepository getInstance() {
            if (instance == null) {
                instance = new DataRepository();
            }
    
            return instance;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getEmail() {
            return email;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
    }

    První fragment:
    DataRepository.getInstance().setName("Jarda");

    Druhý fragment:
    DataRepository.getInstance().setEmail("jarda@novak.cz");

    Třetí fragment:
    DataRepository dataRepository = DataRepository.getInstance();
    String name = dataRepository.getName();
    String email = dataRepository.getEmail();

    Jednoduchý jak žebřík :-).
    JOHNY_G
    JOHNY_G --- ---
    ADAMH: No už se někam dostáváme :-). Tyto fragmenty rozhodně mohou být zcela nezávislé. Potřebuješ jenom nějaký repozitář pro data. Pokud mají být perzistentní i do dalšího spuštění, tak si to dej prostě do SharedPreferences (sice potřebují context, ale na to právě můžeš použít getActivity()), odkud si to na druhé straně zase vytáhneš. Počítám tedy, že jde o triviální data, která můžeš zaznamenat jako key-value. Jinak totéž, ale s nějakou databází :-)). Pokud jsou data jednorázová a po ukončení irelevantní, tak si prostě udělej singleton, do kterého to budeš ukládat in-memory. Jestli použiješ nějaký sofistikovaný thread-safe a lifecycle-aware framework, anebo si tam prostě uděláš statickou referenci a getInstance(), to záleží čistě na tobě :-)). Osobně bych si kvůli modularitě udělal singletonový wrapper i na ty Shared Preferences, ale to už bys musel být lifecycle-aware kvůli tomu kontextu. Takže na vlastní nebezpečí :-).
    ADAMH
    ADAMH --- ---
    JOHNY_G: Je to asi dost poznat :)

    K příkladu co chci docílit. Mám svoji api třídu, která získává data z internetu či je tam ukládá.

    - intro fragment - který přes api získá data, jakmile je získá zobrazí část těchto dat a tlačítko pokračovat
    - home fragment - tam se zobrazí volby (switche) co si uzivatel nastavi a pak stiskne tlačitko na začít pracovat
    - pracovni fragment - tam se to cele provadí na zaklade dat z api tj intro fragmentu a i na zaklade toho co si nastavi uzivatel v home fragmentu pres ty switche a posleze se pres api neco ulozi

    To jak jsi to psal mě začíná případat logické, ale představoval bych si (což je asi špatně), že ta data budu mít uložena v aktivite a fragmenty je budou menit ci doplnovat dle potřeby.

    Předpokládám teda, že správně to je tak ze z activity se do fragmentu pošle v zásadě jen úvodní dávka informací při otevření a to je vše. A do activity se vicemene nic neposila.
    JOHNY_G
    JOHNY_G --- ---
    ADAMH: Já jsem se ztratil taky. Předpokládám, že Android není zrovna tvoje domovina, stejně jako Java, takže jsem zabloudil už u deskriptoru :-)). Předpokládám, že mluvíme o referenci, což už takhle na začátku vypadá na křehkou architekturu, protože fragment a aktivita nemají dokonale synchronizovaný životní cyklus, takže si koleduješ o IllegalStateException, navíc ostré reference na context (v tomto případě aktivita) nevyhnutelně vedou k memory leakům. Aktivita by měla řídit jen životní cyklus, a sice na úrovni aktivity, tedy nad fragmentem (např. spouštím jinou aktivitu, jinou aplikaci, zobrazuji dialog). Fragment by měl být soběstačný, a když po aktivitě něco chce, má na ní nullable getter getActivity(), popř. unsafe non-null requireActivity(). Nemyslím si, že by aktivita měla kdy něco chtít po fragmentu (vstupní parametry obstarají Safe Args v navigation components, popř. getInstance() a arguments bundle), tudíž neshledávám důvod k obousměrné komunikaci. Zejména, když používáš nav controller, pro který si fragment umí sáhnout sám přes findNavController(). Počítám, že MVVM nepoužíváš, takže budeš mít ve fragmentu i business logiku a tudíž ti odpadá ta relevantní oboustranná komunikace mezi fragmentem a viewmodelem. Můžeš uvést příklad svého use case? Vyzkoušený tutorial nemám, protože jsem se to učil při práci na již navrženým projektu postaveném na Android Clean Architecture (extrémně nedoporučuji!) a já jsem si z ní pro svoje projekty odnesl jen to, co jsem považoval za funkční :-).
    ADAMH
    ADAMH --- ---
    JOHNY_G: Ač nejsem začátečník, tak uznám, že se v tom ztrácím. Já si zpravidla do fragmentu přenesu deskriptor activity z activity volam přes deskriptor fragmentu. S navcontrolerem se to zdá být obtížnější. Neřeším znovpoužitelnost aplikace ale to aby fungovala.

    Bohužel těch návodu na internetu je hodně, ale je to jak kdy kotlin či java (dělám v jave), často je to návod na vieparger, často jen na nějaký základní přenosy dat a jen jedním směrem. Pro mě chaos.

    Nemáš náhodou někde opravdu funkční ukázku s navcontrolerem v jave na obousmernou komunikaci?
    JOHNY_G
    JOHNY_G --- ---
    Já s fragmenty nemám problém. Používám je s architecture a navigation components k takřka plné spokojenosti. Jediný problém mám s nav controllerem a jeho správou back stacku, ale člověk si zvykne. V MVVM není obvykle nad rámec občasných argumentů (které nav controller podporuje) ke komunikaci mezi fragmenty důvod. Na logiku přesahující potřeby obrazovky/fragmentu/viewmodelu typicky používám nějaký provider (dle potřeby singletonový nebo instancovaný přes factory) a/nebo repository.
    ADAMH
    ADAMH --- ---
    Bude to znít asi jako začátečnícký dotaz, ale i tak to zkusím.

    Máte rádi fragmenty? Mě se jeví značne nefunkční a obzvláště komunikace mezi nima a celková funkčnost aplikace se stává velmi složitou a méně funkční než když se dá jen jedna activita bez fragmentu. Obzvlášt těd co jsem zkusil udělat appku s navcontrolerem namísto fragment manageru.

    Navíc protěžovaný kotlin čímdál víc zabírá misto původní jave ve smyslu různých howto apod.
    DATEL
    DATEL --- ---
    Ahoj, zoufalý dotaz. Děláte někdo widgety? Mám tu záhadu, nad kterou sedím už dvě hodiny, zkouším kde co a bez výsledku. Ve vlastní třídě poděděné z AppWidgetProvideru mám onUpdate(). Ten je v android knihovně interně volaný z onReceive(), když přijde android.appwidget.action.APPWIDGET_UPDATE - tato událost by dle dokumentace měla přijít např. po rebootu, restartu aplikace nebo když je dosažen časový limit nastavený v konfiguraci appwidget-provider přes updatePeriodMillis. Podotýkám, že to mám nastavené na 0.

    A teď, úplně jsem vyházel kód, zůstala jen holá kostra. V tom onUpdate() volám:

    val refreshWorkRequest = OneTimeWorkRequestBuilder<RefreshWidgetWorker>()
    WorkManager.getInstance().enqueueUniqueWork(REFRESH_WORKER_TAG, ExistingWorkPolicy.KEEP, refreshWorkRequest)

    uvnitř toho RefreshWidgetWorkeru je doWork, který teď nic nedělá, jen vrátí Result.success()

    A teď ten problém - zavolání toho enqueueUniqueWork způsobí to, že je v tom widget provideru neustále vyvoláván onUpdate(), tj. do onReceive() chodí ta akce action.APPWIDGET_UPDATE - a vůbec nechápu proč. Když to volání enqueue metody vyhodím, je to v pohodě. Způsobuje snad vyvolání nějakého "procesu" na pozadí to, že do widgetu jde znova ten Intent? Je otázka, jestli nový nebo původní?
    LWEEK
    LWEEK --- ---
    JOHNY_G: Ha ha, dík :-)
    JOHNY_G
    JOHNY_G --- ---
    LWEEK: Počítám, že už jsi na pokraji šílenství z takového úkolu všechna čistá řešení s propagací eventů vyzkoušel, takže to zkusme ručně :-D. Musíš se progetovat k příslušné Drawable (nevím, jestli to máš jako background, src, nebo kýhočerta) a na ní zavolat setState(new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled}) a třeba za čtvrt sekundy zase reset na setState(new int[]{}). Když najdeš RippleDrawable (na API 21+), tak si to můžeš vycastovat a zaměřit pomocí setHotspot(0.5f, 0.5f) (aspoň myslím, že jsou to relativní souřadnice, to už si vyžehlíš). Pěkná čuňárnička :-).
    LWEEK
    LWEEK --- ---
    Tak jsem to vyřešil, ale přišel jsem o ripple efekt. Netušíte jestli jde nějak zobrazit na parentu ripple efekt pokud dojde ke clicku v childu?
    LWEEK
    LWEEK --- ---
    Vyrábím tabulky. Potřebuju aby se to scrolovalo horizontálně i vertikálně. Ale aby to bylo vtinější mám tam takzvané sticky sloupce které mohou být nalevo i napravo. Ale potřebuju aby když uživatel klikne kamkoliv tak to zaznamenalo klik "na řádek" a zároveň aby fungoval vnitřní scroll a tlačítka které mohou být vnořené jak v prostřední horizontálně scrollovacím view tak i v těch postraních. Už mi z toho malinko hrabe. :)
    JOHNY_G
    JOHNY_G --- ---
    LWEEK: Interceptovat můžeš, ale pokud to nechceš zkonzumovat, tak musíš vrátit false, tím pádem ty eventy probublají dál.

    Většinu podobných bolehlavů vyřešíš tím, že vyměníš ScrollView za NestedScrollView, který má většinu podobných scénářů ošetřenou. V ideálním případě upravíš návrh tak, aby tam nesting vůbec nebyl (neznám tvůj use case, ale v případě HorizontalScrollView může být alternativou ViewPager), ale ne vždycky to jde, a vždycky je to opruz :-)).
    Kliknutím sem můžete změnit nastavení reklam