<?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: Nikhil Thakkar</title>
    <description>The latest articles on DEV Community by Nikhil Thakkar (@_nikhi1).</description>
    <link>https://dev.to/_nikhi1</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%2F242160%2F9333fed3-a149-4186-b399-06e8ca5c43aa.png</url>
      <title>DEV Community: Nikhil Thakkar</title>
      <link>https://dev.to/_nikhi1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/_nikhi1"/>
    <language>en</language>
    <item>
      <title>Hey Android, Where's my Process?</title>
      <dc:creator>Nikhil Thakkar</dc:creator>
      <pubDate>Thu, 29 Jul 2021 19:13:30 +0000</pubDate>
      <link>https://dev.to/_nikhi1/hey-android-where-s-my-process-4f0e</link>
      <guid>https://dev.to/_nikhi1/hey-android-where-s-my-process-4f0e</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Sometimes good guys gotta do bad things to make the bad guys pay. &lt;br&gt;
&lt;br&gt;- &lt;em&gt;Harvey Specter&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This article is a followup on this &lt;a href="https://medium.com/mindorks/hey-android-please-keep-my-activities-7bf96ccc0a38"&gt;medium article&lt;/a&gt; written by my friend Calvin. I would highly recommend you to go through it as it lays the foundation for this article.&lt;/p&gt;

&lt;p&gt;We would be particularly dealing with process kill scenarios and explore potential solutions to mitigate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Android App Lifecycle
&lt;/h2&gt;

&lt;p&gt;Every app runs in its own sandbox environment i.e its own process. Every process is allotted some amount of RAM from the existing available RAM by the OS.&lt;/p&gt;

&lt;p&gt;Nowadays, Android is becoming more and more battery-friendly and it's doing that, partly, by aggressively killing background apps that are not in the foreground after a relatively small amount of time. This, of course, depends on various other factors happening on the device like available RAM, etc. Check out this &lt;a href="https://dontkillmyapp.com/"&gt;site&lt;/a&gt; for more information about how different manufacturers deal with background apps restrictions.&lt;/p&gt;

&lt;p&gt;So it's the developer's responsibility to test his/her app for such scenarios for optimal user experience. &lt;/p&gt;

&lt;h2&gt;
  
  
  How to simulate a process kill 😉?
&lt;/h2&gt;

&lt;p&gt;Now that we have established the reason to test these edge cases, its time to simulate a process kill scenario.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cAYrn_UE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://giphygifs.s3.amazonaws.com/media/8oPkn7Hl79J6g/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cAYrn_UE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://giphygifs.s3.amazonaws.com/media/8oPkn7Hl79J6g/giphy.gif" alt="Harvey"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Naive way
&lt;/h3&gt;

&lt;p&gt;The camera app on your phone is resource-intensive and requires a lot of RAM to run. Once you start the app, this results in the systematic killing of your background apps almost instantly. Mind well this might not be true for every scenario. Only opt for this approach if you are lazy 😁.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Nerdy way 😎
&lt;/h3&gt;

&lt;p&gt;Let's get our hands dirty and run some terminal commands. Assuming an Android emulator is available and you have the sample project running with applicationId &lt;strong&gt;com.processkill.example&lt;/strong&gt;, go to terminal and type this command (these commands have been tested on Android emulator running P)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;adb shell pidof com.processkill.example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should output the ProcessID in which the app is running. Now go ahead and minimize the app by pressing the HOME button. This is needed to be done as Android would not kill a user-focused activity/app/process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;adb shell am kill com.processkill.example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By running this command we have in principle simulated a process kill scenario. If you run the earlier command again you should see an empty string being printed on console meaning the process has been actually terminated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Time for retrospective
&lt;/h3&gt;

&lt;p&gt;Go ahead and test your app by running the above commands and see how it behaves in different scenarios.&lt;br&gt;
If you have a well-crafted app and it works well in the above scenario then you should be proud of yourself achieving such a feat 🍻. &lt;/p&gt;

&lt;p&gt;If you are facing some issues then read on.&lt;/p&gt;
&lt;h3&gt;
  
  
  Who's the culprit? And I don't mean it's you 😂
&lt;/h3&gt;

