<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های abstractArrow</title>
        <link>https://virgool.io/feed/@ramtintoosi</link>
        <description>بیشترین طلاها از ذهن افراد بیرون کشیده می‌شود، نه معادن</description>
        <language>fa</language>
        <pubDate>2026-06-07 18:36:04</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/180856/avatar/2Lt3jP.png?height=120&amp;width=120</url>
            <title>abstractArrow</title>
            <link>https://virgool.io/@ramtintoosi</link>
        </image>

                    <item>
                <title>Android Intent | Intent Filter</title>
                <link>https://virgool.io/@ramtintoosi/android-intent-sxbhoo83oiba</link>
                <description>از حرکت بین صفحات اپلیکیشن خودتان تا استفاده از صفحات اپلیکیشن‌های دیگر نصب شده بر روی گوشی کاربر، با یادگیری دو مفهوم Intent و Intent Filter می‌توانید از Activity های دیگر اپلیکیشن‌ها از جمله جیمیل، تلگرام، دوربین و ... در درون اپلیکیشن خود استفاده کنید.مفهوم Intent چیست؟یک پاکت نامه را در نظر بگیرید، شما از این پاکت نامه برای ارسال اطلاعات به شخص دیگری در هر جای دنیا می‌توانید استفاده کنید. Intent هم پاکت نامه‌ای است که آن را به سیستم عامل می‌دهید تا Component مورد نظر شما را اجرا کند.val intent = Intent(context, SomeOtherActivity::class.java)منظور از Component چیست؟اندروید بر پایه چهار جز (Component) اصلی با نام‌های زیر تشکیل شده است:ActivityServiceBroadcast ReceiverContent Providerبه جز Content Provider برای شروع و ارتباط با سه Component دیگر از Intent استفاده می‌کنیم.انوع Intentدو نوع پیغام در اندروید می‌توانیم ارسال کنیم:Explicit (صریح)Implicit (ناواضح)پیغام Explicit چیست؟پیغامی است که در آن گیرنده کاملا مشخص است. باز کردن صفحات دیگر اپلیکیشن خودتان از این نوع Intent می‌باشد:val intent = Intent(context, SomeOtherActivity::class.java)
startActivity(intent)پیغام Implicit چیست؟هنگامی که شما به سیستم‌عامل اندروید درخواست می‌دهید تمامی Componentهایی که توانایی کمک به انجام عمل خاص شما را دارند معرفی کند. https://gist.github.com/d9666461f627e8df17e066f7bcad3339#file-sample-kt دیالوگ انتخاب اپلیکیشندر اینجا Action چیست؟در واقع Action عملیاتی است که یک Activity توانایی اجرای آن را دارد. در اینجا به سیستم عامل اندروید می‌گویید به من Activityهایی را نمایش بده که توانایی ارسال (از هر نوعی) دارند.منظور از Type چیست؟نوع یا همان MIME Type می‌باشد. اولین بار MIME Typeها در مبحث وب مورد استفاده قرار گرفتند و نشان‌دهنده نوع اطلاعات بودند. در اندروید هم ما از MIME Type برای مشخص کردن نوع اطلاعات استفاده می‌کنیم. در اینجا می‌گوییم تمام Activityهایی را برای من نمایش بده که قابلیت ارسال نوشته (Text) و از نوع ساده (Plain) را دارند.مثال:text/plain = نوشته سادهimage/jpeg = عکس از فرمت جی‌پگimage/* = عکس از هر نوعی منظور از Plain این می‌باشد که نوشته عادی می‌باشد و هیچ مفهوم دیگری ندارد، مثلا HTML یا CSS نیست.دلیل استفاده از فانکشن putExtra چیست؟برای ارسال اطلاعات مورد نظرمان می‌توانیم از Extra های از پیش تعیین شده استفاده کنیم. در اینجا Text کلیدی است که برای ارسال اطلاعات به گیرنده ارسال می‌شود.هر Action ای با هر Extra ای سازگار نیست! و بستگی به توسعه‌دهنده اپلیکیشن گیرنده دارد.دلیل استفاده از Intent.createChooser چیست؟این فانکشن هر بار برای کاربر یک دیالوگ برای انتخاب اپلیکیشن مورد نظر نمایش می‌دهد. اگر در نسخه‌های جدید اندروید از این فانکشن استفاده نکنید دیالوگ کوچک دیگری نمایش داده می‌شود و کاربر حق انتخاب از بین اپلیکیشن‌ها را دارد، اگر گزینه به یاد بسپار را کلیک کند دیگر این دیالوگ نمایش داده نمی‌شود.چگونه اندروید Activity ها را فیلتر می‌کند؟با استفاده از intent-filter هایی که در AndroidManifest.xml تعریف می‌شود سیستم‌عامل Activity ها را شناسایی و به سایرین معرفی می‌کند.به Activity اصلی اپلیکیشن خود در AndroidManifest.xml نگاهی بندازید:&lt;activity android:name=&amp;quot.MainActivity&amp;quot&gt;
            &lt;intent-filter&gt;
                 &lt;action android:name=&amp;quotandroid.intent.action.MAIN&amp;quot /&gt;
                 &lt;category android:name=&amp;quotandroid.intent.category.LAUNCHER&amp;quot /&gt;
            &lt;/intent-filter&gt;
&lt;/activity&gt;در اینجا صفحه‌اصلی برنامه Action یا عمکرد اصلی خود را به عنوان Main یا شروع‌کننده معرفی می‌کند و همچنین خود را در دسته‌بندی شروع کننده اپلیکیشن یا Launcher قرار می‌دهد.برای مثال‌های قبلی چه نوع Intent Filter ای لازم هست؟&lt;activity android:name=&amp;quot.SenderActivity&amp;quot&gt;
            &lt;intent-filter&gt;
                 &lt;action android:name=&amp;quotandroid.intent.action.SEND&amp;quot/&gt;
                 &lt;category android:name=&amp;quotandroid.intent.category.DEFAULT&amp;quot/&gt;
                &lt;data android:mimeType=&amp;quottext/plain&amp;quot/&gt;
            &lt;/intent-filter&gt;
