<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Bala Ramdoss on Medium]]></title>
        <description><![CDATA[Stories by Bala Ramdoss on Medium]]></description>
        <link>https://medium.com/@bala.ramdoss?source=rss-b5b9b52f078d------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*lMhJcNnvOe28Cw-MnZHlDQ.jpeg</url>
            <title>Stories by Bala Ramdoss on Medium</title>
            <link>https://medium.com/@bala.ramdoss?source=rss-b5b9b52f078d------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 18 May 2026 06:36:44 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@bala.ramdoss/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Your Baby’s Data Shouldn’t Be Anyone Else’s Business]]></title>
            <link>https://medium.com/nerd-for-tech/your-babys-data-shouldn-t-be-anyone-else-s-business-db755d3e212e?source=rss-b5b9b52f078d------2</link>
            <guid isPermaLink="false">https://medium.com/p/db755d3e212e</guid>
            <category><![CDATA[ai-on-device]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[privacy]]></category>
            <dc:creator><![CDATA[Bala Ramdoss]]></dc:creator>
            <pubDate>Sat, 28 Mar 2026 23:18:01 GMT</pubDate>
            <atom:updated>2026-03-28T23:18:01.775Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LcqHediRxeajVwPW3JwUHA.jpeg" /><figcaption>All things newborn</figcaption></figure><p>I became a dad not too long ago. Like most new parents, we leaned on apps to help navigate the chaos. My partner used a nursing tracker to log feeding times, durations, which side, all that. Pretty useful honestly.</p><p>Then the ads started. Supplements to boost milk supply. Tips for “fixing” nursing schedules. Could be a coincidence. Probably not.</p><p>That got me thinking. These apps know a lot. Not just what you tell them but when, how often, the patterns. And most of us just hand that over without thinking twice because the app is helpful and we’re tired and we just want to know when the last feeding was.</p><p>I’m a developer. So I built something different. An app that knows <em>nothing</em> about you except what stays on your phone.</p><h3>AI is Everywhere, and That’s Not Free</h3><p>Almost every app you use today has some kind of AI feature. Your photos app groups faces. Your keyboard predicts your next word. Your fitness tracker tells you when to sleep. It feels like magic and honestly a lot of it is useful.</p><p>Here is what that looks like in numbers. In 2025, people downloaded AI apps <a href="https://www.dailysabah.com/business/tech/ai-app-spending-surges-past-5b-as-usage-more-than-triples-in-2025">3.8 billion times</a>. Revenue from those apps more than tripled to over $5 billion. The word “AI” now appears in over <a href="https://techcrunch.com/2025/07/30/gen-ai-apps-doubled-their-revenue-grew-to-1-7b-downloads-in-first-half-of-2025/">100,000 app descriptions</a> on the App Store and Google Play combined. It is not a trend anymore. It is the default.</p><p>But here’s the thing. Most of that AI isn’t running on your phone. It’s running on a server somewhere. Your data makes a round trip, leaves your device, gets processed, comes back as an answer. Every single time.</p><p>I work on AI for a living. I’m one of the engineers behind <a href="https://www.amazon.com/Lens/b?ie=UTF8&amp;node=206517768011">Amazon Lens AI</a>. I understand why this is the default. The infrastructure is there, the models are powerful and it works. It makes sense for a lot of use cases.</p><p>But it also means your data is traveling. And depending on what that data is, that’s worth pausing on. It has never been cheaper to store, process and make sense of large amounts of personal information. Most companies have good intentions. But intentions and incentives don’t always point in the same direction.</p><h3>What Does “Private” Actually Mean?</h3><p>When I tell people I built an app that is truly private, the first question is usually “<em>what do you mean by private?</em>”</p><p>Fair question. Privacy gets thrown around a lot. Every app has a privacy policy. Every company says they take your data seriously. But that’s not what I mean.</p><p>I mean the information never leaves your phone. There is no server receiving it. No company storing it. No policy to read or trust. The AI that processes your voice lives on your device and stays there.</p><p>Think of it like writing something on a piece of paper. Only you can read it. You decide what happens to it. You could share it, store it, throw it away. That’s your call entirely. The app is just the pen.</p><p>That’s the standard I built to. Not “<em>we handle your data responsibly</em>.” Your data simply doesn’t go anywhere.</p><h3>The App</h3><p>The app started as a simple idea. New parents are exhausted. Logging a diaper change at 3 AM should not feel like filling out a form.</p><p>So I built a voice logger. You just talk to it.</p><ul><li><em>“Poop diaper with a blowout.”</em></li><li><em>“3 oz formula an hour ago.”</em></li><li><em>“Two hours of sleep.”</em></li></ul><p>It understands you and logs it. That’s it.</p><p>The AI that does this, Google Gemini Nano, lives entirely on the device. No internet connection needed. You could turn on airplane mode, open the app and it still works. Your baby’s data never leaves your phone. Not even once.</p><p>And when you want to do something with that data, like spot patterns or track trends, the app lets you export it as a CSV file. Open it in whatever spreadsheet tool you like and dig in yourself. The app doesn’t tell you what your data means. It gives you your data and gets out of the way.</p><p>Oh and there’s a Wear OS extension too. That one was a game changer for me personally. Middle of the night, hands full, I could just talk to my watch and log it. No fumbling for the phone. The AI still runs on the phone, the watch is just the input, but the two talking to each other worked better than I expected. Honestly one of the more fun things I’ve built in a while.</p><p>I think that’s how it should work.</p><h3>The Honest Part</h3><p>I want to be upfront about a few things.</p><p>Right now the app only works on Pixel 9 and newer devices. That’s just where on-device AI is today. The hardware needs to be powerful enough to run the model locally. It’s a real limitation and I’m not going to pretend otherwise. I’m working on supporting more devices using open weight models, but that’s still ahead.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*gPQyk6X-9-hwFm66.jpeg" /></figure><p>The app can also make mistakes. You say “<em>poop diaper</em>” and it might log it as a wet diaper. Not a big deal, there’s an edit option. But it’s a good reminder that AI is not perfect and apps have a responsibility to handle that gracefully, especially when the data is personal.</p><p>I actually built a feature where you could ask the AI questions about your logs. “<em>When was the last feeding?</em>” Things like that. I ended up pulling it out. The guardrails needed to make it safe and reliable were more than the feature was worth at this stage. That was a deliberate call.</p><p>I also had to go through Google Play’s compliance process even though the app has no internet access at all. I was fine with that. App stores pushing for accountability on AI features is a good thing. Builders should have to think carefully about what they ship.</p><h3>The Edge is Moving</h3><p>A year ago this app couldn’t have existed. The models weren’t small enough to run on a phone. The hardware wasn’t ready. On-device AI was mostly a research conversation.</p><p>That’s changing fast. The gap between what you can do in the cloud and what you can do on a device is closing. And as that gap closes, the excuse that “<em>we need your data on our servers to make this work</em>” gets weaker.</p><p>I’m planning to open source this app. Not because I think it’s perfect but because I think the conversation it starts is worth having. If you’re a developer and you’re building something that touches personal data, I hope this is useful. You don’t always have to choose between powerful AI and respecting your users.</p><p>And if you’re not a developer, I hope this at least makes you ask the question next time an app wants access to something personal. Not out of fear. Just with a little more awareness.</p><p>The technology to do this right exists. More people just need to choose to use it.</p><h3>Questions to Ask of Every App</h3><p>You don’t need to be a developer to think about this stuff. Next time you download an app that wants to know something personal, just ask a few things.</p><ul><li>What’s the worst case if this AI gets something wrong? A misread diaper log is harmless. An AI making assumptions about your health, your mood, your relationships is a different thing entirely.</li><li>Does the app give you your data or does it just use it? Can you export it, delete it, take it somewhere else? Or does it live in the app and only in the app?</li><li>Who benefits from what you’re sharing? Sometimes the answer is clearly you. Sometimes it’s less clear. That’s worth knowing.</li></ul><p>You don’t have to be paranoid. Most apps are fine. But the ones that touch the most personal parts of your life deserve a little more scrutiny. Especially now when AI makes it easier than ever to do a lot with a little bit of information.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=db755d3e212e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/nerd-for-tech/your-babys-data-shouldn-t-be-anyone-else-s-business-db755d3e212e">Your Baby’s Data Shouldn’t Be Anyone Else’s Business</a> was originally published in <a href="https://medium.com/nerd-for-tech">Nerd For Tech</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[When Picasso fails you]]></title>
            <link>https://medium.com/@bala.ramdoss/when-picasso-fails-you-892bc78c69db?source=rss-b5b9b52f078d------2</link>
            <guid isPermaLink="false">https://medium.com/p/892bc78c69db</guid>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[image-renderer]]></category>
            <category><![CDATA[picasso]]></category>
            <dc:creator><![CDATA[Bala Ramdoss]]></dc:creator>
            <pubDate>Fri, 13 Jan 2023 05:07:20 GMT</pubDate>
            <atom:updated>2023-01-13T05:07:20.996Z</atom:updated>
            <content:encoded><![CDATA[<p>Picasso is a very popular Image loading library for Android. It has been serving Android community for years.</p><p>The following situation happened to me because I had to use an older version of Picasso-2.5.0. I know, it is way too old. This issue does not exist in the newer version of Picasso(2.8+). But, if you happen to encounter this issue and are looking for an answer, please continue reading.</p><p>I encountered an image rendering problem in our production app where some of the images that are rendered by Picasso are rotated counter-clockwise.</p><p>While debugging, I found that the Uri that system gives after a user selects an image, differs based on how the user shares the image to the app 🤯</p><p>When using a photo picker from an OS 9 Samsung device, the Uri looks like this:</p><p>content://com.android.externalstorage.documents/document/primary%3ADCIM%2FCamera%2F20221102_1111610.jpg</p><p>When sharing the same photo from the camera app, it looks like:</p><p>content://media/external/images/media/335</p><p>When sharing the same photo via Google Photos, it will look like:</p><p>content://com.google.android.apps.photos.conentprovider/-1/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F355/REQUIRE_ORIGINAL/NONE/image%2Fjpeg/1763556495</p><p>The RequestHandler implementation inside Picasso handles these differently. Anything that doesn’t have media in the path will be handled by ContentStreamRequestHandler which does not look for the EXIF orientation tag.</p><p>To solve this, I introduced a new implementation for handling all Uris that has content:// scheme and attached it to the list of request handlers of the Picasso instance.</p><pre>class LocalImageHandler(val context: Context) : RequestHandler() {<br><br>    override fun canHandleRequest(data: Request): Boolean {<br>        return data.uri.scheme== &quot;content&quot;<br>    }<br><br>    override fun load(request: Request, networkPolicy: Int): Result? {<br>        val contentResolver = context.contentResolver<br><br>        val imageInputStream = contentResolver.openInputStream(request.uri) <br>                            ?: return null<br><br>        val originalBitmap = BitmapFactory.decodeStream(imageInputStream)<br>                            ?: return null<br><br>        // use androidx EXIF interface library to read the EXIF TAG_ORIENTATION tag<br>        val exifOrientation = getExifOrientation(request.uri, context)<br><br>        if (exifOrientation ==ORIENTATION_UNDEFINED) {<br>            return Result(originalBitmap, Picasso.LoadedFrom.DISK)<br>        }<br><br>        // refer to utils from Picasso<br>        // https://github.com/square/picasso/blob/00bc2a4bdc4f18e1b2462c8b909987be73b4fca3/picasso/src/main/java/com/squareup/picasso3/MatrixTransformation.kt#L213<br>        val rotation = getExifRotationDegrees(exifOrientation)<br>        val translation = getExifTranslation(exifOrientation)<br><br>        val exifMatrix = Matrix()<br><br>        if (rotation != 0f) {<br>            exifMatrix.preRotate(rotation)<br>        }<br><br>        if (translation != 1f) {<br>            exifMatrix.postScale(translation, 1f)<br>        }<br><br>        val newBitmap = Bitmap.createBitmap(originalBitmap,<br>                0,<br>                0,<br>                originalBitmap.width,<br>                originalBitmap.height,<br>                exifMatrix,<br>                false)<br>        if (newBitmap != originalBitmap) {<br>            originalBitmap.recycle()<br><br>        }<br><br>        return Result(newBitmap, Picasso.LoadedFrom.DISK)<br><br>    }</pre><pre>val picassoInstance = new Picasso.Builder(context)<br>			.addRequestHandler(LocalImageRequestHandler(context))<br>			.build()</pre><p>This problem is fixed in the latest version of Picasso. If you are like me, and are stuck with an older version of Picasso, this can come in handy.</p><p>Comment below if you have incurred any such issues! I would love to know.</p><p>In another post, I’ll write about how I shared the image cache between react native and native Android image rendering.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=892bc78c69db" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[iOS Simulator? or Android Emulator? or Both?]]></title>
            <link>https://medium.com/@bala.ramdoss/ios-simulator-or-android-emulator-or-both-b597815dddbd?source=rss-b5b9b52f078d------2</link>
            <guid isPermaLink="false">https://medium.com/p/b597815dddbd</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[emulator]]></category>
            <dc:creator><![CDATA[Bala Ramdoss]]></dc:creator>
            <pubDate>Sat, 15 Aug 2020 21:16:20 GMT</pubDate>
            <atom:updated>2020-08-15T21:16:52.192Z</atom:updated>
            <content:encoded><![CDATA[<p>From the outside looking in, an optimistic, rookie React Native dev says,</p><blockquote><em>Write code once, use it twice</em></blockquote><p>React Native is awesome. Businesses drool over the concept of “write once and use it twice” as it drastically reduces the cost and improves productivity.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/0*-zKFf1yUcsyIVfL6.gif" /></figure><p>When building a brand new app, developers often prefer to run the server locally. This comes handy as building new features in mobile app that also requires server changes. Hence, in most cases, the dev app points to ports in localhost. This works great for iOS since the simulator&#39;s localhost is the same as the machine&#39;s localhost. However, this doesn&#39;t work for Android Emulator. We have to modify the host to the machine&#39;s IP address to make this work.</p><p>Here comes ADB to the rescue…</p><pre>$ adb reverse tcp:8000 tcp:8000</pre><p>This enables a reverse proxy between a virtual server in the emulator port 8000 and wires it to the host machine’s port 8000. Now we can run / <a href="https://facebook.github.io/react-native/docs/debugging#automatic-reloading">live reload</a> our mobile app on both platforms without any additional effort. Keep in mind that the reverse proxy will be void if the emulator restarts.</p><h3>More resources on cross platform development</h3><ul><li><a href="https://www.donnfelker.com/flutter-just-might-work/">Donn Felker’s post — Flutter just might work</a></li></ul><p>Gif credits : <a href="https://giphy.com">giphy.com</a></p><p><em>Originally published at </em><a href="https://srbkrishnan.dev/blog/2019/06/23/adb-reverse/"><em>https://srbkrishnan.dev</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b597815dddbd" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Few Javascript Gotchas]]></title>
            <link>https://medium.com/@bala.ramdoss/a-few-javascript-gotchas-37f7c72c2c14?source=rss-b5b9b52f078d------2</link>
            <guid isPermaLink="false">https://medium.com/p/37f7c72c2c14</guid>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Bala Ramdoss]]></dc:creator>
            <pubDate>Sat, 15 Aug 2020 20:59:54 GMT</pubDate>
            <atom:updated>2020-08-15T20:59:54.371Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5nvvoF-U3zTbmhb0pVOhxg.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@markusspiske?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Markus Spiske</a> on <a href="https://unsplash.com/s/photos/javascript?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><h3>Hello there!</h3><p>It has been a while since I wrote my last post. I recently started looking into react native development to see why people love it so much. The last time I coded in javascript, it was in 2014. So the things that I am going to share here are from a JS newbie perspective.</p><p>First and foremost, I now don’t hate javascript. Credits to ES6/ES2015+ and React. All the destructuring and spreading were confusing at first; however, they make a lot of sense now.</p><p>I am going to discuss one minor JS gotcha here and I will continue sharing what I learn in future posts.</p><h3>Javascript class methods</h3><p>Classes in JS are new to me, so I went on to <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes">MDN</a> see what classes look like.</p><p>Let’s create a class:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5f49005edd37262ffe2e4905b640072d/href">https://medium.com/media/5f49005edd37262ffe2e4905b640072d/href</a></iframe><p>In your component,</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5d63b4ad4e07b12cea5d5eafc1948e28/href">https://medium.com/media/5d63b4ad4e07b12cea5d5eafc1948e28/href</a></iframe><p>Now when we run the app and press the view, it logs brewing... DarkRoast in the console, which is expected.</p><p>Let’s look at a slightly different example where we pass in coffeeBrewer to the component using props and destructure the brew method:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8e70c30bd8a1d46f570fe55a8a52dc19/href">https://medium.com/media/8e70c30bd8a1d46f570fe55a8a52dc19/href</a></iframe><p>We’d expect it to log brewing... DarkRoast in the debug console. However, it logs brewing...undefined. Coming from a Java and Kotlin background, this was surprising.</p><p>To find out more, let print this instead of this.beanName in brew(),</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/919/0*8HJVrUg-bwv2XMot.png" /></figure><p>After talking to my fellow JS experts, I understood why this is happening. This is because brew() didn&#39;t run in the CoffeeBrewer&#39;s context. The function brew doesn&#39;t belong to the &quot;class&quot; until you &quot;bind&quot; it.</p><p><strong>GOTCHA…</strong></p><p>Here’s how you do it</p><pre>constructor(name) {<br>   this.beanName = name; <br>   this.brew = this.brew.bind(this);<br>}</pre><p>This will result in the debug console as</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/808/0*RZYjBB8KHJadGiNy.png" /></figure><p>We can also use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">arrow functions</a> in classes to get this “binding” without doing this.brew.bind(this);</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8e6dae41978d1f470c83c392ff872e5a/href">https://medium.com/media/8e6dae41978d1f470c83c392ff872e5a/href</a></iframe><p>Looks like this is a very common problem in Javascript and yet I stumbled on it despite following the standard docs.</p><p>Above examples are ran with the environment :</p><pre>&quot;dependencies&quot;: {</pre><pre>&quot;react&quot;: &quot;16.8.3&quot;,</pre><pre>&quot;react-native&quot;: &quot;0.59.9&quot;</pre><pre>},</pre><pre>&quot;devDependencies&quot;: {</pre><pre>&quot;@babel/core&quot;: &quot;7.4.5&quot;,</pre><pre>&quot;@babel/runtime&quot;: &quot;7.4.5&quot;,</pre><pre>&quot;babel-jest&quot;: &quot;24.8.0&quot;,</pre><pre>&quot;jest&quot;: &quot;24.8.0&quot;,</pre><pre>&quot;metro-react-native-babel-preset&quot;: &quot;^0.54.1&quot;,</pre><pre>&quot;react-test-renderer&quot;: &quot;16.8.3&quot;</pre><pre>}</pre><p>Of course there are many and even better ways to do this. Which one do you think is best? DM me <a href="https://www.twitter.com/srbkrishnan">@srbkrishnan</a></p><h3>Resources on ES6 classes:</h3><ul><li><a href="https://medium.com/@parsyval/javascript-prototype-vs-class-a7015d5473b">Classes vs Prototypes</a></li><li><a href="https://medium.com/@charpeni/arrow-functions-in-class-properties-might-not-be-as-great-as-we-think-3b3551c440b1">Arrow functions and functions in classes</a></li></ul><p><em>Originally published at </em><a href="https://srbkrishnan.dev/blog/2019/06/23/javascript-gotchas/"><em>https://srbkrishnan.dev</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=37f7c72c2c14" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Infinite scroll / pagination in Flatlist with hooks and function Components]]></title>
            <link>https://medium.com/@bala.ramdoss/infinite-scroll-pagination-in-flatlist-with-hooks-and-function-components-c9c08bba23a8?source=rss-b5b9b52f078d------2</link>
            <guid isPermaLink="false">https://medium.com/p/c9c08bba23a8</guid>
            <category><![CDATA[hooks]]></category>
            <category><![CDATA[pagination]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[infinite-scroll]]></category>
            <dc:creator><![CDATA[Bala Ramdoss]]></dc:creator>
            <pubDate>Sun, 12 Jul 2020 20:25:02 GMT</pubDate>
            <atom:updated>2020-07-13T15:19:51.251Z</atom:updated>
            <content:encoded><![CDATA[<h3>Infinite scroll/Paginating Flatlist with <em>just</em> hooks and function components</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kpd-RrXqcgV6SslxdYfOnA.jpeg" /><figcaption>I ♥️ dogs. Photo by <a href="https://unsplash.com/@lovedbyleighphoto?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Marissa Deck</a> on <a href="https://unsplash.com/images/animals/dog?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>I’ve come across many infinite-scroll examples for React Native <a href="https://reactnative.dev/docs/flatlist">Flatlist</a> with class components. I think function components are the future of react- Why? You may ask. Recently, I’ve been working on React Native projects and have been using function components and custom hooks a lot more than class components. They read better, use less boilerplate code and are easy to test. You can read more about function components <a href="https://reactjs.org/docs/components-and-props.html">here</a> and <a href="https://overreacted.io/how-are-function-components-different-from-classes/">here</a> or if you’d like to watch, I’d recommend watching <a href="https://www.youtube.com/watch?v=dpw9EHDh2bM">this</a>.</p><p>Let’s jump into an example.</p><p>We will be building an infinite scroll feed using just function components and hooks that shows dog pictures, because I just love these cute creatures :)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/578/1*54-fNq849ZKsu7r4gNvOyw.gif" /></figure><p>Let’s start with the Unsplash API setup. Follow their <a href="https://unsplash.com/documentation">developer doc</a> to get an API key to fetch photos. Unsplash API supports pagination and have a ton of photos which makes it suitable for our example.</p><p>Create an async function that takes in keyword, pageNumber, limit as parameters and returns array of photos.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/604f8885b83f494cde3dd07d3ae4d7e0/href">https://medium.com/media/604f8885b83f494cde3dd07d3ae4d7e0/href</a></iframe><p>Now let’s create a custom hook using state and effect hooks to provide data to our Flatlist.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d51bb709ca3bbffc5bbed2b2690037bc/href">https://medium.com/media/d51bb709ca3bbffc5bbed2b2690037bc/href</a></iframe><p>This custom hook relies on the effect hook to call whenever any of page, shouldFetch changes. We use a callback fetchMore to set shouldFetch to true. Note that the shouldFetch has a default value of true. This triggers the initial effect call to fetch the first page automatically.</p><p>Also observe the order of setting the states :</p><ol><li>Set shouldFetch to false</li><li>Update remaining states setPhotos, setPage</li></ol><p>This prevents the effect hook from automatically fetching the next page as we update the page state.</p><p>Let’s use this custom hook to display dog images using aFlatlist.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6d4f84c40d2bb12542590fd59eff507e/href">https://medium.com/media/6d4f84c40d2bb12542590fd59eff507e/href</a></iframe><p>Observe how the photos and fetchMore are used. This will result in an endless feed of dog photos :)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/578/1*54-fNq849ZKsu7r4gNvOyw.gif" /></figure><p>Because hooks are essentially a function, we can mock it out in our tests.</p><p>This post covered how to do infinite scrolling in flatlist using function components and hooks. We did not cover error handling and loading state. I will write a separate post to cover loading and error states.</p><p>Please leave a comment if you think there are better ways to do pagination using hooks in function components.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c9c08bba23a8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Easiest BulletProof Coffee]]></title>
            <link>https://medium.com/@bala.ramdoss/easiest-bulletproof-coffee-b8977d47be6f?source=rss-b5b9b52f078d------2</link>
            <guid isPermaLink="false">https://medium.com/p/b8977d47be6f</guid>
            <category><![CDATA[bulletproof-coffee]]></category>
            <category><![CDATA[coffee]]></category>
            <category><![CDATA[ketogenic-diet]]></category>
            <category><![CDATA[keto]]></category>
            <dc:creator><![CDATA[Bala Ramdoss]]></dc:creator>
            <pubDate>Mon, 06 Apr 2020 00:23:11 GMT</pubDate>
            <atom:updated>2020-04-06T01:25:03.294Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rdJE0thYpMbymf4uYCpUrQ.png" /><figcaption>At one of my favorite coffee roasters’</figcaption></figure><p>Hey, there fellow coffee-nerd!</p><p>This post is NOT about how to make BulletProof coffee, but it is about how to make it with the least effort. Yes, including the cleaning part, which takes the most time in the whole process.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QHWv6yLxp2x-olI4mso-aA.jpeg" /><figcaption>My simple Bulletproof coffee brewing setup</figcaption></figure><p>Brew your favorite hot coffee by any method. If you are looking for the least effort, use a pour over. Instead of brewing into a cup, I brewed into a 32 oz wide mouth mason jar. The jar gives enough space for the hand-blender to blend your coffee with butter.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UsMXWQ6Cv2w_bVe02r-m-Q.jpeg" /></figure><p>Add butter to the jar before brewing the coffee, this helps the butter to melt before you blend. If you prefer adding collagen protein with your BulletProof coffee, add it before you blend to prevent any lumps. While any unsalted butter gets the job done, I use Kerrygold grass-fed butter. It tastes a lot better than others :) After you finish brewing, remove the pour-over and wash it right away.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*quciZsD_-ARGYL2Sh9iW2A.png" /></figure><p>Most hand-blenders work well for BulletProof coffee. The blender has to run in hi-speed settings to make the coffee forthy and creamy. If you prefer less frothy, run it in low speed settings. Also make sure the blender splits into 2 parts so that it is easy to clean.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*29rdwC7nx-0SJLwYjad-6Q.png" /></figure><p>Once you are done, remove the blending stick and clean it right away. If it gets dried, it needs more effort to clean!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fF0_wk_yRKEVvNbCmHB-_Q.jpeg" /></figure><p>Now you can enjoy the Bulletproof coffee directly from the jar. I like this 32 oz jar because it can make coffee for 2.</p><p>Below are the things in the picture if you like to try out the exact setup. Post on the comments below if there are any other hacks I could use!</p><p>Cuisinart variable speed hand blender, <a href="https://shop.bulletproof.com/collections/coffee/products/coffee-the-original-ground-12oz">BulletProof® The Original Coffee</a>, <a href="https://www.vitalproteins.com/products/collagen-peptides?view=pdp-2020&amp;variant=43393712134&amp;utm_medium=cpc&amp;utm_source=google&amp;utm_campaign=Google%20Shopping&amp;utm_source=google&amp;utm_medium=cpc&amp;utm_campaign=us_core_20190823_collagen-peptides-google-shopping_collagen-peptide-searchers_all_3&amp;utm_term=conversion&amp;utm_content=smart-shopping&amp;device=c&amp;keyword=&amp;matchtype=&amp;adposition=&amp;gclid=EAIaIQobChMI27m1tcLS6AIVEtNkCh2L2AIyEAQYASABEgLebvD_BwE">Vital Proteins — Plain</a>, <a href="https://www.amazon.com/Ball-Mason-Mouth-Bands-Jars/dp/B07HGG3DD1/ref=sr_1_1?crid=34UH2VN38EVVK&amp;dchild=1&amp;keywords=ball+32+oz+mason+jars+wide+mouth&amp;qid=1586132176&amp;s=home-garden&amp;sprefix=ball+32+%2Cgarden%2C202&amp;sr=1-1">Ball 32 oz wide mouth jars</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b8977d47be6f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Jetify my React Native App — Pro Tip]]></title>
            <link>https://medium.com/@bala.ramdoss/jetify-my-react-native-app-pro-tip-a3f5243ae297?source=rss-b5b9b52f078d------2</link>
            <guid isPermaLink="false">https://medium.com/p/a3f5243ae297</guid>
            <category><![CDATA[android]]></category>
            <category><![CDATA[androidx]]></category>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[android-app-development]]></category>
            <dc:creator><![CDATA[Bala Ramdoss]]></dc:creator>
            <pubDate>Fri, 29 Nov 2019 02:01:01 GMT</pubDate>
            <atom:updated>2019-12-01T20:21:52.664Z</atom:updated>
            <content:encoded><![CDATA[<h3><strong>Jetify my React Native App</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*q08ovx7tuKXc8h8sJOoKPg.jpeg" /><figcaption>Photo by <a href="https://www.freeimages.com/photographer/lflank-56818">lenny flank</a> from <a href="https://freeimages.com/">FreeImages</a></figcaption></figure><p>React Native migrated to AndroidX since 0.60. This means if your app or one of your RN dependencies is using any of the Android legacy support libraries, you won’t be able to make it work successfully. Android studio has some tools to migrate your native code to AndroidX. Follow these instructions to get your native apps/libraries migrated to AndroidX 👉 <a href="https://developer.android.com/jetpack/androidx/migrate">https://developer.android.com/jetpack/androidx/migrate</a></p><p>Note that the jetifier offers migration only for binaries your app depends on, and the tools offered by Android studio offers migration for your source code to AndroidX.</p><p>But what about the native modules you install through NPM? These modules are part of the source of our React Native app. We cannot be using Android studio to migrate the app every time we do npm install. <br> <br> How do we migrate the React Native libraries to AndroidX without using Android Studio? <br> <br> Most of the React Native developers don’t use Android Studio for coding, let alone migrating the source to AndroidX. React Native community offers this nice little <a href="https://www.npmjs.com/package/jetifier">cli tool</a> based on <a href="https://blog.danlew.net/2018/11/14/the-reality-of-migrating-to-androidx/">Dan Lew’s script</a> to migrate all our source code to AndroidX including the native dependencies we install using NPM.</p><p>If you are using RN 0.61+, this jetify tool is automatically used before all react-native run-android and there is pretty much nothing we need to do to get your app working.</p><p>But, what is the catch?</p><p>What if you have a brown field app? Do you have an app that is partially React Native? Do you use Android Studio to run/debug/profile your app? <br> <br> Here is a Pro tip. <br> <br> Migrating our source code is just a one time setup and pretty much straight forward. It is just the React Native libraries installed through npm we need to take care of. These Native modules are pretty much untouched after getting installed. So the best way to migrate them to AndroidX is to jetify right after installing these native modules.</p><p>You probably got an idea where I am getting at,<br> <br>npm-post-install is your friend. Just add a post-install script to jetify your native modules and we’re good to go. The app should build whether we use react-native run-android or ./gradlew installDebug.</p><p><strong>Bonus</strong>: This also works if you have a CI-CD pipeline setup to make release builds.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a3f5243ae297" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[React Native Auto Linking on Android]]></title>
            <link>https://medium.com/@bala.ramdoss/react-native-auto-linking-on-android-65a850bb9ed9?source=rss-b5b9b52f078d------2</link>
            <guid isPermaLink="false">https://medium.com/p/65a850bb9ed9</guid>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[react-native]]></category>
            <dc:creator><![CDATA[Bala Ramdoss]]></dc:creator>
            <pubDate>Sat, 23 Nov 2019 07:37:51 GMT</pubDate>
            <atom:updated>2019-11-28T22:35:30.918Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IoDbw3NK5_7Ys-032ilQaA.jpeg" /><figcaption>Photo by Armin Hanisch from <a href="https://freeimages.com/">FreeImages</a></figcaption></figure><p>If you are a mobile developer and haven’t tried React Native, you probably should. React Native makes it so much easy to build simple, beautiful apps with almost just Javascript. It also allows developers to write native code for each platform (iOS, Android, Windows and more) and use it via Javascript. These are called Native modules. There are plenty of libraries out there that helps you use some of the key device features such as Bluetooth, Wifi, camera that uses native code and expose interfaces to Javascript via NativeModules fromReactNative module.</p><p>Here are some of the popular react-native libraries that are also comes with platform specific native modules</p><ul><li><a href="https://github.com/invertase/react-native-firebase">react-native-firebase</a></li><li><a href="https://github.com/innoveit/react-native-ble-manager">react-native-ble-manager</a></li><li><a href="https://github.com/facebook/react-native-fbsdk">react-native-fbsdk</a></li></ul><p>Prior to RN 0.60, to use a library that is also a native module, we need to add the dependency to package.json and also link it to our native projects so that it is included in our native builds. This can be done either using react-native link &lt;dependency name&gt; or manually if you have super powers.</p><p>In case of Android, the linking is as simple as adding the dependency project’s path to settings.gradle and adding an implementation &lt;dependency package&gt; in build.gradle and also include the package in your MainApplication.java file.</p><p>For example, if you were to add the library react-native-ble-manager to your project, you need to follow these steps:</p><p>Disclaimer : I totally stole these from their <a href="https://github.com/innoveit/react-native-ble-manager/blob/1ff4e9b0187921efced9e8b697c95e4227b0810a/README.md">README</a></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/88704df6adec42642741c995e4b71775/href">https://medium.com/media/88704df6adec42642741c995e4b71775/href</a></iframe><p>Add the lines to your MainApplication.java:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3591b165f658ce690b3cd93ebcffa666/href">https://medium.com/media/3591b165f658ce690b3cd93ebcffa666/href</a></iframe><p><strong>Note</strong>: This post concentrates on Autolinking on Android, take a look at here for how it used to be for iOS : 👉 <a href="https://facebook.github.io/react-native/docs/linking-libraries-ios">Linking iOS Libraries</a></p><p>Basically for Android, there are 2 steps involved in linking a native library to react-native projects . For each dependency,</p><ol><li>Include the dependency project in settings.gradle</li><li>Include the implementation &lt;dependency project&gt; in our dependency {…} in build.gradle file.</li><li>Include the package in our Application class.</li></ol><p>As of React native 0.60+, the react-native cli was extracted out and maintained separately into the <a href="https://github.com/react-native-community/cli">react-native-community/cli</a> repo which had a major version update. This update eliminates the need for us to manually link the native libraries after adding them to package.json.</p><p><strong>Note</strong>: RN 0.60+ requires cocoapods for iOS and AndroidX for Android. I will write more about it on a separate post.</p><p>For example, if you were to add the same library react-native-ble-manager to your project with RN 0.60+, all you have to do is just add react-native-ble-manager to your package.json. This makes it so much easy to maintain and easily update our dependencies.</p><p><strong>How does this Auto-linking work for Android projects?</strong></p><p>We discussed how to link native libraries manually prior to RN 0.60. Setting up Autolinking with RN 0.60+ is very similar to the 3-step manual linking for each dependency. Below steps are just a one time setup.</p><p><strong>1. Including Project in </strong><strong>settings.gradle</strong></p><p>Instead of adding individual native libraries to our settings.gradle file, we just include one script native_modules.gradle that comes with react-native-cli 2.0+ and then invoke the function applyNativeModulesSettingsGradle(settings).</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/568ca25381b5a6144d5233e185d75d53/href">https://medium.com/media/568ca25381b5a6144d5233e185d75d53/href</a></iframe><p><strong>2. Include the implementation for each dependency we added</strong></p><p>This is similar to the previous step, we include the gradle script native_modules.gradle again and invoke the function applyNativeModulesAppBuildGradle(project) which will take care of adding implementation &lt;dependency project&gt; automatically.</p><p><strong>3. Include the package in our Application class.</strong></p><p>The native_modules.gradle generates a class called PackageList which has all the dependencies’ packages included. We just need to instantiate this class using the ApplicationContext and return it to the getPackages method of our Application class. If there are additional native modules need to be included, we can just add them to this PackageList instance.</p><p><strong>What is in the file </strong><strong>native_modules.gradle that makes this process so simple?</strong></p><p>We need to thank its Javascript counter part for that. The react-native-cli has this pretty neat CLI tool config. This tool provides us all the necessary information about the react native project including the native dependencies that should be added to our native projects (iOS, Android, etc). This is how it looks for a project that has a dependency react-native-ble-manager :</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4653ccea0c0fe63d0a158efee8fe74ea/href">https://medium.com/media/4653ccea0c0fe63d0a158efee8fe74ea/href</a></iframe><p>I removed most of the stuff in this output to keep it short. Take a closer look at the android property of dependencies.react-native-ble-manager.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/893176d01a2bb8258de2e62020e53bbe/href">https://medium.com/media/893176d01a2bb8258de2e62020e53bbe/href</a></iframe><p>The script uses this information to auto-link native libraries to our project automatically — for each dependency 🤯</p><p>Learn more about Auto-linking 👉 <a href="https://github.com/react-native-community/cli/blob/master/docs/autolinking.md">here</a></p><p>Pro Tip: When you migrate to RN 0.60+, you may need to unlink all your previously “linked” native libraries. You can do it by using npx react-native unlink &lt;dependency name&gt; . This removes the entry from your settings.gradle , build.gradle and MainApplication.java . If you have already moved your MainApplication class to Kotlin, then this unlinking <strong>will</strong> <strong>not work</strong>. You need to unlink manually, which is the reverse of manual linking.</p><p>More Reading: Migrating to RN 0.60+</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=65a850bb9ed9" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>