&lt;p&gt;There could be a number of reasons for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maybe the way you have implemented the app architecture without giving 
careful thought about the state of the app in such scenarios.&lt;/li&gt;
&lt;li&gt;You were short on time, which is mostly the case, in fast pace driven development.&lt;/li&gt;
&lt;li&gt;Android itself 😏&lt;/li&gt;
&lt;li&gt;Add your own reason 😁&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;The issue/feature about &lt;strong&gt;Android&lt;/strong&gt; is that it will automagically re-create the last Activity and also re-attach the Fragments, if any, from your Task Stack if the user resumes the app after it has been killed by OS. This is different from &lt;strong&gt;iOS&lt;/strong&gt; behaviour wherein the OS doesn't restore the last ViewController automatically.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Though the intention from Android seem correct resulting in better UX, it throws a challenge for us, developers, to handle these scenarios and think of it while designing apps.&lt;/p&gt;

&lt;p&gt;Let's see what we can do here and strike a balance between UX and state of the app.&lt;/p&gt;
&lt;h3&gt;
  
  
  But first, repeat after me:
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Static and/or member variables defined in the &lt;strong&gt;Application&lt;/strong&gt; or any &lt;strong&gt;Singleton&lt;/strong&gt; class won't survive the &lt;strong&gt;process kill&lt;/strong&gt; and will reset to their default values which could be &lt;strong&gt;null&lt;/strong&gt;. Remember &lt;code&gt;NullPointerException&lt;/code&gt; 😱.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  Scenario: 1
&lt;/h4&gt;

&lt;p&gt;You don't have any caching/persistence strategy implemented for your app.&lt;/p&gt;

&lt;p&gt;In such scenarios, the easiest way out would be to start from a clean slate. Here is the code that can potentially go inside the BaseActivity class.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developer Warning&lt;/strong&gt;⚠️  Use this solution only as a last resort.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&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="n"&gt;savedInstanceState&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;currentProcessId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;myPid&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&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="n"&gt;currentProcessId&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PID_KEY&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;intent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;applicationContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SplashActivity&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FLAG_ACTIVITY_NEW_TASK&lt;/span&gt; &lt;span class="n"&gt;or&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FLAG_ACTIVITY_CLEAR_TASK&lt;/span&gt;
                &lt;span class="nf"&gt;startActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;finish&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;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onSaveInstanceState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onSaveInstanceState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;outState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;putString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PID_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;myPid&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&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;What this piece of code is doing is that if we detect our app has been recreated because of the process kill then we re-direct the app to the launcher activity which in this case is the SplashActvity.&lt;/p&gt;

&lt;p&gt;At first, you would be tempted to use this solution in every app you have built. But this would be bad for UX as the user expects to start off from where he/she left your application.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scenario: 2
&lt;/h4&gt;

&lt;p&gt;Let's try to put everything in &lt;code&gt;Bundle&lt;/code&gt; -&amp;gt; objects that are intended to be used across process boundaries such as with IPC/Binder transactions, between activities with intents, and to store transient state across configuration changes. &lt;/p&gt;

&lt;p&gt;Please refer to &lt;a href="https://github.com/nikhil-thakkar/process-kill-example"&gt;this&lt;/a&gt; github repo for a sample project. Checkout the master branch for the project if you want to follow along.&lt;br&gt;
The code is very simple to understand and is pretty much a boilerplate with classical MVC 😋.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I'm using sample json files packed inside &lt;code&gt;assets&lt;/code&gt; folder to keep things simple and readable.&lt;br&gt;
The json file holds some randomly generated data to be consumed by the app. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The main components of the app are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DataProvider&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a simple interface to abstract the source from where the data is coming from. In our case it's a file read from &lt;code&gt;assets&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MainFragment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Listing page of all the users.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DetailFragment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Detail page about a particular user.&lt;/p&gt;

&lt;p&gt;Now if you place around with the app, it should work fine in every scenario including process death. Do verify it by running the terminal commands to simulate a process death scenario we discussed above.&lt;/p&gt;