&lt;/activity&gt;چرا Category در اینجا Default می‌باشد؟در Intent هایی که می‌خواهید implicit باشند Category را بر روی DEFAULT قرار دهید که معنای قابل شناسایی توسط اندروید را می‌دهد تداعی می‌کند. بدون این خط برنامه شما در لیست نمایش داده نمی‌شود.شروع کردن یک اپلیکیشن خاصبرای مثال اپلیکیشن واتس‌اپ را می‌خواهیم شروع کرده و پیغامی ارسال کنیم: https://gist.github.com/48cb72b09b20b50e42e9c03c991c0681#file-sample-kt دلیل استفاده از resolveActivity چیست؟در اینجا به دنبال آن می‌گردیم آیا اپلیکیشنی با مشخصات داده شده وجود دارد یا خیر؟ اگر مقدار null باشد اپلیکیشن با خطا همراه خواهد شد که ما در بلاک let از آن جلوگیری کرده‌ایم.</description>
                <category>abstractArrow</category>
                <author>abstractArrow</author>
                <pubDate>Mon, 25 May 2020 17:26:10 +0430</pubDate>
            </item>
                    <item>
                <title>آموزش RxKotlin - قسمت ۲</title>
                <link>https://virgool.io/@ramtintoosi/rxkotlin-02-wpqod5wb7kdn</link>
                <description>قسمت ۰ - مقدمهقسمت ۱ - Observable قسمت ۲ - انواع Observableها (در حال مطالعه هستید)ReactiveXدر قسمت قبل با Observable ها آشنا شدیم که اطلاعات/رویداد‌ها را به Observer انتقال می‌دهند. در این قسمت با چندین زیرمجموعه از Observableها آشنا می‌شویم که دارای کاربرد مشخص‌تری هستند.Singleهمیشه و تنها فقط و فقط یک مقدار/رویداد به Observer ارسال می‌کند. این مقدار یا یک موفقیت (Success) و یا یک اررو (Error) می‌باشد.رویداد onSuccess ترکیبی از onNext و onComplete می‌باشد. در واقع با صدا زدن onSuccess اطلاعات ارسال و کار به پایان رسیده و کل Observable ما dispose می‌شود. https://gist.github.com/92da9b8e4436c19bb503dbf048faf9ed#file-sample-kt Completableتنها یک رویداد کامل شد (onComplete) و یا یک رویداد ارور () تولید می‌کند و هیچ اطلاعات/رویداد واقعی به Observer ارسال نمی‌کند: https://gist.github.com/5ad0ca064c74c24d819fe8ec8915abbb#file-sample-kt Maybeترکیبی از Single و Completable می‌باشد:فقط و فقط یک اطلاعات/رویداد تولید می‌کند.شامل رویداد onSuccess یا onComplete یا  می‌باشد.به هیچ عنوان نمی‌توانید دو رویداد/اطلاعات را با هم به Observer ارسال کنید، مثلا بعد از صدا زدن onSuccess دیگر نمی‌توانید onComplete را صدا بزنید.علاوه بر Observableهایی که در این قسمت معرفی شد انواع پیشرفته‌تری نیز وجود دارند که در پست‌های بعدی مورد بررسی قرار خواهیم داد.قسمت ۳ - Side Effectها (انتشار دوشنبه 05-03-1399)برای اطلاع‌رسانی سریع از قسمت بعدی Follow کنید، همچنین هر لایک شما دلگرمی است بدون هیچ زحمتی برای ارائه مطالب بهتر ;)</description>
                <category>abstractArrow</category>
                <author>abstractArrow</author>
                <pubDate>Sat, 23 May 2020 11:52:50 +0430</pubDate>
            </item>
                    <item>
                <title>آموزش RxKotlin - قسمت ۱</title>
                <link>https://virgool.io/@ramtintoosi/rxkotlin01-bsmruxloibyn</link>
                <description>پیش از شروع به خواندن توصیه می‌شود قسمت ۰ (مقدمه و آشنایی با ReactiveX) را مطالعه کنید.قسمت ۰ - مقدمهقسمت ۱ - Observable (در حال مطالعه هستید)قسمت ۲ - انواع Observableها (انتشار 01-03-1399)RactiveXآموزش ساخت پروژه و افزودن RxKotlinتنظیمات هنگام ساخت پروژه:از منوی سمت چپ Gradle را انتخاب کنیدتیک Java را حذف کنید.تیک Kotlin/JVM را بزنید.نسخه JDK شما توصیه می‌شود بر روی نسخه 8 یا همان 1.8 باشد.تنظیمات هنگام ساخت پروژهافزودن RxKotlinوارد فایل build.gradle شوید.کتابخانه (Dependency) زیر را به قسمت dependencies اضافه کنید.compile &#039;io.reactivex.rxjava2:rxkotlin:2.2.0&#039;در صورت نیاز، برای یافتن آخرین نسخه از Maven Repository استفاده کنید.کلمه Observable به معنای آنچه که قابل مشاهده و بررسی می‌باشد معنا می‌دهد و در ReactiveX ما به عنوان Observer (مشاهده‌گر) علاقه‌مند به اطلاعاتی که Observable در اختیار ما می‌گذارد هستیم. به رابطه بین Observer و Observable کلمه Subscription (عضویت) نسبت داده می‌شود:برای تمرین تمام مثال‌ها را داخل فانکشن main قرار دهید.Observable.just(&amp;quotBitcoin&amp;quot, &amp;quotEthereum&amp;quot, &amp;quotTether&amp;quot)
        .subscribeBy { currency -&gt;
            println(currency)
        }خروجی:BitcoinEthereumTetherدر اینجا سه رمز ارز معروف بیت‌کوین، اتریوم و تتر را در داخل یک Observable داریم که توسط ما Subscribe (عضویت) صورت گرفته تا تمام آیتم‌های آن چاپ شود.این قسمت اطلاعات قابل مشاهده ما را تعریف می‌کند (Observable):Observable.just(&amp;quotBitcoin&amp;quot, &amp;quotEthereum&amp;quot, &amp;quotTether&amp;quot)به فانکشن‌ها در ReactiveX کلمه Operator اختصاص داده شده، مثلا just در اینجا یک Operator می‌باشد.این قسمت ما خودمان را به عنوان مشاهده‌گر (Observer) معرفی می‌کنیم:.subscribeBy { currency -&gt; println(currency) }اپراتور just به معنای فقط در اینجا تنها (فقط) چندین اطلاعات را در خود نگهداری می‌کند. این اپراتور overload شده می‌باشد و بر اساس نیاز می‌توانید تعداد دلخواه تا سقف مجاز نگهداری کنید.امیدوارم بدانید Overload به معنای وجود چندین فانکشن با اسامی یکسان ولی امضاهای متفاوت می‌شود. امضا یا Signature همان ورودی‌های آن فانکشن محسوب می‌شود، یعنی اگر در یک کلاس دو فانکشن نام یکسان add را داشتند یکی از آن‌ها دو ورودی Int دریافت می‌کند، دیگری باید دو ورودی از نوع دیگر مثلا String یا تعداد متفاوت ورودی Int قبول کند.هر Observable سه حالت کلی دارد:اطلاعات/رویداد (Data/Event) بعدی رسید - ()onNextارسال اطلاعات/رویداد به پایان رسید - ()onCompleteارسال اطلاعات/رویداد با مشکل رو به رو شد - ()در مثال قبلی  subscribeBy تنها onNext را برای ما چاپ کرد ولی اینبار دو حالت دیگر را نیز اضافه می‌کنیم:Observable.just(&amp;quotBitcoin&amp;quot, &amp;quotEthereum&amp;quot, &amp;quotTether&amp;quot)
        .subscribeBy(
                onNext = { currency -&gt;
                    println(currency)
                },
                onComplete = {
                    println(&amp;quotCompleted&amp;quot)
                },
                 = {
                    println(&amp;quotError&amp;quot)
                }
        )خروجی:BitcoinEthereumTetherCompletedتوجه داشته باشید که  به علت عدم وجود خطا چاپ نمی‌شود.هنگامی که دو فانکشن  یا onComplete صدا زده می‌شوند عضویت (Subscription) بین Observer و Observable از بین می‌رود (Dispose می‌شود) در قسمت‌های بعدی موقعیت‌هایی وجود دارد که حتما بایستی به صورت دستی این عضویت‌ها را Dispose کنیم ولی در اینجا به علت اینکه Observable ما تنها چندین اطلاعات/رویداد در خود نگه می‌دارد و پس از اتمام  یا onComplete به صورت خودکار صدا زده می‌شوند نیازی به این کار وجود ندارد.نتیجه رابطه Observer و Observable یک Subscription می‌باشد:val subscription = Observable.just(&quot;Bitcoin&quot;, &quot;Ethereum&quot;, &quot;Tether&quot;)        .subscribeBy { println(it) }println(&quot;Is subscription disposed? -&gt; ${subscription.isDisposed}&quot;)استفاده از کالکشن در Observable:روش اول تبدیل کالکشن به Observable که دارای سه آیتم است:Observable&lt;String&gt;listOf(&amp;quotLitecoin&amp;quot, &amp;quotMonero&amp;quot, &amp;quotTRON&amp;quot).toObservable()
        .subscribeBy {
            println(it)
        }اپراتور toObservable یک کالکشن را تبدیل به Observable شامل سه آیتم می‌کند. روش دوم تبدیل کل لیست به یک آیتم در Observable:Observable&lt;List&lt;String&gt;&gt;Observable.just(listOf(&amp;quotLitecoin&amp;quot, &amp;quotMonero&amp;quot, &amp;quotTRON&amp;quot))
        .subscribeBy { currencyList: List&lt;String&gt; -&gt;
            currencyList.forEach {
                println(it)
            }
        }ساخت Observable دلخواهبرای ساخت منطق شخصی‌سازی شده می‌توانید از Operator ای به نام create استفاده کنید و با استفاده از Observable Emitter آن هر جا که نیاز داشتید رویداد onNext, , onComplete را صدا بزنید:کلمه Emitter به معنای انتشار دهنده می‌باشد، در ReactiveX ما اطلاعات را به Observer انتشار می‌دهیم.برای تست یکبار ورودی را سن واقعی خودتان و یکبار یک کاراکتر غیر عددی وارد کنید تا تفاوت را متوجه شوید.val observable = Observable.create&lt;String&gt; { emitter -&gt;
    println(&amp;quotPlease enter your age:&amp;quot)
    val ageInput = readLine()
    ageInput ?: return@create
    try {
        val age = ageInput.toInt()
        if (age &lt; 18) {
            emitter.onNext(&amp;quotUser is under age: $age&amp;quot)
        } else {
            emitter.onNext(&amp;quotUser is at appropriate age&amp;quot)
        }
        emitter.onComplete()
    } catch (exception: NumberFormatException) {
        emitter.(exception)
    }
}

