<?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>Forem: Waqas Younis</title>
    <description>The latest articles on Forem by Waqas Younis (@waqas334).</description>
    <link>https://forem.com/waqas334</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%2F1199305%2Ff42629bd-7fb6-4648-b41a-6d0f9d39feac.png</url>
      <title>Forem: Waqas Younis</title>
      <link>https://forem.com/waqas334</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/waqas334"/>
    <language>en</language>
    <item>
      <title>Canceling a Coroutine Simplified ❌</title>
      <dc:creator>Waqas Younis</dc:creator>
      <pubDate>Sat, 14 Sep 2024 23:45:28 +0000</pubDate>
      <link>https://forem.com/waqas334/canceling-a-coroutine-simplified-amo</link>
      <guid>https://forem.com/waqas334/canceling-a-coroutine-simplified-amo</guid>
      <description>&lt;p&gt;Just like making a function main safe, you are also responsible for making it cancelable. It won’t do it itself.&lt;/p&gt;

&lt;p&gt;In lifecycle dependent environment like Android, you should try to make each suspend function cancelable. Because any job can be cancelled at any time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is that important?
&lt;/h2&gt;

&lt;p&gt;Allow me to explain via an example, suppose you wrote a nice-shinny main-safe function that compresses the image to show it to user.&lt;/p&gt;

