<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: raha</title>
    <description>The latest articles on DEV Community by raha (@srahman0203).</description>
    <link>https://dev.to/srahman0203</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3986082%2F8424d118-51c6-4d78-926e-4d67bfe2f906.png</url>
      <title>DEV Community: raha</title>
      <link>https://dev.to/srahman0203</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/srahman0203"/>
    <language>en</language>
    <item>
      <title>android doze kills your react native background tasks--here's why and how to fix it</title>
      <dc:creator>raha</dc:creator>
      <pubDate>Mon, 15 Jun 2026 18:48:32 +0000</pubDate>
      <link>https://dev.to/srahman0203/android-doze-kills-your-react-native-background-tasks-heres-why-and-how-to-fix-it-2299</link>
      <guid>https://dev.to/srahman0203/android-doze-kills-your-react-native-background-tasks-heres-why-and-how-to-fix-it-2299</guid>
      <description>&lt;p&gt;android doze kills your background tasks and nobody explains why properly&lt;br&gt;
been building a react native app that schedules stuff to run later. worked fine every time i tested it. shipped it, and it started missing schedules. only when the phone had been sitting idle for a while. never on my desk.&lt;br&gt;
took me way too long to figure out what was going on so writing it up here.&lt;br&gt;
what happens&lt;br&gt;
you schedule something for 1am. check logs next morning:&lt;/p&gt;

&lt;p&gt;01:00:00  alarm fired&lt;br&gt;
01:00:02  connected (while back grounded, 2 seconds)&lt;br&gt;
01:18:xx  the actual send ran&lt;/p&gt;

&lt;p&gt;the connection came up fine. in 2 seconds. while the phone was back grounded. but the code that was supposed to do something with that connection ran 18 minutes later when something else woke the phone up.&lt;br&gt;
why&lt;br&gt;
doze mode freezes javascript timers. setTimeout, setInterval, any polling loop on the js thread-all frozen. but native events (connection callbacks, lifecycle events, native module bridges) keep firing.&lt;br&gt;
i had a setInterval checking "are we connected yet" every second. doze froze that loop. the connection came up, nobody noticed for 18 minutes because the thing checking for it was asleep.&lt;br&gt;
the phone could do the work. my code just couldn't tell.&lt;br&gt;
stuff i tried that didn't fix it&lt;br&gt;
foreground service — keeps the process alive but doesn't unfreeze js timers. not the problem.&lt;br&gt;
more setTimeout/setInterval variations, literally the thing causing it. spent two days making the problem worse.&lt;br&gt;
HeadlessJS dropped in without changes compiled, never ran on newer RN. lost a few hours there.&lt;br&gt;
the actual fix&lt;br&gt;
move everything off timers. put your work directly in the event handler.&lt;br&gt;
instead of polling to check if you're connected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;js&lt;/span&gt;&lt;span class="c1"&gt;// this is frozen by doze. don't.&lt;/span&gt;
&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isReady&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="nf"&gt;doWork&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="nx"&gt;jsconnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doWork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;native events survive doze. timers don't. that's the whole thing.&lt;br&gt;
for waking up at the right time — native AlarmManager with setExactAndAllowWhileIdle. it's the doze-piercing variant. set that to fire at your scheduled time, let it cold-start the app, then your event handler picks it up.&lt;br&gt;
AlarmManager fires at T (native, survives doze)&lt;/p&gt;

&lt;p&gt;→ app cold starts&lt;br&gt;
    → opens connection&lt;br&gt;
      → "connected" event fires&lt;br&gt;
        → do the work in the handler&lt;br&gt;
no timers anywhere in that chain.&lt;br&gt;
persistence matters&lt;/p&gt;

&lt;p&gt;your app is probably a cold start at fire time. process got killed hours ago. anything in memory is gone. write your pending jobs to AsyncStorage (or whatever persistent store you use) when scheduling, read them back on every launch. if the job isn't on disk it doesn't exist.&lt;br&gt;
delete after success, not before  if something crashes mid-run the job stays on disk for next time instead of disappearing silently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
const job = await Storage.get('pending_job')
if (job) reconnect()

connection.on('status', (state) =&amp;gt; {
  if (state === 'connected') {
    doWork(job)
    Storage.delete('pending_job')
  }
})


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;samsung/xiaomi/oppo will still kill you&lt;br&gt;
stock android respects the alarm. samsung and the rest have their own battery killing layer on top. your alarm fires, your receiver triggers, and then the OS kills your service before the js task starts. nothing you can do except prompt the user to whitelist your app from battery optimisation on those devices. fun times.&lt;br&gt;
wrapping up&lt;br&gt;
i'm cleaning up the native alarm + headless task + event-driven scaffolding into a starter repo so other people don't have to wire this from scratch. if that sounds useful drop a comment.&lt;/p&gt;

&lt;p&gt;**&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>android</category>
      <category>mobile</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