val subscription = observable.subscribeBy(
        onNext = { message -&gt;
            println(message)
        },
         = { throwable -&gt;
            println(&amp;quotError, $throwable&amp;quot)
        },
        onComplete = {
            println(&amp;quotCompleted&amp;quot)
        }
)دلیل احتمال کرش کردن برنامه در کد بالا فانکشن toInt می‌باشد که توانایی تبدیل کاراکتر غیر عددی را به یک عدد ندارد و برنامه با Exception رو به رو خواهد شد و ما آن را Catch کرده و با RxKotlin یک رویداد خطا به مشاهده‌گر انتشار می‌دهیم.در قسمت بعدی با انواع Observableها و همچنین Side Effectها آشنا خواهیم شد. انواع زیر مجموعه Observable ها به ما کمک می‌کنند رویدادهای بهتر و مناسب‌تری به Observer ارائه دهیم.</description>
                <category>abstractArrow</category>
                <author>abstractArrow</author>
                <pubDate>Sun, 17 May 2020 15:10:23 +0430</pubDate>
            </item>
                    <item>
                <title>آموزش RxKotlin - قسمت ۰</title>
                <link>https://virgool.io/@ramtintoosi/rxkotlin-xmtcibzvdnjv</link>
                <description>در این مجموعه با برنامه‌نویسی ReativeX و همچنین زیرمجموعه‌های آن RxKotlin, RxJava, RxAndroid آشنایی کامل پیدا خواهیم کرد.این مجموعه بر اساس نسخه پرطرفدار و پراستفاده 2 نوشته شده است، نسخه 3 به تازگی منتشر شده است که در مفاهیم پایه و پیاده‌سازی مشابه همین نسخه می‌باشد.امیدوارم با خوندن این پست‌ها بگی این از اون آموزشی که توی Medium بود خیلی بهتره! هر چند که پست‌های من قبل انتشار توی اینجا، ابتدا توی Medium نوشته می‌شن و اینبار تصمیم گرفتم اولویت انتشار اینجا باشه.ReactiveXReactiveXیک API برای برنامه‌نویسی نامتقارن می‌باشد که از داده‌های قابل مشاهده استفاده می‌کند. ReactiveX ترکیبی از Observer Pattern و Iterator Pattern به همراه مفاهیم Functional Programming می‌باشد.اگر متوجه مفهوم ReactiveX نشدید نگران نباشید از عنوان بعدی همه چیز ساده می‌شود.مفهوم API چیست؟یک رستوران را در نظر بگیرید، این رستوران قطعا شامل یک آشپزخانه برای پخت و تهیه غذا می‌شود. برای اینکه شما غذای خود را از آشپزخانه دریافت کنید چه واسطی این کار را انجام می‌دهد؟ قطعا خود شما به آشپزخانه نمی‌روید تا غذا را دریافت کنید، یا حتی آشپز به سر میز شما با سینی غذا نخواهد آمد، در صورتی که رستورانی با این مشخصات می‌شناسید حتما در قسمت نظرات بیان کنید :) این کار وظیفه واسطی به نام گارسون، مهماندار یا پیش‌خدمت می‌باشد.کلمه API مخفف عبارت Application Programming Interface می‌باشد که معنی واسط برنامه‌نویسی اپلیکیشن را می‌دهد و در طول توسعه اپلیکیشن‌های موبایلی، دسکتاپ و وب همواره ما در حال استفاده از آن‌ها می‌باشیم.لطفا این Interface را با ساختار Interface که در اکثر زبان‌های برنامه‌نویسی وجود دارد اشتباه نگیرید، اینجا Interface به معنی واسط منظور ماست و هیچ نسبتی با زبان‌های برنامه‌نویسی ندارد.در طول توسعه اپلیکیشن‌های موبایلی شما نیاز داشته‌اید که به دیتابیس آنلاین اتصال شوید و اطلاعات را از آن دریافت کنید، چگونه این کار را انجام می‌دهید؟ Rest APIبرنامه‌نویسی نامتقارن چیست؟فرض کنید در یک ایستگاه قطار قدیمی ایستاده‌اید و تمامی مسافران در یک صف پشت هم انتظار می‌کشند تا مامور قطار بلیط آن‌ها را گرفته تا بتوانند سوار قطار شوند. تا زمانی که افراد جلوی شما سوار قطار نشده باشند، شما نمی‌توانید سوار شوید و همچنین افراد قبل از شما نمی‌توانند همزمان یا جلوتر از شما سوار شوند.در برنامه‌نویسی متقارن تا زمانی که خط کد قبلی به صورت کامل اجرا نشده خط بعدی حق اجرا شدن ندارد.نمونه کد برنامه‌نویسی متقارن - Github Gist https://gist.github.com/6220c8eec1d829a51e3d297b55592417#file-sample-kt حالا در نظر بگیرید اگر قرار باشد اپلیکیشن ما یک کار محاسباتی سنگین، دریافت اطلاعات از دیتابیس و یا ارسال اطلاعات کاربر از طریق API را داشته باشد و همزان نیاز باشد که با کلیک کاربر بر روی دکمه عملیات دیگری صورت بگیرد. در این صورت با کلیک شدن دکمه در صورتی که فرآیند محاسباتی سنگین هم در حال انجام باشد کاربر با کندی اپلیکیشن رو به رو خواهد شد.جاوا از Thread (رشته‌) برای انجام برنامه‌نویسی نامتقارن استفاده می‌کند تا کارهای سنگین در پس‌زمینه (Background) انجام شوند. در هر برنامه یک Thread اصلی برای کارهای مربوط به UI و Eventهای آن وجود دارد که در صورت انجام کارهای سنگین بر روی آن با گیرهای اپلیکیشن مواجه می‌شویم.در صورتی که اطلاعاتی در این مورد ندارید بهترین کار Bookmark کردن این صفحه و شروع به آشنایی با مفاهیم Thread - Runnable- Synchronization می‌باشد. پیشنهاد من مطالعه‌ی کتاب Head First Java می‌باشد.کتابخانه Retrofit2 که از شناخته‌ترین‌های دنیای برنامه‌نویسی اندروید می‌باشد به صورت خودکار HTTP Requestهای شما را در پس زمینه و بر روی یک Thread جداگانه اجرا می‌کند. AsyncTask یکی دیگر از نمونه‌های شناخته شده برای انجام کار در Thread جداگانه می‌باشد.نمونه کد برنامه‌نویسی نامتقارن با Thread ها - Github Gistهر بار که کد بالا را اجرا کنید خروجی متفاوتی می‌گیرید به این دلیل که هیچکس جز JVM بر اساس منطق خود نمی‌تواند تصمیم بگیرید که کدام Thread اجرا خواهد شد و چه مدت در حال اجرا خواهد بود.نمونه خروجی کد:Thread: Thread[main,5,main] - 1