&lt;p&gt;Take this code snippet as an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class BitmapCompressor(
    private val context: Context
) {

    suspend fun compressImage(
        contentUri: Uri,
        compressionThreshold: Long
    ): Bitmap? {
        return withContext(Dispatchers.IO) {
            val inputBytes = context
                .contentResolver
                .openInputStream(contentUri)?.use { inputStream -&amp;gt;
                    inputStream.readBytes()
                } ?: return@withContext null


            withContext(Dispatchers.Default) {
                val bitmap = BitmapFactory.decodeByteArray(inputBytes, 0, inputBytes.size)


                var outputBytes: ByteArray
                var quality = 100
                do {
                    ByteArrayOutputStream().use { outputStream -&amp;gt;
                        bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream)
                        outputBytes = outputStream.toByteArray()
                        quality -= (quality * 0.1).roundToInt()
                    }
                } while (outputBytes.size &amp;gt; compressionThreshold &amp;amp;&amp;amp; quality &amp;gt; 5)


                BitmapFactory.decodeByteArray(outputBytes, 0, outputBytes.size).also{
                  println("Compression Finished")
                }
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don’t get overwhelmed, it’s just a function that compresses the image to a provided compressionThreshold&lt;/p&gt;

&lt;p&gt;Now, suppose user opened the screen, which had a viewModel which triggered this function, so that a compressed image can be shown.&lt;/p&gt;

&lt;p&gt;Before the function could finish compressing the image, user navigated back, at this point, there is no use of the compressed image. So ideally the function should cancel it’s execution.&lt;/p&gt;

&lt;p&gt;But if you actually implement it, you will see it won’t cancel itself, it will execute all the way to last statement which prints “Compression Finished”&lt;/p&gt;

&lt;p&gt;Don’t believe me?&lt;/p&gt;

&lt;p&gt;Check out this manual cancelation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MainActivity(): AppCompactActivity(){

  override onCreate(..){
  //some other stuff

    lifecycleScope.launch{
        val job = launch{
          BitmapCompressor(this@MainActivity).compressImage(
          //pass URI of the image &amp;amp; threshold
          )
          println("Inner Job Finished")
        }

        delay(1000)
        println("Canceling the job")
        job.cancel()

    }


  }


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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The compression takes around 5 seconds, on my testing device when provided a good size image. And in code, I am canceling the coroutine after one second.&lt;br&gt;
This is my output:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Canceling the job
Compression Finished
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It did not print &lt;code&gt;Canceling the job&lt;/code&gt; because the job was canceled BUT strangely enough, it printed &lt;code&gt;Compression Finished&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  BUT WHY??
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://waqasyounis334.medium.com/canceling-a-coroutine-simplified-0000b5b4c895" rel="noopener noreferrer"&gt;Check it out here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>androiddev</category>
      <category>kotlin</category>
      <category>coroutine</category>
    </item>
    <item>
      <title>Dispatchers.IO vs Dispatchers.Default?</title>
      <dc:creator>Waqas Younis</dc:creator>
      <pubDate>Tue, 10 Sep 2024 16:15:04 +0000</pubDate>
      <link>https://forem.com/waqas334/dispatchersio-vs-dispatchersdefault-35no</link>
      <guid>https://forem.com/waqas334/dispatchersio-vs-dispatchersdefault-35no</guid>
      <description>&lt;p&gt;I recently learnt about this via a very practical example so sharing it here with you guys.&lt;/p&gt;

&lt;p&gt;As you may already know, Dispatchers.IO is optimised for IO related operations like Network call or reading a file etc, and Dispatchers.Default is optimised for CPU intensive task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But why is that?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do they work under the hood?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let me share with you an example. Take a look at the following code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun dispatchersTester(){

    //keep track of threads used
    val threads = hashMapOf&amp;lt;Long,String&amp;gt;()


    val job = GlobalScope.launch(Dispatchers.Default) {
        repeat(100){
            launch {
                //storing the threads
                threads[Thread.currentThread().id] = Thread.currentThread().name

                //simulate a network call
                Thread.sleep(1_000)
            }
        }
    }

    //Wait for the above job to finish and 
    //measure the duration
    GlobalScope.launch {
        val timeMs = measureTimeMillis {
            job.join()
        }

        Log.d(TAG, "Took ${threads.keys.size} threads and $timeMs ms ")

    }

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

&lt;/div&gt;



&lt;p&gt;In a nutshell, we are creating 100 coroutines and launching them in Default dispatcher and simulating the network call by adding a sleep of 1 sec.&lt;/p&gt;

&lt;p&gt;After running for couple times, the following results were obtained:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Took 4 threads and 25075 ms 
Took 4 threads and 25048 ms 
Took 4 threads and 25060 ms 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, it uses 4 threads at max and took whooping 25 seconds to complete this task.&lt;/p&gt;

&lt;p&gt;It means the system launched a batch of 4 threads simultaneously. As we are creating 100 coroutines, 4 threads at a time with a delay of 1 sec takes around 25 seconds.&lt;/p&gt;




&lt;p&gt;Now, let’s change the Dispatcher to IO. And check out the results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Took 64 threads and 2011 ms
Took 64 threads and 2009 ms
Took 64 threads and 2005 ms 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This time the system is using 64 threads to complete the task in just 2 seconds.&lt;/p&gt;

&lt;p&gt;Which means it’s launching a batch of 64 threads at a time, and as we are only launching 100 coroutines, so it launched two batches, each with delay of 1 sec and completed the task in roughly 2 seconds&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notice how changing only dispatcher brought this huge difference.&lt;br&gt;
Why is that?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;IO Dispatcher is optimised for task where the threads go in a state where they trigger something and wait for the result, like a network request. The optimisation is done in a such a way that it allows them to create multiple threads and when a thread reach the pause state, the system resumes execution on the other thread.&lt;/p&gt;

&lt;p&gt;Which is not the case with Default Dispatcher.&lt;/p&gt;
&lt;h2&gt;
  
  
  Let’s see what Dispatchers.Default is good at.
&lt;/h2&gt;

&lt;p&gt;Instead of simulating the network call, let’s simulate a CPU intensive task.&lt;/p&gt;

&lt;p&gt;Replace &lt;code&gt;Thread.sleep(1000)&lt;/code&gt; with &lt;code&gt;(1..100_000).map{it*it}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It is going from 1 to 100K and computing square of each number.&lt;/p&gt;

&lt;p&gt;Let’s run it with Dispatchers.IO:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Took 51 threads and 249 ms
Took 54 threads and 546 ms
Took 57 threads and 402 ms 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let’s change the Dispatcher to Default&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Took 4 threads and 154 ms
Took 4 threads and 107 ms
Took 4 threads and 121 ms 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though the actual difference is not much, but still it took half the amount of time than IO dispatcher.&lt;/p&gt;

&lt;p&gt;Hope it helps, &lt;br&gt;
Cheers.&lt;/p&gt;

</description>
      <category>android</category>
      <category>androiddev</category>
      <category>kotlin</category>
      <category>coroutine</category>
    </item>
    <item>
      <title>Chrome extension to show the status of tasks from Asana to Google Play Console</title>
      <dc:creator>Waqas Younis</dc:creator>
      <pubDate>Thu, 15 Aug 2024 21:15:42 +0000</pubDate>
      <link>https://forem.com/waqas334/chrome-extension-to-show-status-of-tasks-from-asana-to-chrome-extension-22o2</link>
      <guid>https://forem.com/waqas334/chrome-extension-to-show-status-of-tasks-from-asana-to-chrome-extension-22o2</guid>
      <description>&lt;p&gt;Hello there, being an Android Developer and mostly working on Crashes reported by Google Play Console, I have to go back and forth to keep track of the status of the crash/anr and see who is working on it,&lt;/p&gt;

&lt;p&gt;To overcome this problem, I am creating a Chrome extension that would:&lt;/p&gt;

&lt;p&gt;Create a task in Asana with a single click, if already not created&lt;/p&gt;

&lt;p&gt;Show the task status, like who is working on it, and whether is it in Progress, Completed, or whatever section you create in Asana.&lt;/p&gt;

&lt;p&gt;What do you think about it? Is it worth doing? Would you use such a thing?&lt;/p&gt;

&lt;p&gt;Hello there, being an Android Developer and mostly working on Crashes reported by Google Play Console, I have to go back and forth to keep track of the status of the crash/anr and see who is working on it,&lt;/p&gt;

&lt;p&gt;To overcome this problem, I am creating a Chrome extension that would:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Create a task in Asana with a single click, if already not created&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Show the task status, like who is working on it, and whether it is in Progress, Completed, or whatever section you create in Asana.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What do you think about it? Is it worth doing? Would you use such a thing?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9sftpqlhnvn98iq72uy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9sftpqlhnvn98iq72uy.png" alt="Screenshot of Google Play Console crashes page" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>asana</category>
      <category>google</category>
      <category>play</category>
    </item>
    <item>
      <title>Understanding Cohesion</title>
      <dc:creator>Waqas Younis</dc:creator>
      <pubDate>Sun, 14 Jul 2024 01:05:12 +0000</pubDate>
      <link>https://forem.com/waqas334/understanding-cohesion-h9o</link>
      <guid>https://forem.com/waqas334/understanding-cohesion-h9o</guid>
      <description>&lt;p&gt;I just finished learning about Cohesion and it's part and here is a summary.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is it?
&lt;/h2&gt;

&lt;p&gt;It is how your module is structured, not how it communicates/integrates with another module. That is a couple. &lt;/p&gt;

&lt;h2&gt;
  
  
  There are 7 types of Cohesion
&lt;/h2&gt;

&lt;p&gt;The best one is &lt;strong&gt;Function Cohesion&lt;/strong&gt;, where everything that helps do a specific well-defined task is kept in one module. Like an Authentication Module, which offers functionality like login, logout, forgot password, etc&lt;/p&gt;

&lt;p&gt;The worst one is &lt;strong&gt;Coincidental Cohesion&lt;/strong&gt;, where there is no specific relation between the elements, except that they are at the same place. Consider a Utility module that has all sort of functions like String Format, Printing Log, Creating New File, etc. &lt;/p&gt;

&lt;p&gt;The other ones didn't look interesting to me, they were like different sides of the same coin. &lt;/p&gt;

</description>
      <category>architecture</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>Find something worth solving, not what you can solve.</title>
      <dc:creator>Waqas Younis</dc:creator>
      <pubDate>Sun, 14 Jul 2024 00:52:58 +0000</pubDate>
      <link>https://forem.com/waqas334/find-something-worth-solving-not-what-you-can-solve-52ln</link>
      <guid>https://forem.com/waqas334/find-something-worth-solving-not-what-you-can-solve-52ln</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fespqy4df8dsddecgmjuh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fespqy4df8dsddecgmjuh.png" alt="Image description" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I follow how software and programs were developed back in the day; one of my favorites is the creation of VisiCalc. When the computer keyboard used to have only left and right keys, no up and down keys, they developed a spreadsheet software. Isn't that amazing?&lt;/p&gt;

&lt;p&gt;After reading a couple of articles and watching some videos, I wrote the calculation in my personal-tech diary:&lt;br&gt;
"Don't think of it as if the problem is actually solvable by you or not. Or it must be easy, there could be a possibility that you need to go extra mile to bring it to life." &lt;br&gt;
"The only thing you need to think about is that the problem actually exists and people are willing to pay to get it solved" 20th December 2023&lt;/p&gt;

&lt;p&gt;Consider it as a signal to start working on the idea that you think it's too big for you.&lt;/p&gt;

&lt;p&gt;Cheers.&lt;br&gt;
PS: Pardon my handwriting, I am better at typing. :)&lt;/p&gt;

</description>
      <category>motivation</category>
      <category>programming</category>
      <category>productivity</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
