Fórum Živě.cz

Víc lidí víc ví
Právě je 6. 3. 2021 06:45

Všechny časy jsou v UTC + 1 hodina




Odeslat nové téma Odpovědět na téma  [ Příspěvků: 7 ] 
Autor Zpráva
 Předmět příspěvku: Android Java - plánované (časované) operace
Odeslat příspěvekNapsal: 4. 11. 2019 11:58 
Offline
Junior
Ahoj,

měl bych obecný dotaz k plánovaným (časovaným) operacím na Androidu z aplikace.

Začínám tak, že si odvodím třídu z BroadcastReceiveru

Kód:
public class MyBroadcastReceiver extends BroadcastReceiver {

@Override
    public void onReceive(Context context, Intent intent) {

// Zde provedu akci, která se má provést při plánování

}
}


Na tuto třídu použiji referenci v mojí aktivitě, třeba takto:

Kód:
public void onClickBtnClick(View v)   // Při kliknutí na buttonek naplánuj:
    {
      AlarmManager alarmMgr = (AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
       Intent intent = new Intent(this, MyBroadcastReceiver.class); 
     pendingIntent = PendingIntent.getBroadcast(this, 1, intent,
                                PendingIntent.FLAG_UPDATE_CURRENT);
                alarmMgr.set(AlarmManager.RTC_WAKEUP, 20000000,  pendingIntent);
  }


Ovšem někdy se to nechová tak, jak by mělo.
Obecně jsem vypozoroval, že při krátkých, několikaminutových intervalech
to funguje docela spolehlivě. Ovšem pokud tam zadám interval v řádu hodin, tak většinou žádné samočinné upozornění neproběhne. Upozornění proběhne však okamžitě, jakmile mobil probudím.

Všimnul jsem si, že podobně nespolehlivě se chovají i profesionální aplikace na GooglePlay.
Například Bluemail a podobně.

Mám mobil Asus Zenfone Max Pro M1 ZB602KL.

Potřeboval bych se prosím zeptat, zda tento problém souvisí obecně s agresivním uspáváním na mobilech, nebo zda jsem něco přehlédl.
Co jsem četl na internetu, tak u nových systémů se doporučuje spíše používat jinou třídu namísto AlarmManager.

Na straně druhé je internet plný podobných příspěvků, kdy se lidem nechce alarm aktivovat a v podstatě tam nejsou kloudné odpovědi. Respektive toto jsem odkoukal, jako "best practise" postup.

Každý android obsahuje aplikaci budík, která funguje spolehlivě.
A pak je otázkou zda je taková aplikace nějak privilegovaná nebo jen dobře napsaná.

Tak zdá se, tady jsem našel smutnou odpověď, přímo v dokumentaci:
Citace:
Note: Beginning in API 19, the trigger time passed to this method is treated as inexact: the alarm will not be delivered before this time, but may be deferred and delivered some time later. The OS will use this policy in order to "batch" alarms together across the entire system, minimizing the number of times the device needs to "wake up" and minimizing battery use. In general, alarms scheduled in the near future will not be deferred as long as alarms scheduled far in the future.

With the new batching policy, delivery ordering guarantees are not as strong as they were previously. If the application sets multiple alarms, it is possible that these alarms' actual delivery ordering may not match the order of their requested delivery times. If your application has strong ordering requirements there are other APIs that you can use to get the necessary behavior; see setWindow(int, long, long, android.app.PendingIntent) and setExact(int, long, android.app.PendingIntent).

Applications whose targetSdkVersion is before API 19 will continue to get the previous alarm behavior: all of their scheduled alarms will be treated as exact.


Nahoru
 Profil   
 
 Předmět příspěvku: Re: Android Java - plánované (časované) operace
Odeslat příspěvekNapsal: 4. 11. 2019 16:41 
Offline
Moderátor
S programováním pro android zkušenosti nemám, takže co za třídu použít ti neporadím. Ale kolega v práci měl podobný problém i s budíkem. Bylo to před pár lety, tehdy měl nějaký samsung (asi S4) a měl stejný problém. Pokud budík nastavil, aby zvonil za pár minut tak vše OK, ale jakmile tam nastavil třeba hodinu, na telefon nesahal, tak nezvonil. Začal zvonit až když telefon probudil. Jak to tehdy vyřešil ani nevím, ale vím že si na to stěžoval a říkal že je to naprd, když ho budík ráno nevzbudí a začne zvonit až když se vzbudí sám a chce se na telefon podívat kolik je hodin.

Jinak jako řešení by mohlo být použití krátkého alarmu a trochu aplikační logiky.
Například víš že potřebuješ vykonat nějakou činnost ve 21:30 (tj např za 5 hodin). Funkce pro zavolání alarmu bude kontrolovat zda je čas plánu delší než např 10 minut. Pokud ne, tak nastaví alarm na požadovaný čas. Pokud bude delší tak nastaví alarm jen na 10 minut. Jinými slovy, alarm se nastaví max na 10 minut do budoucnosti.
Při probuzení zkontrolovat zda je již požadovaný čas 21:30. Pokud ano, tak provést požadovanou činnost. Pokud ne, tak znovu naplánovat alarm.
Tím pádem se bude telefon stále každých 10 minut probouzet a kontrolovat zda už má něco dělat nebo dále spát. Asi to bude žrát baterku, ale snad né moc.

Je mi jasné že je to celkem prasácké řešení, ale když ti android háže klacky pod nohy, tak mu je tam házej taky.

_________________
Desktop: Ryzen 7 1800X (3.95GHz, 1.35V), Asus Crosshair VI Hero, 16GB DDR4 Ram (3200MHz), 128GB SSD + 3TB HDD, Nvidia GTX 1080
Notebook: Asus UL50VT 15.6" (SU7300@1.7GHz, 4GB ram, 500GB HDD, Intel GMA 4500MHD + nVidia G210M, dlouha vydrz cca 7+ hod)


Nahoru
 Profil   
 
 Předmět příspěvku: Re: Android Java - plánované (časované) operace
Odeslat příspěvekNapsal: 4. 11. 2019 18:02 
Offline
Junior
Díky Nargone za postřeh.

Přesně tento problém řeším. A popisuji ho ke konci citováním dokumentace.
Tam to v podstatě popisují jako "zdravé chování", za účelem šetření baterii.


Nahoru
 Profil   
 
 Předmět příspěvku: Re: Android Java - plánované (časované) operace
Odeslat příspěvekNapsal: 6. 11. 2019 14:49 
Offline
Junior
Som len pokročilý začiatočník (to je teda oxymoron) a s týmto som ešte nerobil (moje maximum je zatiaľ práca s firebase), ale osobne by som povedal, že android ti tú aktivitu zabíja - pár minút ti ju nechá bežať ale potom ti ".destroy()"ne
https://developer.android.com/guide/com ... -lifecycle
Trochu Googlením som našiel https://developer.android.com/reference ... duler.html
Ale až od API 21, keď tak nezabudni prepísať gradle.


Nahoru
 Profil   
 
 Předmět příspěvku: Re: Android Java - plánované (časované) operace
Odeslat příspěvekNapsal: 6. 11. 2019 16:36 
Offline
Junior
Ano, děkuji za rady.
Scheduler je přesně ta alternativa, kterou jsem myslel, ale nedokázal jsem si vzpomenout na název.

Perfektní článek zdarma je zde:
https://blog.teamtreehouse.com/scheduling-work-jobscheduler
Hned jsem si ho stahl, pro případ, že by zmizel.

Nicméně třída neobsahuje sama o sobě něco, co by umožňovalo na čas plánovat.
To do ní musí zřejmě nějak přidat uživatel-programátor.
Například pomocí periodického setPeriodic.

V každém případě by mě moc zajímalo, jak funguje takový WhatsApp nebo kecálek Facebooku. Tyto programy totiž dokáží vždy spolehlivě upozornit na novou zprávu a vzbudit mobil ihed.

Tak by mě hodně zajímalo, zda implementují nějaké otrocké čekání. Nebo naopak jsou navázáni na nějakou "chytrou" podmínku "Network data change", kde kontrolují jen při jejím splnění efektivně podmínku. :hm

Jinak dotaz, který řešil totéž, co já je zde: (Jen použil novější JobScheduler
https://stackoverflow.com/questions/56011217/jobscheduler-scheduled-every-10-min-does-not-always-work

A nedopadl také slavně, tam mu zase snad doporučili použít to, co já použil neúspěšně.


Nahoru
 Profil   
 
 Předmět příspěvku: Re: Android Java - plánované (časované) operace
Odeslat příspěvekNapsal: 6. 11. 2019 19:37 
Offline
Junior
Prešiel som Google (aj mňa to celkom zaujíma) a pred Androidom 8 sa to riešilo službou (Service) - čo je logické.
Možno skús toto:
https://developer.android.com/training/ ... te-service


Nahoru
 Profil   
 
 Předmět příspěvku: Re: Android Java - plánované (časované) operace
Odeslat příspěvekNapsal: 7. 11. 2019 16:36 
Offline
Junior
Mmmm. Toto si nemyslím že bude řešením.

Na tom tvojem odkaze píší ukázku:
Kód:
public class RSSPullService extends IntentService { ......


Čili je odvozena servisní třída od IntentService.

A už na začátku v dotaze uvadím:
Kód:
Intent intent = new Intent(this, MyBroadcastReceiver.class); 


Takže si při vší úctě nemyslím, že tudy povede cesta.

Ale vrtá mi v hlavě, jak jsou navrženy moderní kecálky typu WhatsApp atd..., které spolehlivě mobil probudí kdykoliv, respektive při přijmu nové zprávy kdykoliv. :hm
Teď jsem se do toho ponořil trochu více.
Super článek, přes service tady:
https://www.vogella.com/tutorials/AndroidServices/article.html

-- 8. 11. 2019 20:24 --

Tak jsem nakonec neodolal a implementoval to přes service a odvozenou třídu od timeru v tom service:
Obrázek

Popisek není přesný, je to doba timeru v service (v ms).
Takto implementovaný timer nemá problém vzbudit zařízení přesně i po 1h či 2h jsem to zkoušel.
Vše bez problému. Tedy až na jednu věc.

MyActivityClass:

Kód:
public class MainActivity extends AppCompatActivity {

    EditText editText;
    Intent serviceIntent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        editText = (EditText) findViewById(R.id.editText);

    }
    // Start the service
    public void startService(View view) {


        serviceIntent = new Intent(this, MyService.class);
        serviceIntent.putExtra("cas", editText.getText().toString());

        startService(serviceIntent);
    }
    // Stop the service
    public void stopService(View view) {

        stopService(serviceIntent);
    }
}



Servisní třída service (MyServiceClass) :

Kód:
public class MyService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        return  null;
    }
    @Override
    public void onCreate() {
        Toast.makeText(this, "Service was Created", Toast.LENGTH_LONG).show();
    }

    private Context context;
    private MediaPlayer player;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        player = MediaPlayer.create(this, Settings.System.DEFAULT_RINGTONE_URI);
        // This will play the ringtone continuously until we stop the service.
        player.setLooping(true);
        // It will start the player
        //player.start();
        this.context = this;
        Bundle extras = intent.getExtras();
        int zaCas = Integer.parseInt(extras.getString("cas"));
        new MyCountDownCalculator(zaCas, 1000) {
            public void onTick(long millisUntilFinished) {

            }

            public void onFinish() {
                PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
                PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "myapp:app_name");
                wl.acquire();

                player = MediaPlayer.create(context, Settings.System.DEFAULT_RINGTONE_URI);
                // This will play the ringtone continuously until we stop the service.
                player.setLooping(true);
                player.start();

                NotificationHelper notification = new NotificationHelper(context);
                notification.createNotification("Vzbuzuji device","Úspěch");
                wl.release();
            }
        }.start();

        Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
        return START_STICKY;
    }
    @Override
    public void onDestroy() {
        Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
        super.onDestroy();
        if(player != null)
        {
            try{
                player.stop();
                player.release();
            }finally {
                player = null;
            }
        }


    }
}