Thread: Thread[Thread-1,5,main] - 1
Thread: Thread[Thread-0,5,main] - 1
Thread: Thread[Thread-1,5,main] - 2
Thread: Thread[Thread-1,5,main] - 3
Thread: Thread[Thread-1,5,main] - 4
Thread: Thread[main,5,main] - 2
Thread: Thread[Thread-1,5,main] - 5
Thread: Thread[Thread-0,5,main] - 2
Thread: Thread[Thread-1,5,main] - 6
Thread: Thread[main,5,main] - 3
Thread: Thread[Thread-1,5,main] - 7
Thread: Thread[Thread-0,5,main] - 3
Thread: Thread[Thread-0,5,main] - 4
Thread: Thread[Thread-1,5,main] - 8
Thread: Thread[main,5,main] - 4
Thread: Thread[Thread-1,5,main] - 9
Thread: Thread[Thread-0,5,main] - 5
Thread: Thread[Thread-0,5,main] - 6
Thread: Thread[Thread-0,5,main] - 7
Thread: Thread[Thread-1,5,main] - 10
Thread: Thread[Thread-0,5,main] - 8
Thread: Thread[main,5,main] - 5
Thread: Thread[main,5,main] - 6
Thread: Thread[main,5,main] - 7
Thread: Thread[main,5,main] - 8
Thread: Thread[main,5,main] - 9
Thread: Thread[main,5,main] - 10
Thread: Thread[Thread-0,5,main] - 9
Thread: Thread[Thread-0,5,main] - 10لطفا بحث Thread های جاوایی را با Core و Thread های CPU اشتباه نگرید. بحث این دو کاملا جداست، در جاوا Thread ها را می‌سازیم و JVM از OS برای اجرای آن‌ها کمک می‌گیرد و این OS است که تصمیم میگیرید که کدام Thread بر روی کدام Core از CPU شما و کدام Thread آن CPU اجرا شود.Java Threads != CPU Threadsمفهوم Functional Programming چیست؟قبل از توضیح این مورد نیاز است با دو الگوی برنامه‌نویسی Imperative و Declarative آشنا شویم:فرض کنید با خانواده وارد یک رستوران شیک و شلوغ شده‌اید چند راه برای انتخاب صندلی و مکان نشستن دارید؟ یکی اینکه بگویید من و خانواده آن میز شماره N را می‌خواهیم (Imperative - دستوری) را می‌خواهیم، یا اینکه می‌توانید بگوید لطفا یک میز خانوادگی برای نشستن به ما بدهید (Declarative - اعلانی).سبک برنامه‌نویسی Object-Oriented از نوع دستوری (Imperative) می‌باشد، جاوا، #Cسبک برنامه‌نویسی Functional Programming از نوع اعلانی (Declarative) می‌باشد، SQL، HTMLزبان‌های برنامه‌نویسی جدید همانند Kotlin و Swift و همچنین نسخه‌های جدید Java علاوه بر OOP بودن از سبک Functional هم پشتیبانی می‌کنند.نمونه کد برنامه‌نویسی Functional در Kotlin و نحوه پیاده‌سازی - Github Gistدر ReactiveX به سبک Functional یا همان Declarative (اعلانی) اطلاعات را درخواست می‌کنیم.مفهوم ObserverPattern چیست؟یکی از الگوهای طراحی (Design Pattern) های معروف که در دسته Behavioral Pattern ها قرار می‌گیرد. Behavioral Pattern دسته‌ای از الگوهای طراحی می‌باشند که نحوه به ایجاد راه حلی برای پیاده‌سازی بهینه الگوریتم‌ها و تخصیص وظیفه به هر کدام از Object ها در برنامه می‌پردازند.فرض کنید یک شهر کوچک نشریه‌ای پرطرفدار وجود دارد و برخی از مردم علاقه‌مند به دریافت نسخه جدید آن نشریه در درب منزل هستند. آیا نشریه روزنامه را برای تمامی اعضای آن شهر ارسال خواهد کرد؟ در این صورت بسیاری مردم که خواهان آن نشریه نبوده‌اند ناراضی خواهند بود و پولی بابت آن پرداخت نخواهند کرد. راه حل مناسب‌تر این است که نشریه از مردم بخواهد که خود درخواست عضویت بدهند و هرگاه که دیگر تمایلی به دریافت نسخه‌های جدید را نداشتند عضویت خود را باطل کنند.Subscriber = کسی که عضوی از دریافت‌کننده اطلاعات می‌باشدPublisher = کسی که اطلاعات را به اعضا ارسال می‌کندSubscription = عضویتاصطلاح دیگر Publisher/Subscriber مفهوم Observer (مشاهده‌گر) و Observable (مشاهده‌شونده) می‌باشد.Publisher == ObservableSubscriber == Observerبه رابطه بین Observer/Subscriber با Observable/Publisher کلمه Subscription (عضویت) اختصاص داده شده.تماشاچی‌ها (Observers) بلیط مشاهده نمایش شعبده‌باز (Observable) را تهیه کرده‌اندبرای یادگیری کامل این الگوی طراحی که بسیار توصیه می‌گردد از این مقاله دنبال کنید.مفهوم Iterator Pattern چیست؟یادگیری این Design Pattern به هیچ عنوان واجب نبوده و افراد علاقه‌مند می‌توانند از این مقاله با مفاهیم کامل آن آشنا شوند.این الگوی طراحی برای نحوه پیدا کردن المان‌های یک Iterator (قابل چرخش) استفاده می‌شود.مفهوم RxKotlin چیست؟کتابخانه RxKotlin همان RxJava می‌باشد که برخی Extensionها برای راحتی کار به آن اضافه شده است، در نتیجه تفاوتی چشم‌گیری با هم ندارند. همچنین RxAndroid شامل کلاس‌های اضافه برای کار با RxJava بر روی سیستم عامل Android و استفاده از Main Thread آن می‌باشد.با استفاده از RxKotlin کارهای سنگین مانند خواندن فایل و ذخیره اطلاعات را با استفاده از RxKotlin انجام می‌دهیم. بسیاری از کتابخانه‌های معروف همانند Retrofit و Room از این کتابخانه پشتیبانی می‌کنند.شما می‌توانید از ReactiveX بر روی زبان‌های دیگر نیز استفاده کنید، از جمله:Rx.net (C#)RxJs (JavaScript)RxSwift (Swift)...پست‌های آموزش RxKotlinقسمت اول - Observable رفتن به پستقسمت دوم - انواع Observableهارفتن به پست</description>
                <category>abstractArrow</category>
                <author>abstractArrow</author>
                <pubDate>Thu, 14 May 2020 17:25:58 +0430</pubDate>
            </item>
                    <item>
                <title>آموزش Enum و Sealed کلاس‌ها در Kotlin</title>
                <link>https://virgool.io/@ramtintoosi/eum-vs-sealed-in-kotlin-qwg2lnwuydtg</link>
                <description>مقدمهدر این پست به بررسی کلاس‌های Enum و Sealed و در انتها تفاوت این دو با یکدیگر می‌پردازیم. شما هم احتمالا در هنگام کد نویسی به این نکته برخورد کرده‌اید که گاهی اوقات نیاز است مقادیر ثابت و مشخصی را داخل کد تبادل کنید و  با دو ساختاری که در Kotlin وجود دارد می‌توانید پیاده‌سازی مناسب‌تری داشته باشید. دوستانی که مقالات قبلی من رو دنبال کردن می‌دونن که هدف من مفهومی‌ترین و آسان‌ترین روش برای یادگیری برنامه‌نویسی هستش، در صورت تمایل حتما من رو دنبال کنید. هر لایک شما برای این پست دلگرمی بیشتر برای ارائه مطالب بهتر می‌باشد ;)کلمه Sealed به معنای مهر و موم شده (بسته) است.Enumاگر بخواهیم چهار جهت جغرافیایی را در کد خود ذخیره کنیم و آن‌ها را به فانکشن‌ها پاس دهیم چه راهی را انتخاب می‌کنید؟ ذخیره به عنوان String را انتخاب می‌کنید؟Github Gistobject Direction {
    val NORTH = &amp;quotnorth&amp;quot
    val SOUTH = &amp;quotsouth&amp;quot
    val EAST = &amp;quoteast&amp;quot
    val WEST = &amp;quotwest&amp;quot
}

