<?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: Nyerhovwo Adjekughene (Nero)</title>
    <description>The latest articles on DEV Community by Nyerhovwo Adjekughene (Nero) (@nerojust).</description>
    <link>https://dev.to/nerojust</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%2F3353493%2F809f3045-8357-4e4a-a5a7-36a96ea9d05b.jpg</url>
      <title>DEV Community: Nyerhovwo Adjekughene (Nero)</title>
      <link>https://dev.to/nerojust</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nerojust"/>
    <language>en</language>
    <item>
      <title>📸 JetImagePicker: Effortless Image Picking in Jetpack Compose (With Zero Permission Worries)</title>
      <dc:creator>Nyerhovwo Adjekughene (Nero)</dc:creator>
      <pubDate>Tue, 15 Jul 2025 08:20:31 +0000</pubDate>
      <link>https://dev.to/nerojust/jetimagepicker-effortless-image-picking-in-jetpack-compose-with-zero-permission-worries-2512</link>
      <guid>https://dev.to/nerojust/jetimagepicker-effortless-image-picking-in-jetpack-compose-with-zero-permission-worries-2512</guid>
      <description>&lt;p&gt;&lt;em&gt;Let's face it - handling image capture and gallery selection in Android is painful. Between READ_MEDIA_IMAGES, scoped storage, runtime permissions, compression, and Compose UI updates… it's easy to mess up. That's why I built JetImagePicker - a plug-and-play image picker for Android from API 21 to 34+ that just works.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What Is JetImagePicker?&lt;/strong&gt;&lt;br&gt;
JetImagePicker is a modern Kotlin library that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Handles camera/gallery permissions automatically&lt;/li&gt;
&lt;li&gt;Supports multiple image selection&lt;/li&gt;
&lt;li&gt;Handles Android 13+ scoped media permissions&lt;/li&gt;
&lt;li&gt;Provides compression, resizing, and easy-to-use UI previews&lt;/li&gt;
&lt;li&gt;Works with both Jetpack Compose and classic XML&lt;/li&gt;
&lt;/ol&gt;