Pokud zadám nějaký drobnější časový interval, řekněme 4 minuty.
Tak se zařízení vzbudí a je možnost kliknout na tlačítko STOP SERVICE, které obsahuje v aktivitě MainActivity referenci na službu.
Ovšem pokud je interval delší, řekněme hodinu nebo dvě, tak se reference vymaže.
Vizuálně to není nijak vidět, ale probíhá stále zvonění !

Kód:
   player = MediaPlayer.create(context, Settings.System.DEFAULT_RINGTONE_URI);
                // This will play the ringtone continuously until we stop the service.
                player.setLooping(true);
                player.start();

A vtip je v tom, že zvonění už nejde nikterak vypnout z mojí aktivity, protože té se vymaže reference na tu službu. Jediná možnost, jak se zbavit toho zvonění je ručně killnout celý proces.

-- 9. 11. 2019 23:30 --

ča :-)

Viz. https://stackoverflow.com/questions/51460417/service-is-killed-in-sleep-mode-why

Výsledek: Nijak nevyřešeno. Plno odkazů, které ve výsledku nefungují spolehlivě.
To na straně jedné. Na straně druhé tu máme provokující WhatsApp nebo Facebook kecálek, které, ač jsou doinstalované, tak jsou vždy schopny upozornit na novou zprávu, i když je device ve sleep modu.

ča. Už mi z toho hrabe.


Nahoru
 Profil   
 
Zobrazit příspěvky za předchozí:  Seřadit podle  
Odeslat nové téma Odpovědět na téma  [ Příspěvků: 7 ] 

Všechny časy jsou v UTC + 1 hodina


Kdo je online

Uživatelé procházející toto fórum: Žádní registrovaní uživatelé a 0 návštevníků


Nemůžete zakládat nová témata v tomto fóru
Nemůžete odpovídat v tomto fóru
Nemůžete upravovat své příspěvky v tomto fóru
Nemůžete mazat své příspěvky v tomto fóru
Nemůžete přikládat soubory v tomto fóru

Hledat:
Přeskočit na:  
Podmínky pro užívání služby informační společnosti | Informace o zpracování osobních údajů | Cookies
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group