fun move(direction: String) = when (direction) {
    Direction.NORTH -&gt; {}
    Direction.SOUTH -&gt; {}
    Direction.EAST -&gt; {}
    Direction.WEST -&gt; {}
    else -&gt; {}
}این کد در نگاه اول هیچ مشکلی اجرایی یا منطقی ندارد، ولی چندین دلیل می‌توان ارائه داد که احتمال خطای کدنویسی و عدم کارکرد دلخواه ایجاد خواهد شد.در صورتی که شخصی به جای north نوشته North یا NORTH و ... را به فانکشن move ارسال کند بلاک else اجرا خواهد شد.بلاک else مفهومی ندارد، دلیلی برای وجود آن نیست. در وحله اول اصلا نیازی به صدا زدن این فانکشن بدون ارسال یکی از چهار جهت تعریف شده وجود ندارد.برای حل این چالش ما می‌توانیم از ساختار Enum استفاده کنیم:Github Gistenum class Direction {
    NORTH,
    SOUTH,
    EAST,
    WEST;
}

fun move(direction: Direction) = when (direction) {
    Direction.NORTH -&gt; {}
    Direction.SOUTH -&gt; {}
    Direction.EAST -&gt; {}
    Direction.WEST -&gt; {}
} به هر مقدار درون Enum یک Constant (ثابت) می‌گویند.کلمه Enum مخفف Enumeration به معنای شمارش می‌باشد.حالا که دلیل استفاده از Enum را می‌دانیم، کافی است مفهوم و چند تکنیک را که می‌توانیم با آن‌ها پیاده‌سازی شود بررسی کنیم.ساختار Enumهر مقداری که در داخل یک Enum تعریف می‌شود (مثلا NORTH) یک object که از آن کلاس Enum ارث‌بری کرده محسوب می‌شود.‌در کاتلین ساختار object باعث می‌شود که تنها یک نمونه (instance) از آن کلاس داشته باشیم. در واقع می‌توانیم بگوییم که ساختار object در کاتلین ترکیبی از Singleton و Static جاوا می‌باشد.سینگلتون (Singleton) یکی از الگوهای طراحی (Design Pattern) های پر استفاده می‌باشد که در آن تنها و تنها یک نمونه (شی) از آن کلاس ساخته می‌شود.می‌توانید یک Enum را ساختاری برابر با یک کلاس شامل object در نظر بگیرید:Github Gistenum class Direction {
    NORTH,
    SOUTH,
    EAST,
    WEST;
}

abstract class Direction {
    object NORTH : Direction()
    object SOUTH : Direction()
    object EAST : Direction()
    object WEST : Direction()
}چند تکتیک با EnumGithub Gistenum class PaymentMethod(val balance: Double) {
    CASH(147.50) {
        override fun printFormattedAmount(): String {
            return NumberFormat.getCurrencyInstance(Locale.US).format(balance)
        }
    },
    CREDIT(15.00) {
        override fun printFormattedAmount(): String {
            return &amp;quot$balance&amp;quot
        }
    };

    abstract fun printFormattedAmount(): String
}متغییر balance که به عنوان Property کلاس محسوب می‌شود به Constructor هر Constant اعمال شده است.فانکشن abstract به نام printFormattedAmount هم در هر Constant بازنویسی (Override) شده است.Github Gistfun main() {
    println(&amp;quot+-------------------+&amp;quot)
    PaymentMethod.values().forEach { medthod -&gt;
        println(&amp;quotPayment Method: ${medthod.name} - - - Balance: ${medthod.balance}&amp;quot)
    }
}

enum class PaymentMethod(val balance: Double) {
    CASH(147.50),
    CREDIT(15.00)
}فانکشن values() تمامی Constant ها را در قالب یک Array به شما می‌دهد.پراپرتی name نام String ای آن Constant را برمی‌گرداند.Github Gistfun main() {
    val creditPayment = PaymentMethod.valueOf(&amp;quotCREDIT&amp;quot)
    println(paymentMethod.balance)
    enumValues&lt;PaymentMethod&gt;().forEach { method -&gt;
        println(method)
    }
    val cashPayment: PaymentMethod = enumValueOf&lt;PaymentMethod&gt;(&amp;quotCASH&amp;quot)
    println(paymentMethod.name)
}

enum class PaymentMethod(val balance: Double) {
    CASH(147.50),
    CREDIT(15.00)
}در صورتی که با نام String ای نیاز داشتید Constant را بگیرید از فانکشن valueOf() استفاده کنید. این فانکشن در صورت عدم وجود IllegalArgumentException ایجاد می‌کند و باعث کرش می‌شود.می‌توانید از Kotlin Extension Function های enumValueOf و enumValues هم استفاده کنید.Sealed Classesمی‌توان Sealed Class ها را Enum های پیشرفته معرفی کرد. به دلیل object بودن هر مقدار (Constant) داخل Enum نمی‌توانید چندین نمونه از آن‌ها بگیرید. فرض کنید دو کاربر داریم که برای هر کدام می‌خواهیم یک روش پرداخت با موجودی متفاوت بسازیم:Github Gistfun main() {
    val user1 = PaymentMethod.CASH
    val user2 = PaymentMethod.CASH
    user1.balance = 2_000.00
    println(&amp;quot+-----------------------------------+&amp;quot)
    println(user1.balance) //Prints 2000.0
    println(user2.balance) //Also prints 2000.0
}

enum class PaymentMethod(var balance: Double) {
    CASH(147.50),
    CREDIT(15.00)
}برای حل این مشکل از Sealed Class ها استفاده می‌کنیم که دارای ویژگی‌های زیر می‌باشند:یک کلاس Sealed را تنها اعضای آن می‌توانند ارث بری (Extend) کنند. کلاس Sealed یک کلاس abstract می‌باشد که اعضای آن به عنوان Concrete کلاس شناخته می‌شوند.کلاس abstract کلاسی است که نمی‌توان از آن شی (Object) ساخت و به همین دلیل کلاسی که از آن ارث بری می‌کند و فانکشن‌ها و پراپرتی‌های abstract (بدون بدنه) آن را پیاده سازی می‌کند Concrete گفته می‌شود.Github Gistfun main() {
    val user1 = PaymentMethod.CASH(2_000.0)
    val user2 = PaymentMethod.CASH(9_000.0)
    
    println(&amp;quot+---------------------+&amp;quot)
    println(user1.amount)
    println(user2.amount)
}