&lt;p&gt;&lt;strong&gt;Why I Built It&lt;/strong&gt;&lt;br&gt;
While working on photo uploads at &lt;a href="https://www.raenest.com/" rel="noopener noreferrer"&gt;Raenest&lt;/a&gt;, we found ourselves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copy-pasting permission logic into every feature&lt;/li&gt;
&lt;li&gt;Handling edge cases manually for Android 10–14&lt;/li&gt;
&lt;li&gt;Writing boilerplate code for image compression, state handling, and previews&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I thought: There has to be a cleaner way - so I created &lt;strong&gt;JetImagePickerLibrary&lt;/strong&gt;.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Full Example in Jetpack Compose&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Composable
fun ImagePickerScreen(modifier: Modifier = Modifier) {
    val context = LocalContext.current
    var message by remember { mutableStateOf&amp;lt;String?&amp;gt;(null) }
    val pickerState = rememberJetImagePickerState(
        context = context,
        config = JetImagePickerConfig(
            enableCompression = true,
            compressionQuality = 70,
            allowMultiple = false,
            targetWidth = 1024,
            targetHeight = 1024
        )
    ) { result -&amp;gt;
        when (result) {
            is ImagePickerResult.Success -&amp;gt; {
                message = null
                Log.d("ImagePicker", "Images selected: ${result.uris}")
            }
            is ImagePickerResult.PermissionDenied -&amp;gt; {
                message = "Permission denied: ${result.permission}"
            }
            is ImagePickerResult.PermissionPermanentlyDenied -&amp;gt; {
                message = "Permission permanently denied: ${result.permission}. Enable in settings."
            }
            is ImagePickerResult.ShowRationale -&amp;gt; {
                message = "Please grant ${result.permission} permission to continue."
            }
        }
    }
    Column(modifier = modifier.padding(16.dp)) {
        Button(
            onClick = pickerState.pickFromGallery,
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("Pick from Gallery")
        }
        Spacer(modifier = Modifier.height(8.dp))
        Button(
            onClick = pickerState.captureWithCamera,
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("Capture with Camera")
        }
        Spacer(modifier = Modifier.height(16.dp))
        when (pickerState.selectedImageUris.size) {
            1 -&amp;gt; ImagePreview(uri = pickerState.selectedImageUris.first())
            in 2..Int.MAX_VALUE -&amp;gt; MultiImagePreview(imageUris = pickerState.selectedImageUris)
        }
        message?.let {
            Spacer(modifier = Modifier.height(12.dp))
            Text(
                text = it,
                color = MaterialTheme.colorScheme.error,
                style = MaterialTheme.typography.bodySmall
            )
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Features Recap&lt;/strong&gt;&lt;br&gt;
Feature JetImagePicker Library &lt;/p&gt;

&lt;p&gt;📱 API Level Support 21 to 34+ &lt;br&gt;
🔐 Runtime Permissions    - Auto-handled &lt;br&gt;
🖼 Multiple Image Support - Yes &lt;br&gt;
🧯 Compression &amp;amp; Resizing - Configurable &lt;br&gt;
🧩 Jetpack Compose Ready  - Native &lt;br&gt;
🎯 Zero Boilerplate       - Yes&lt;/p&gt;



&lt;p&gt;⚙️ &lt;strong&gt;How It Works&lt;/strong&gt;&lt;br&gt;
rememberJetImagePickerState manages all state, permissions, and result callbacks&lt;br&gt;
JetImagePickerConfig lets you control compression, multi-selection, and image dimensions&lt;br&gt;
Preview components (ImagePreview, MultiImagePreview) are provided out of the box&lt;/p&gt;



&lt;p&gt;🔌 &lt;strong&gt;Installation&lt;/strong&gt;&lt;br&gt;
// settings.gradle&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dependencyResolutionManagement {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;// app/build.gradle&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dependencies {
    implementation 'com.github.nerojust:JetImagePicker:v1'
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;//In android manifest&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; &amp;lt;uses-permission android:name="android.permission.CAMERA" /&amp;gt;
    &amp;lt;uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /&amp;gt;
    &amp;lt;uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Check out the library on Github &lt;a href="https://github.com/Nerojust/JetImagePicker" rel="noopener noreferrer"&gt;Here&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;br&gt;
If you're building modern Android apps with Jetpack Compose or XML, JetImagePickerLibrary will save you dozens of hours. No more worrying about runtime permissions or fragile file URI logic.&lt;br&gt;
One function. All versions. All scenarios handled.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Want to Contribute?&lt;/strong&gt;&lt;br&gt;
Got improvements, Compose UI integrations, or better compression ideas?&lt;/p&gt;

&lt;h2&gt;
  
  
   📦 Fork it on GitHub: &lt;a href="https://github.com/Nerojust/JetImagePicker" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;🤝 &lt;strong&gt;Let's Connect&lt;/strong&gt;&lt;br&gt;
 💼 &lt;a href="https://www.linkedin.com/in/nyerhovwo-adjekughene-97508674/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
 🐙 &lt;a href="//www.github.com/nerojust"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I share posts weekly on:&lt;br&gt;
📱 Android Dev • 🧠 Clean Architecture • ⚙️ Jetpack • 🔐 Security • 🌍 Fintech Engineering&lt;/p&gt;




&lt;p&gt;🏷 &lt;strong&gt;Tags&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  AndroidDev #Kotlin #JetpackCompose #Permissions #MobileDevelopment #CleanArchitecture #OpenSource #DevTools
&lt;/h1&gt;

</description>
      <category>programming</category>
      <category>android</category>
      <category>kotlin</category>
      <category>mobiledev</category>
    </item>
    <item>
      <title>Kotlin lazy vs lateinit: When and Why You Should Use Them</title>
      <dc:creator>Nyerhovwo Adjekughene (Nero)</dc:creator>
      <pubDate>Mon, 14 Jul 2025 11:37:58 +0000</pubDate>
      <link>https://dev.to/nerojust/kotlin-lazy-vs-lateinit-when-and-why-you-should-use-them-p78</link>
      <guid>https://dev.to/nerojust/kotlin-lazy-vs-lateinit-when-and-why-you-should-use-them-p78</guid>
      <description>&lt;p&gt;Knowing when to use lazy or lateinit is one of those "aha" moments that separates clean, reliable Kotlin code from spaghetti code - especially in Android development. In this post, I'll break down these powerful property delegates, share my Android use cases, and help you decide which one is right - and when.&lt;/p&gt;




&lt;p&gt;🧐 &lt;strong&gt;So, what are they?&lt;/strong&gt;&lt;br&gt;
Both lazy and lateinit are tools that allow delayed initialization of properties - but they solve different problems.&lt;br&gt;
Think of it like this:&lt;br&gt;
🛋️ lazy is like setting up a beanbag you'll only sit on when you feel like it&lt;br&gt;
🔧 lateinit is like screwing on a table leg after you've assembled the frame&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Kotlin lazy – For Read-Only, One-Time Initialization&lt;/strong&gt;&lt;br&gt;
lazy lets you define a read-only property (val) whose value is computed only once - the first time it's accessed.&lt;/p&gt;

&lt;p&gt;Real Example: Lazy-loading a Retrofit service&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val apiService by lazy {
    Retrofit.Builder()
        .baseUrl(BASE_URL)
        .build()
        .create(ApiService::class.java)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why this works great:&lt;br&gt;
We only initialize the Retrofit service when needed&lt;br&gt;
Saves memory during early startup&lt;br&gt;
Keeps it thread-safe by default (SYNCHRONIZED mode)&lt;/p&gt;

&lt;p&gt;🧪 Another Example: Config loading&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val config by lazy(LazyThreadSafetyMode.NONE) {
    loadRemoteConfig()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This disables synchronization for better performance if you guarantee no race conditions (like using it in onCreate() only).&lt;/p&gt;




&lt;p&gt;Kotlin lateinit – For Mutable Properties Set Later&lt;br&gt;
lateinit is your tool when you want to declare a non-null var that will be initialized after the object is constructed.&lt;/p&gt;

&lt;p&gt;✅ Common in Android:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, you can't initialize binding at the point of declaration, because layoutInflater isn't ready yet.&lt;/p&gt;




&lt;p&gt;⚔️ *&lt;em&gt;lazy vs lateinit *&lt;/em&gt;– When to Use Each&lt;br&gt;
Ask Yourself Use Is it a val, and only needs 1 init? lazy Is it a var, assigned after init? lateinit Is it null-safe and side-effect-free? lazy Do you need dependency injection later? lateinit&lt;/p&gt;



&lt;p&gt;🧨 &lt;strong&gt;Common Mistakes to Avoid&lt;/strong&gt;&lt;br&gt;
❌ Accessing lateinit before it's initialized&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (::someVar.isInitialized) {
    println(someVar)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always check with ::yourVar.isInitialized to avoid UninitializedPropertyAccessException.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Real-world Android Dev Examples&lt;/strong&gt;&lt;br&gt;
💡 Lazy ViewModel Factory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val viewModelFactory by lazy {
    MyCustomViewModelFactory(requireContext())
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful when building custom ViewModels in Fragments or Composables.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;lateinit + Dependency Injection (e.g. Dagger/Hilt)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Inject
lateinit var userRepo: UserRepository
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can't use constructor injection in some Android components (like Fragments), so lateinit is perfect here.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Why This Matters in Real Apps&lt;/strong&gt;&lt;br&gt;
In one of my projects, using lazy helped me avoid triggering an expensive image loading setup until the user actually opened the gallery screen - reducing cold startup time.&lt;br&gt;
In another case, lateinit saved me from null checks all over a test suite where I needed to inject mocked APIs.&lt;br&gt;
The more your Android app grows, the more these tools help keep code clean, readable, and maintainable.&lt;/p&gt;




&lt;p&gt;🧑‍🏫 &lt;strong&gt;Final Advice&lt;/strong&gt;&lt;br&gt;
🧘 Use lazy when you're dealing with one-time expensive operations&lt;br&gt;
🔧 Use lateinit when you can't initialize immediately but want to avoid nullable types&lt;br&gt;
🤝 Document or comment fields clearly - they might crash if accessed too early!&lt;/p&gt;




&lt;p&gt;🤝** Let's Connect**&lt;br&gt;
If you found this article useful or want to ask me about anything from Kotlin to Clean Architecture:&lt;/p&gt;

&lt;p&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/nyerhovwo-adjekughene-97508674/" rel="noopener noreferrer"&gt;Here&lt;/a&gt;&lt;br&gt;
GitHub: Here (&lt;a href="http://www.github.com/nerojust" rel="noopener noreferrer"&gt;www.github.com/nerojust&lt;/a&gt;)&lt;/p&gt;

&lt;h1&gt;
  
  
  AndroidDev #Kotlin #Coroutines #MobileDevelopment #ModernAndroid #DevJourney #CleanArchitecture #MVVM
&lt;/h1&gt;

</description>
      <category>android</category>
      <category>mobile</category>
      <category>kotlin</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