&lt;p&gt;Now follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checkout branch &lt;strong&gt;scenario-2&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Run the app&lt;/li&gt;
&lt;li&gt;Minimize it&lt;/li&gt;
&lt;li&gt;Look at logcat for some suprises 💩
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;2019-11-13 21:40:10.542 24962-24962/com.processkill.example E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.processkill.example, PID: 24962
    java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 1253524 bytes
        at android.app.servertransaction.PendingTransactionActions&lt;span class="nv"&gt;$StopInfo&lt;/span&gt;.run&lt;span class="o"&gt;(&lt;/span&gt;PendingTransactionActions.java:161&lt;span class="o"&gt;)&lt;/span&gt;
        at android.os.Handler.handleCallback&lt;span class="o"&gt;(&lt;/span&gt;Handler.java:883&lt;span class="o"&gt;)&lt;/span&gt;
        at android.os.Handler.dispatchMessage&lt;span class="o"&gt;(&lt;/span&gt;Handler.java:100&lt;span class="o"&gt;)&lt;/span&gt;
        at android.os.Looper.loop&lt;span class="o"&gt;(&lt;/span&gt;Looper.java:214&lt;span class="o"&gt;)&lt;/span&gt;
        at android.app.ActivityThread.main&lt;span class="o"&gt;(&lt;/span&gt;ActivityThread.java:7319&lt;span class="o"&gt;)&lt;/span&gt;
        at java.lang.reflect.Method.invoke&lt;span class="o"&gt;(&lt;/span&gt;Native Method&lt;span class="o"&gt;)&lt;/span&gt;
        at com.android.internal.os.RuntimeInit&lt;span class="nv"&gt;$MethodAndArgsCaller&lt;/span&gt;.run&lt;span class="o"&gt;(&lt;/span&gt;RuntimeInit.java:492&lt;span class="o"&gt;)&lt;/span&gt;
        at com.android.internal.os.ZygoteInit.main&lt;span class="o"&gt;(&lt;/span&gt;ZygoteInit.java:934&lt;span class="o"&gt;)&lt;/span&gt;
     Caused by: android.os.TransactionTooLargeException: data parcel size 1253524 bytes
        at android.os.BinderProxy.transactNative&lt;span class="o"&gt;(&lt;/span&gt;Native Method&lt;span class="o"&gt;)&lt;/span&gt;
        at android.os.BinderProxy.transact&lt;span class="o"&gt;(&lt;/span&gt;BinderProxy.java:510&lt;span class="o"&gt;)&lt;/span&gt;
        at android.app.IActivityTaskManager&lt;span class="nv"&gt;$Stub$Proxy&lt;/span&gt;.activityStopped&lt;span class="o"&gt;(&lt;/span&gt;IActivityTaskManager.java:4500&lt;span class="o"&gt;)&lt;/span&gt;
        at android.app.servertransaction.PendingTransactionActions&lt;span class="nv"&gt;$StopInfo&lt;/span&gt;.run&lt;span class="o"&gt;(&lt;/span&gt;PendingTransactionActions.java:145&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is because when we communicate across different process boundaries there is limit on the data we can share with the other process wiz. &lt;strong&gt;1MB&lt;/strong&gt;. In our case it's a bit over 1MB and hence the exception, &lt;code&gt;TransactionTooLargeException&lt;/code&gt;, which results in process being killed when in background.&lt;/p&gt;

&lt;p&gt;Therefore always carefully examine what you are going to put in &lt;code&gt;Bundle&lt;/code&gt; and size implications.&lt;br&gt;
Save the smallest amount of data possible which could be one of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;primary column id when reading from database or &lt;/li&gt;
&lt;li&gt;file path when reading from disk or &lt;/li&gt;
&lt;li&gt;some other souce from where you can reliably re-create app state somehow or&lt;/li&gt;
&lt;li&gt;try try try or&lt;/li&gt;
&lt;li&gt;fallback to &lt;strong&gt;Scenario: 1&lt;/strong&gt; 💯 &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Side note on Flutter
&lt;/h3&gt;

&lt;p&gt;Flutter apps run inside a single activity. These apps would, by default, start from the &lt;strong&gt;first widget&lt;/strong&gt; defined in case of &lt;code&gt;Don't keep activities/process death&lt;/code&gt; scenarios unless explicitly handled. This first widget would be the one defined by &lt;em&gt;home&lt;/em&gt; property inside &lt;strong&gt;MaterialApp&lt;/strong&gt; widget.&lt;/p&gt;

&lt;h3&gt;
  
  
  That's It for this time!
&lt;/h3&gt;

&lt;p&gt;Thank you for hanging around. Hope you learned something new 😃. Feel free to reach out on twitter - &lt;a href="https://twitter.com/_nikhi1"&gt;&lt;strong&gt;@_nikhi1&lt;/strong&gt;&lt;/a&gt; - for any questions/feedback you have.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/TW6HfTEHrAPv2/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/TW6HfTEHrAPv2/giphy.gif" alt="Harvey"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Further Reading
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/guide/components/processes-and-threads"&gt;Processes and Threads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/guide/components/activities/parcelables-and-bundles"&gt;Parcels and Bundles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/JoseAlcerreca/android-lifecycles"&gt;Android Lifecycle Cheatsheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/reference/android/os/TransactionTooLargeException"&gt;Transactions Too Large Expection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/topic/libraries/architecture/viewmodel-savedstate"&gt;Save State Module for ViewModel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pub.dev/packages/native_state"&gt;Flutter Native State Plugin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>android</category>
      <category>processkill</category>
      <category>background</category>
    </item>
  </channel>
</rss>