sealed class PaymentMethod(var amount: Double) {
    class CASH(cashAmount: Double) : PaymentMethod(cashAmount)
    class CREDIT(credit: Double) : PaymentMethod(credit)
    data class Crypto(val name: String, val balance: Double) : PaymentMethod(balance)
    //object Gift : PaymentMethod(0.0)
}در یک Sealed Class می‌توانید هر نوع ساختاری (data class, class, and object) را پیاده‌سازی کنید.در نسخه‌های جدیدتر کاتلین نیازی نیست که کلاس ارث برنده داخل بدنه Sealed Class باشد و کافی است که هر دو داخل یک فایل قرار داشته باشند.</description>
                <category>abstractArrow</category>
                <author>abstractArrow</author>
                <pubDate>Thu, 07 May 2020 20:41:02 +0430</pubDate>
            </item>
                    <item>
                <title>صفر تا صد dp در Android</title>
                <link>https://virgool.io/@ramtintoosi/android-dp-fully-explained-li92jb8l6oh8</link>
                <description>در این پست به مفاهیم کامل پیکسل (Pixel)، واحد dp و sp خواهیم پرداخت. خواندن این مقاله برای توسعه‌دهندگان اندروید در هر سطحی و همچین طراحان گرافیکی که قصد تولید محتوی برای این پلتفرم دارند توصیه می‌شود. در هنگام کار با اکثر همکاران عدم درک اولیه از برخی موارد در اندروید برای من بسیار تعجب برانگیز است! به همین دلیل در هر پست هدف من درک موارد مهم و تمرین کردن آن با شما است تا بتوانید با خواندن مقالات رسمی و قدرت ذهنی خود آن را گسترش دهید و پیاده‌سازی کنید.نسخه انگلیسی مقاله:لینک Mediumکیفیت عکس مناسب در اندروید چگونه به دست می‌آید؟پیکسلتمامی صفحات نمایش که اطلاعات بر روی آن نمایش داده می‌شود، از اجزای ریز مربع شکل به نام پیکسل تشکیل شده‌اند. بزرگی یا کوچکی این واحد‌ها به تعداد پیکسل‌ها و اندازه صفحه نمایش مرتبط است، اگر غیر این است چگونه صفحه نمایش یک موبایل با رزولوشن 1080x1920 با صفحه نمایش یک کامپیتور خانگی با رزولوشن 1920x1080 هر دو دارای تعداد پیکسل‌های یکسانی هستند؟ این دو صفحه دارای اندازه متفاوت پیکسل و در نتیجه غلظت‌های مختلف پیکسلی هستند.یک پیکسل (مربع سفید)منظور از رزولوشن (Resolution) چیست؟به تصویر زیر توجه کنید:4 x 4 = 16عرض این مربع 4 پیکسل کشیده و طول آن 4 پیکسل کشیده می‌باشد و مجموعا دارای 16 پیکسل می‌باشد، به دو عدد 4x4 میزان رزولوشن آن گفته می‌شود.منظور از غلظت (Density) چیست؟غلظت نمایش دهنده میزان وجود چیزی در فضای مشخص می‌باشد.در مبحث کار با صفحه‌های نمایش ما از واحد پیکسل در هر (یک) اینچ (Pixel Per Inch) استفاده می‌کنیم.این مربع دارای غلظت چهار پیکسل در هر اینچ می‌باشد.این مربع دارای غلظت دو پیکسل در هر اینچ می‌باشد.این مربع دارای غلظت دو پکیسل در هر اینچ می‌باشد.پیکسل در (یک) اینچ با نماد ppi نمایش داده می‌شود ولی در پلتفرم اندروید از نماد dpi که به معنای نقطه در هر اینچ (dots per inch) است، استفاده می‌شود. پیکسل مربع است و نقطه نیست، دلیل استفاده از این نماد کمی عجیب است، دوستانی که Photoshop کار کردن با نماد ppi آشنا هستند.محاسبه غلظت پیکسلی دستگاهگوشی خود را برای یافتن مواردی که در بالا گفته شد آماده کنید. در این آموزش من از دستگاه فیزیکی خود با مشخصات زیر استفاده می‌کنم:Galaxy A5 2017
Screen Resolution: 1080x1920
Physical Size: 5.2 inchسایز صفحه نمایش هر دستگاهی معمولا به صورت مورب به شما داده می‌شود.طبق قوانین فیثاغورث برای محاسبه تعداد پیکسل‌های موجود بر روی خط فرضی 5.2 اینچی داریم:c = ~ 2200 (تعداد پیکسل‌ها بر روی خط 5.2 اینچی)
2200 / 5.2 = ~ 424 dpi (غلظت دستگاه)DP و SPنمونه اولدر این قسمت می‌خواهیم دکمه‌ای که را بر روی دو صفحه نمایش مختلف با غلظت‌های متفاوت ولی رزولوشن یکسان نمایش دهیم:رزولوشن برابر | غلظت متفاوتحجم دکمه بر روی مربع راست کمتر از دکمه سمت چپ می‌باشد. اگر مربع ما کوچکتر از قبل شود نتیجه چه خواهد شد؟ آیا کاربر می‌تواند به راحتی بر روی آن کلیک کند؟ برای حل این مشکل از واحدی برای ثابت نگه داشتن حجم دکمه و هر View دیگری بر روی اندروید استفاده می‌کنیم که به غلظت پیکسلی توجهی ندارد:dp/dip = density-independent pixel = پیکسل فارغ از غلظت sp = scale-independent pixel = پیکسل فارغ از تناسبواحد dp که برای تمامی View ها استفاده می‌شود توسط فرمول زیر محاسبه می‌شود:dp = px * (160 / dpi)دلیل وجود عدد 160 در این معادله چیست؟در اندروید 160 غلظت پیکسلی است که در آن هر یک پیکسل برابر یک dp می‌باشد. به این عدد غلظت پایه هم گفته می‌شود.واحد sp چیست؟این واحد دقیقا همانند dp می‌باشد ولی فقط برای سایز نوشته‌ها در اندروید استفاده می‌شود، تنها تفاوت آن با dp این است که اگر کاربر در تنظیمات گوشی خود سایز نوشته‌های سیستم عامل را تغییر داده باشد در اپلیکیشن شما هم اعمال خواهد شد.با فرض اینکه مربع راست دارای غلظت پیکسلی 320 و مربع سمت چپ دارای غلظت پیکسلی 160 می‌باشند  با جایگذاری عدد 1dp در معامله میزان پیکسل مورد نیاز بر روی هر صفحه نمایش برای ثابت نگه داشتن سایز دکمه را محاسبه می‌کنیم:مربع سمت راست:1dp = 2px =&gt; (2x2) px * 2 = (4x4) px سایز دکمهمربع سمت چپ:1dp = 1px =&gt; (2x2) px * 1 = (2x2) px سایز دکمهدکمه سمت راست حجم برابری با دکمه سمت چپ دارد.با توجه به نتیجه به دست آمده متوجه می‌شویم که با افزایش غلظت پیکسلی بر روی صفحه نمایش تعداد پیکسل‌های Image یا View مورد نظر افزایش می‌یابد تا بر روی همه صفحات نمایش اندازه یکسانی داشته باشیم.نمونه دومبرای نمایش یک عکس با رزولوشن 4x2 با نتیجه زیر رو به رو خواهیم شد:اندازه برابر | غلظت متفاوتطراحان همیشه با واحد پیکسل تصاویر را تولید و برای شما ارسال می‌کنند. برای حل این مشکل اندروید برای ثابت نگه داشتن حجم تصاویر از پوشه‌هایی استفاده می‌کند که دارای غلظت پیکسل‌های متفاوتی هستند:ldpi: 0.75x or 75% (~120 dpi) (این غلظت از دور خارج شده است)mdpi: 1x or 100% (~160 dpi)hdpi: 1.5x or 150% (~240 dpi)xhdpi: 2x or 200% (~320 dpi)xxhdpi: 3x or 300% (~480 dpi)xxxhdpi: 4x or 400% (~640 dpi)nodpi (فاقد غلظت)تصاویر همیشه در پوشه drawable قرار می‌گیرند، برای ساخت این پوشه با غلظت‌های متفاوت موارد بالا را به عنوان پسوند آن اضافه می‌کنیم، مثلا drawable-xhdpiمعنای این پوشه‌ها چیست؟با قرار دادن تصویر خود در این پوشه‌ها به اندروید اعلام می‌کنید من سایز تصویر خودم را با توجه به غلظت مورد نظر تغییر داده‌ام و لطفا هنگام استفاده از تصویر آن را از نظر اندازه تغییر نده!اگر من عکسی با سایز 24x24 پیکسل در mdpi قرار دهم پس باید در سایر پوشه‌ها:hdpi = 32x32 px (x1.5)xhdpi = 48x48 px (x2)xxhdpi = 72x72 px (x3)اگر فقط تصویر خودم را در پوشه mdpi قرار دهم چه اتفاقی می‌افتد؟اگر تصویر خود را در یکی از پوشه‌ها قرار ندهید از نزدیکترین پوشه‌ دریافت و تغییر سایز داده می‌شود.فرآیند تغییر سایز شامل عملیات زمان‌بر و همچنین احتمال کاهش کیفیت عکس می‌شود، سعی کنید تصاویر خود را برای همه پوشه‌ها آماده کنید.اگر عکس 24x24 خود را در پوشه mdpi قرار دهم و گوشی کاربری دارای غلظت xhdpi باشد، سیستم عامل با تکنیک‌های پردازش تصویر تعداد پیکسل‌های آن را به 48x48 می‌رساند.پوشه drawable خام نیز همانند drawable-mdpi دارای غلظت پایه (160dpi) می‌باشد.اگر تصویر خود را فقط در پوشه nodpi قرار دهم چه اتفاقی خواهد افتاد؟تصاویری که در این پوشه قرار دارند به همان سایز پیکسلی وارد برنامه خواهند شد، برای جلوگیری از ارور معروف OutOfMemory بهتر است که قبل از وارد کردن تصویر به مموری آن را تغییر اندازه دهید.با دو برابر کردن پیکسل‌های تصویر چالش بر طرف می‌شوددر پشت غلظت پیکسلی هر پوشه علامتی با نشان ~ دیده می‌شود و به این معناست که این اعداد حدودی می‌باشند، دستگاه شما ممکن است عددی نزدیک به این غلظت‌ها داشته باشد. این که تصویر مورد نظر برای دستگاه شما از کدام پوشه دریافت می‌شود بستگی به نظر سازنده دستگاه دارد، مثلا اگر غلظت پیکسلی شما برابر 390 باشد ممکن است در زمره پوشه xhdpi یا xxhdpi قرار بگیرید و میزان scale شدن تصویر هم عددی به غیر از اعداد داده شده باشد.دسترسی به مشخصات دستگاهGithub Gistval density = resources.displayMetrics.density
val densityDpi = resources.displayMetrics.densityDpi
val heightPixels = resources.displayMetrics.heightPixels
val widthPixels = resources.displayMetrics.widthPixels 
val scaledDensity = resources.displayMetrics.scaledDensity</description>
                <category>abstractArrow</category>
                <author>abstractArrow</author>
                <pubDate>Fri, 01 May 2020 20:55:40 +0430</pubDate>
            </item>
                    <item>
                <title>خواندن/نوشتن فایل در اندروید (Android Storage I/O)</title>
                <link>https://virgool.io/@ramtintoosi/%D8%AE%D9%88%D8%A7%D9%86%D8%AF%D9%86%D9%86%D9%88%D8%B4%D8%AA%D9%86-%D9%81%D8%A7%DB%8C%D9%84-%D8%AF%D8%B1-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-android-storage-io-h3ng74wxn4fa</link>
                <description>مقدمهدر این پست قصد یادگیری مفهومی و مناسب از عملیات خواندن/نوشتن (Input/Output) را از رم به دیسک و بالعکس را داریم. احتمالا شما هم در هنگام انجام پروژه‌ها با هرگونه سطح چالش با این مسئله مواجه شده‌اید که نیاز بوده فایلی را در دیسک (مموری کارد) اندروید ذخیره کنید یا آن را وارد اپلیکیشن خود کنید.لیست کلمات و معانی آن از نظر نویسنده:رم = Ramدیسک = Android Memory Cardخواندن/نوشتن = Input/Outputدریافت سمپل کد برای پروژه:لینک گیت‌هابنسخه انگلیسی مقاله:لینک مدیومآشنایی با مفاهیم اولیهمنظور از I/O چیست؟Input = خواندن اطلاعات از دستگاه فیزیکی و انتقال آن به رم Output = انتقال اطلاعات موجود در رم به دستگاه فیزیکی و ذخیره آنتمامی کلاس‌هایی که ما در این پست آموزش استفاده از آن‌ها را یاد می‌گیریم در پکیج java.io قرار گرفته‌اند.دستگاه فیزیکی چیست؟کیبورد، صفحه نمایش و دیسک همگی مثال‌های دستگاه‌های فیزیکی می‌باشند.در این پست هدف ما یادگیری ارتباط بین دیسک و رم می‌باشد.منظور از Stream چیست؟استریم (جریان داده) عبارت است از یک پل ارتباطی که بین دستگاه فیزیکی و رم برای کمک به تبادل اطلاعات صورت می‌گیرد.جاوا از دو نوع استریم پشتیبانی می‌کند:Byte Stream = دریافت و ارسال اطلاعات به صورت بایتCharacter Stream = دریافت و ارسال اطلاعات به صورت نوشتهبرای ذخیره/خواندن فایل‌های نوشتاری (Text) از Character Stream و برای هر نوع فایل دیگر از جمله عکس‌ها ، ویدیو و ... از Byte Stream استفاده می‌کنیم.کلاس‌های زیر مجموعه جریان‌های داده در نمودار بالا هر چهار کلاس نمایش داده شده (مستطیل‌ها) از نوع Abstract می‌باشند.مفهوم Abstract در Java و Kotlin مربوط به کلاسی می‌باشد که توانایی ایجاد نمونه (شی) از خود نداشته و حتما  نیاز است که کلاسی از آن ارث‌بری (Extend) کند.با توجه به مفهوم بالا نیاز داریم که از Subclass های آن‌ها استفاده کنیم.FileReader = خواندن فایل نوشتاریFileWriter = ذخیره فایل نوشتاریFileInputStream = خواندن فایلFileOutputStream = ذخیره فایلکلاس File برای کار با فایل‌ها و پوشه‌هاکلاسی که به شما تنها اجازه دسترسی به اطلاعات فایل‌های درون دیسک را می‌دهد، اطلاعاتی همچون محل ذخیره، نوع و حجم آن. می‌توان این کلاس را مثل یک کاغذ کادویی به دور یک هدیه در نظر گرفت، کاغذ کادویی شامل شکل و اندازه، محل قرارگیری کادو می‌باشد ولی خود هدیه نیست.پیش به سوی انجام عملیاتذخیره‌سازی  فایل نوشتاری ... ولی با یک چالش!Github Gistval file = File&#40;filesDir, &amp;quothello.txt&amp;quot&#41;
val fw = FileWriter(file)
fw.write(&amp;quotHello&amp;quot)
fw.write(&amp;quot\n&amp;quot)
fw.write(&amp;quotWorld!&amp;quot)
fw.close()دلیل بستن  FileWriter چیست؟در هنگام کار با کلاس‌های I/O برای نهایی شدن عملیات خواندن/نوشتن و آزاد شدن منابع تحت تسلط آن‌ها حتما باید آن را ببندید، در غیر این صورت عملیات نهایی نمی‌شود و در نتیجه فایل شما ساخته نمی‌شود.در صورت نیاز به انجام عملیات بدون بستن استریم می‌توانید از فانکشن flush به جای close استفاده کنید.در صورتی که نحوه دسترسی به فایل ذخیره شده در دیسک را نمی‌دانید، می‌توانید با استفاده از راهنمای انتهای مقاله آن را یاد بگیرید.در اینجا یک مشکل سرعت انجام عملیات داریم! برای ذخیره سازی تک تک کاراکتر‌های‌های نیاز است که به سیستم‌عامل دستور داده شود که آن را بر روی دیسک (مموری کارد) ذخیره کند.مفهوم Buffer چیست؟بافر قسمتی از رم می‌باشد که اطلاعات را قبل از خواندن/نوشتن در خود ذخیره می‌کند تا سرعت عملیات را افزایش دهد. وقتی بافر پر شد حالا تنها در یک قدم اطلاعات ارسال/دریافت می‌شوند و دیگر نیازی به فراخوانی‌های مجدد سیستم‌عامل نیست. بدون استفاده از Buffer برای ذخیره‌سازی 500 کاراکتر نیاز به 500 فراخوانی سیستم‌عامل وجود دارد.کلمه Buffer در معنای لغوی به معنای میانگیر می‌باشد.BufferedWriter = برای ذخیره کردن فایل‌های نوشتاریBufferedReader = برای خواندن فایل‌های نوشتاریBufferedOutputStream = برای ذخیره فایل‌هاBufferedInputStream = برای خواندن فایل‌هاذخیره فایل نوشتاری ... روش بهینهGithub Gistval file = File&#40;filesDir, &amp;quothello.txt&amp;quot&#41;
val fw = FileWriter(file)
val bw = BufferedWriter(fw)
bw.write(&amp;quotHello&amp;quot)
bw.newLine()
bw.write(&amp;quotWorld!&amp;quot)
bw.close()چرا FileWriter را به عنوان ورودی BufferedWriter دادیم؟کلاس‌های استریم پکیج java.io یا از نوع اتصالی (Connection) و یا از نوع زنجیری (Chain) می‌باشند. Connection Stream = کلاس‌هایی که مستقیما به منبع اطلاعات متصل می‌شوندChain Stream = کلاس‌هایی که به استریم‌های اتصالی زنجیر می‌شوند تا تغییری در عملیات صورت گیردنحوه کار کرد استریم‌ها با یکدیگربا بستن بالاترین استریم باقی نیز به صورت خودکار بسته خواهند شد، پس با بستن BufferedWriter دیگر نیازی به بستن FileWriter به صورت جداگانه نداریم.جاوا از الگوی طراحی‌ای (Design Pattern) به نام Decorator برای اتصال این کلاس‌ها به هم استفاده می‌کند. با ترکیب این کلاس‌ها با یکدیگر می‌توان کارایی کلاس‌های استریم را تغییر داد.خواندن فایل نوشتاریGihub Gistval file = File&#40;filesDir, &amp;quothello.txt&amp;quot&#41;
val fr = FileReader(file)
val br = BufferedReader(fr)
var line: String? = &amp;quot&amp;quot
val sb = StringBuilder()
while (br.readLine().also { line = it } != null) {
    sb.append(line + &amp;quot\n&amp;quot)
}
bis.close()توضیحاتی در مورد این کدکلاس BufferReader به ما نوشته‌ها رو خط به خط میده در نتیجه در داخل یک حلقه تا زمانی که خط‌ها به پایان نرسیدن اون‌ها رو به StringBuilder اضافه می‌کنیم.فانکشن .also هم یکی از Scope Function های کاتلین هستش که بعد از انجام کاری (خواندن خط در این حالت) کار دیگه ای رو هم انجام می‌ده بدون اینکه تغییری روی مقدار قبلی بزاره.خط رو بخون و همچنین (also) اون رو داخل متغییر line ذخیره کن بدون اینکه تاثیری روی مقدارش بزاری و حالا چک کن خطی که خوندی null نباشه.دیاگرام کلاس‌های مهم I/Oکلاس‌های Byte Streamکلاس‌های Character Streamخواندن/نوشتن Object ها (Serialization/Deserialization)در این مرحله با Byte Stream ها آشنا می‌شویم.منظور از Serialization و Deserialization چیست؟به عملیات تبدیل یک شی (Object) به فایل برای ذخیره وضعیت آن شی Serialization گفته می‌شود.در صورتی که فایل را به حالت شی (Object) بودن آن برگردانیم این عمل Deserialization نامیده می‌شود.در پلتفرم اندروید به جای Serialization استفاده از Parcelable برای افزایش سرعت این فرآیند توصیه می‌شود.val file = File&#40;filesDir, &amp;quothello.txt&amp;quot&#41;
val person = Person(&amp;quotKeanu Reeves&amp;quot, 55)
val fos = FileOutputStream(file)
val bos = BufferedOutputStream(fos)
val oos = ObjectOutputStream(bos)
oos.writeObject(person)
oos.close() 

val fis = FileInputStream(file)
val bis = BufferedInputStream(fis)
val ois = ObjectInputStream(bis)
val revivedPerson = ois.readObject() as Person
ois.close()دلیل استفاده از ObjectInputStream و ObjectOutputStream چیست؟در مبحث نوع اتصال استریم‌ها متوجه شدیم که استریم‌های زنجیری (Chain Streams) برای افزودن عملکرد به استریم‌های اتصالی (Connection Stream) وصل می‌شوند. در اینجا هم از ObjectOutputStream برای تبدیل شی (Object) مورد نظر به بایت‌‌ها، برای ذخیره کردن در فایل هستیم. کاربرد ObjectInputStream هم بازگرداندن این فایل‌ها به شی‌ مورد نظر می‌باشد.کار با Bitmap (تصاویر)این بار تصویری که در پوشه drawable قرار دارد را به عنوان فایل ذخیره و سپس آن را در اپلیکیشن نمایش خواهیم داد. از کلاس BitmapFactory برای وارد کردن عکس از پوشه drawable به داخل مموری (اپلیکیشن) و همچنین وارد کردن فایل تصویر به داخل مموری استفاده شده است. Bitmap.compress# برای تبدیل کردن تصویر موجود در مموری به بایت‌های قابل ذخیره در فایل استفاده می‌شود.Github Gistval imageFile = File&#40;filesDir, &amp;quotimage.jpeg&amp;quot&#41;
val fos = FileOutputStream(imageFile)
val bos = BufferedOutputStream(fos)
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.profile)
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos)
bos.close()
bitmap.recycle()

val fis = FileInputStream(imageFile)
val bis = BufferedInputStream(fis)
val  imageBitmap = BitmapFactory.decodeStream(bis)
bis.close()
image_view.setImageBitmap(imageBitmap)انجام عملیات I/O به سبک Kotlin Extensionsبا استفاده از Extension های موجود بر روی File می‌توانید عملیات I/O را کم دردسرتر انجام دهید.Github Gistfile.bufferedWriter().use { out -&gt;
    out.write(&amp;quotHell World!&amp;quot)
    out.newLine()
    out.write(&amp;quotHello Kotlin!&amp;quot)
}

val br = file.bufferedReader()
val content = br.readText()
br.close()در کاتلین هنگام استفاده از بلاک use دیگر نیازی به بستن (close) استریم نداریم و به صورت خودکار بسته خواهد شد.اگر نیاز به اضافه کردن کاراکتر به فایل موجود در دیسک داشتم چکار کنم؟Github Gist//true = perform appending
FileOutputStream(file, true).bufferedWriter().use { out -&gt;
    out.newLine()
    out.write(&amp;quotHello World!&amp;quot)
}
//not recommanded, uses no buffer
//appendText() uses .use{}, so closes itself.
file.appendText(&amp;quotAppend this text to file.&amp;quot)راهنمادسترسی به محل ذخیره فایل مثال‌هادر این مقاله من از ذخیره بی‌دردسر فایل در حافظه Internal Storage استفاده کردم، این حافظه برای اپلیکیشن شما خصوصی می‌باشد و سایر اپلکیشن‌ها از جمله File Manager هم به آن دسترسی ندارد. برای مشاهده فایل‌ها می‌توان از طریق Device File Explorer اندروید استادیو اقدام کنیم:View -&gt; Tool Windows -&gt; Device File Explorerبعد از باز شدن پنجره این قسمت در سمت راست صفحه به مسیر زیر بروید:data -&gt; data -&gt; com.example.app -&gt; filesبه جای com.example.app نام پکیج برنامه خود را جستجو کنید.</description>
                <category>abstractArrow</category>
                <author>abstractArrow</author>
                <pubDate>Sun, 26 Apr 2020 15:13:05 +0430</pubDate>
            </item>
            </channel>
</rss>