<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های حسام درویشیان</title>
        <link>https://virgool.io/feed/@darvishiyan</link>
        <description>Android Engineer at Adevinta</description>
        <language>fa</language>
        <pubDate>2026-06-07 10:00:19</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/14509/avatar/6sOmPB.jpeg?height=120&amp;width=120</url>
            <title>حسام درویشیان</title>
            <link>https://virgool.io/@darvishiyan</link>
        </image>

                    <item>
                <title>چطوری با KSP کمتر کد بنویسیم</title>
                <link>https://virgool.io/@darvishiyan/%DA%86%D8%B7%D9%88%D8%B1%DB%8C-%D8%A8%D8%A7-ksp-%DA%A9%D9%85%D8%AA%D8%B1-%DA%A9%D8%AF-%D8%A8%D9%86%D9%88%DB%8C%D8%B3%DB%8C%D9%85-znf8lfspd0ua</link>
                <description>توی این مقاله می‌خواییم در قالب حل یک مسئله ببینیم چقدر راحت می‌تونیم با استفاده از KSP، کدهای تکراری رو به صورت خودکار تولید کنیم و یکسری از چالش‌ها و راه‌کارها رو با هم ببرسی کنیم.قبل از شروع:- یک: annotation ها یکسری متادیتا هستن که هیچ تاثیر بر روی فرایند اجرای کد (runtime) ندارن.- دو: annotation processing یک فرایند کامپایل تایم هستش و تاثیری بر سرعت اجرای برنامه نداره! ولی باعث افزایش زمان کامپایل می‌شه.- سه: ما این رو روی اندروید می‌نویسیم ولی به صورت کلی اگه با کاتلین برنامه می‌نویسین، پلتفرم فرقی نداره.فرض کنید data class زیر رو داریم. https://gist.github.com/Darvishiyan/a87240ca6d9e322000a3bb12ddbae8d0 می‌خواییم به صورت خودکار بر اساس الگوی builder، یک کلاس builder مثل کلاس زیر برای کلاسمون ایجاد کنیم. https://gist.github.com/Darvishiyan/d330d73c7ec11ec9ed1664de5fa3d61f اگه به کد دقت کنید خطای زمان کامپایل داره، برای اینکه پراپرتی های data classمون غیرقابل تغییر هستن. برای رفع این مشکل ما باید به صورت خودکار یک کلاس با اشیای تغییر پذیر ایجاد ‌کنیم. مثل کلاس زیر: https://gist.github.com/Darvishiyan/92ca6d98be5cd0af68f25cc55dfff914 و انتظار داریم که کد کلاس builderمون هم به کد زیر تغییر کنه. https://gist.github.com/Darvishiyan/0e8e0d5ac5303278a30e33fb539f7301 ما توی کاتلین راهکار هایی داریم که نیازی به پیاده‌سازی الگوی builder نداریم. هدف این مثال، آموزش راحتتر KSP و ارائه راهکاری هایی برای بعضی شرایط خاص هستش.پیاده‌سازی:برای این کار سه تا ماژول لازم داریم.ماژول annotations: برای تعریف annotationهامون هستشماژول processor: کدهای ما رو تولید می‌کنه.ماژول app: برای استفاده و تست annotationمونماژول annotations:برای اینکار باید دوتا annotation class زیر رو بسازیم.  https://gist.github.com/Darvishiyan/2e3f8e82a0075701719b9b7841de0f42 ساختار ماژول annotations کلاس AutoBuilder برای این هستش که data class هایی مورد نظر رو مشخص کنیم. و کلاس BuilderProperty برای مشخص کردن پراپرتی هایی که می‌خواییم متد جدا گانه داشته باشند. و پارامتر flexible هم مشخص می‌کنه که آیا ما می‌خواییم کلاسی با اشیای تغییر پذیر ایجاد کنیم یا نه.بعد از نوشتن این annotation ها، کلاس Person به شکل زیر تغییر می‌کنه. https://gist.github.com/Darvishiyan/93364cb9f4ff20468649413d68f5d41a ماژول processor:اول باید classpath زیر رو به پروژتون اضافه کنید.classpath &#039;org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.0&#039;بعد باید پلاگین زیر رو به فایل gradle اصلی پروژه اضافه کنید.id &#039;com.google.devtools.ksp&#039; version &#039;1.7.0-1.0.6&#039; apply falseو بعد باید depenencyهای زیر رو به فایل gradle ماژول processor اضافه کنیم.implementation project(path: &#039;:annotations&#039;)
implementation &amp;quotcom.google.devtools.ksp:symbol-processing-api:1.7.0-1.0.6&amp;quotپروژه رو sync و build می‌کنیم و یک کلاس درست می‌کنیم و اینترفیس SymbolProcessorProvider رو پیاده‌سازی می‌کنیم. https://gist.github.com/Darvishiyan/18e15073e00d9f430243ecc91f2ed46c حالا برای معرفی Providerمون باید آدرس زیر رو بسازیم.processor/src/main/resources/META-INF/servicesیک فایل با نام زیر بسازیم.com.google.devtools.ksp.processing.SymbolProcessorProviderو توی اون اسم Providerمون رو به همراه package nameش وارد می‌کنیم.your.domain.processor.AutoBuilderProcessorProviderهمونجوری که دیدید ما توی کلاس AutoBuilderProcessorProvider به یک شی از نوع SymbolProcessor نیاز داشتیم، برای این کار یک کلاس می‌سازیم و اینترفیس SymbolProcessor رو پیاده‌سازی می‌کنیم.  https://gist.github.com/Darvishiyan/f91eb4e54c1d7cf76fc64246398a0cc4 همچنین TODO کلاس AutoBuilderProcessorProvider رو هم پیاده‌سازی می‌کنیم. https://gist.github.com/Darvishiyan/1efa65bc389437bde06228ec9a747db3 در این مرحله باید متد processمون رو پیاده‌سازی کنیم.در ابتدا باید اشیایی که انوتیشن ما رو دارن رو پیدا کنیم.val symbols: Sequence&lt;KSClassDeclaration&gt; = resolver
    .getSymbolsWithAnnotation(AutoBuilder::class.java.name)
    .filterIsInstance&lt;KSClassDeclaration&gt;()حالا باید بررسی کینم که آیا شی ای انوتیشن ما رو داره یا نه، به خاطر اینکه که نوع شی ما Sequence هستش ما با استفاده از متد hasNext توی اینترفیس Iterator این کار رو انجام می‌دیم.if (symbols.iterator().hasNext().not()) return emptyList()حالا باید شروع به پردازش اشیایی بکنیم که انوتیشن ما رو دارن. اما قبل از اون من چندتا استنشن فانکشن مفید اینجا میزارم. که جلوتر کمکمون می‌کنن کد خواناتری داشته باشیم. https://gist.github.com/Darvishiyan/d71834877ca617f8fafc387d74f56622 به عنوان یک توضیح کوچیک متد getAnnotation بر اساس نام، انوتیشن ما رو برمیگردونه و متد getParameterValue مقدار پارامتر مورد نظر ما رو بر می‌گردونه، متد containsIgnoreCase بررسی می‌کنه که شی ای که انوتیشن ما رو داره یک Modifier خاص رو داره یا نه و متد hasAnnotation بررسی می‌کنه که یک شی انوتیشن ما رو داره یا نه. فقط توجه کنید که باید نام پارامتر رو به صورت رشته ارسال کنیم.برای پردازش اشیایی که انوتیشن ما رو دارن فقط کافیه با یک forEach ساده، شی ای که بالاتر درست کرده بودیم رو پیمایش کنیم.symbols.forEach { symbol -&gt;
    // …
}در ابتدا باید بررسی کنیم که آیا شی ما data class هستش یا نه.if (symbol.modifiers.containsIgnoreCase(&amp;quotdata&amp;quot).not()) {
    logger.error(&amp;quotYou should write this function on a data class&amp;quot, symbol)
    return emptyList()
}همونجوری که می‌دونید هر شی می‌تونه چندتا انوتیشن بگیره، ما برای دسترسی به پارامتری که به انوتیشن فرستادیم باید از کد زیر استفاده کنیم که از دوتا اکستنشن فانکشن بالا استفاده می‌کنه.val flexible = symbol.annotations.getAnnotation(AutoBuilder::class.java.simpleName)
    .arguments.getParameterValue&lt;Boolean&gt;(&amp;quotflexible&amp;quot)کد بالا یک اشکال داره و اون استفاده از رشته هستش، این کار احتمال اشتباه رو بالا می‌بره. برای این ما باید کد AutoBuilder رو به کد زیر تغییر بدیم. https://gist.github.com/Darvishiyan/242936f9da2f5e27dc4979d0e61c9e0d و کدی که مشکل داشت رو هم به کد زیر تغییر می‌دیم.val flexible = symbol.annotations.getAnnotation(AutoBuilder::class.java.simpleName)
    .arguments.getParameterValue&lt;Boolean&gt;(AutoBuilder.flexible) حتما یادتون باشه لیست انوتیشن‌هایی که پردازش کردین رو return کنید تا دوباره پردازش نشن.خوب در این مرحله باید اشیایی که انوتیشن مورد نظر ما رو دارن رو پردازش کنیم برای این کار لازمه که اینترفیس KSVisitor رو پیاده‌سازی کنیم، این اینترفیس دوتا ورودی رو به صورت جنریک می‌گیره.ورود اول D: شی‌ای هست که به صورت ورودی ارسال می‌شه یا در مراحل پراسس ساخته ‌می‌شه.ورودی دوم R: شی‌ای هستش انتظار داریم که کلاسمون برای ما برگردونه.این اینترفیس یک سری پیاده سازی‌ها داره، چون برای مثال ما شی ورودی و خروجی Unit هستش از KSVisitorVoid استفاده می‌کنیم.در رابطه با این شی هم بگم که کارش به این صورت هستش که متد متناظر با شی شما رو صدا میزنه یعنی که انوتیشن رو روی class نوشته باشیم متد visitClassDeclaration رو صدا می‌زنه و اگه اون رو روی property نوشته ب اشیم متد visitPropertyDeclaration رو صدا می‌زنه.در اینجا ما فقط Visitor کلاس builder رو پیاده‌سازی می‌کنیم، Visitor کلاس تغییر پذیرمون رو توی سورس کد میزارم، اگه هر سوالی داشتید بپرسید خوشحال میشم اگه بلد باشم جواب بدم یا متن رو بروز می‌کنم. یک کلاس به اسم AutoBuilderVisitor می‌سازیم و کلاس KSVisitorVoid رو توسعه می‌دیم، طبق توضیحی که دادم، ما باید متد visitClassDeclaration رو بازنویسی کنیم. https://gist.github.com/Darvishiyan/2b8dd49d955f3bd155fbd27063b79736 حالا  باید فایلمون رو بسازیم.val file: OutputStream = codeGenerator.createNewFile&#40;
    dependencies = Dependencies(false&#41;, 
    packageName = [Package Name],
    fileName = [File Name]
)برای جلوگیری از دوباره پردازش شدن و دوباره ساخته شدن فایل‌هایی که لازم نیستن از تکنیک ‍Incremental processing﻿ استفاده می‌کنیم که توی این مقاله قصد نداریم بهش بپردازیم. فقط همین قدر می‌گم که هدف پارامتر dependencies همین هستش. برای اطلاعات بیشتر می‌تونید به لینک زیر سر بزنید. https://kotlinlang.org/docs/ksp-incremental.html نوبت به نوشتن توی فایلمون می‌رسه. برای راحت تر شدن و خواناتر شدن یک operator function می‌نویسیم. https://gist.github.com/Darvishiyan/7326ead9f2fedaeba85f9600222d4956 قبل از اینکه ادامه بدیم باید بگم که حتما یادتون باشه که در انتهای کار OutputStream رو close کنید. https://gist.github.com/Darvishiyan/8d9157db2ed5a43f9ad089a1e2d3cb52 همون طور که می‌بینید نوشتن توی فایلمون بسیار راحت هستش و ما هر چیزی که می‌خواییم در انتها توی فایلمون باشه رو لازمه اینجا بنویسیم.توی کد بالا ما سه مرتبه پراپرتی‌هامون رو بررسی می‌کنیم.۱- برای تولید کد متد سازنده:class PersonBuilder(name: kotlin.String) https://gist.github.com/Darvishiyan/69ca8d32df5e74d95664f14812dfd9a9 ۲- برای تولید کد شی‌ای که قرار هستش داده‌ها رو نگه داره:private val mutablePerson: MutablePerson = MutablePerson(
   name = name,
   age = null,
   email = null,
   contact = null,
) https://gist.github.com/Darvishiyan/6571f008da80259305c7c248dcb8a168 ۳- برای تولید کد متدهای الگوی builder:fun age(age: kotlin.Int): PersonBuilder {
   mutablePerson.age = age
   return this
} https://gist.github.com/Darvishiyan/57c23c6b1d405c4bec276cbe40dbc147 توجه داشته باشید که بررسی تمام typeها و import کردن اونها بالای کلاسمون کار خیلی دردسر داری هستش. چون ما فایل رو داریم خط به خط می‌نویسم. برای حل این مشکل بجای نام هر type، نامش رو همراه با پکیجش ‌می‌نویسیم. یعنی بجای اینکه از پراپرتی declaration شی KSType پراپرتی simpleName رو بگیریم، پراپرتی qualifiedName رو می‌گیریم.این کار باعث میشه که ما بجایList&lt;Boolean&gt;بنویسیمkotlin.collections.List&lt;kotlin.Boolean&gt;که فرقی نداره، فقط مشکل import کردن رو حل کردیم.نکته بعدی که باید توجه داشته باشید این هستش که پیدا کردن type های جنریک به این راحتی نیست و ما باید به صورت بازگشتی typeها رو بررسی کنیم و مقادیر جنریک اونها رو پیدا کنیم. https://gist.github.com/Darvishiyan/dc27777726ea26ab2380fb1b8cef892d  https://gist.github.com/Darvishiyan/2d3021a8483fdc42536b47ec324945d2 همونجوری که می‌بینید در خط ۱۵ متد visitTypeArgument، متد visitTypeArguments رو صدا می‌کنیم و در خط ۶ این متد، متد visitTypeArgument رو صدا می‌کنیم و این روند اینقدر ادامه داره تا تام typeهای جنریک رو پردازش کنیم.در انتها فایل زیر به صورت خودکار تولید می‌شه.  https://gist.github.com/Darvishiyan/8fb550dccd85936c5415d5676716fdf1 ساختار ماژول processor
حالا نوبت به پیاده‌سازی ماژول app میرسه:برای اینکه از این ماژول ها توی برنامتون استفاده کنید باید پلاگین زیر رو به ماژول اصلی برنامه اضافه کنیم.id &#039;com.google.devtools.ksp&#039;و همینطور باید وابستگی های زیر رو هم به ماژول اصلی اضافه کنیم.implementation project(path: &#039;:annotations&#039;)
ksp project(path: &#039;:processor&#039;)خوب حالا پروژه رو sync و build کنید.یک کلاس شبیه کلاس زیر می‌سازیم. https://gist.github.com/Darvishiyan/93364cb9f4ff20468649413d68f5d41a ساختار کل پروژهپروژه رو یکبار دیگه build کنید و به آدرس زیر برید و فایلتون رو ببینید.~/build/generated/ksp/debug/kotlin/[Package Name]/[File Name].ktبرای این کار باید زبانه Project رو روی حالت Project بگذارید. ?چالش‌ها:می‌خواییم فایل های تولید شده رو توی حالت Android ببینیم، مثل فایل های Hilt.برای این کار باید کد زیر رو به فایل gradle ماژول که داره از KSP استفاده می‌کنه اضافه کنیم.در application module:applicationVariants.all { variant -&gt;
    kotlin.sourceSets {
        def name = variant.name
        getByName(name) {
            kotlin.srcDir(&amp;quot$buildDir/generated/ksp/$name/kotlin&amp;quot)
        }
    }
}در library module:libraryVariants.all { variant -&gt;
    kotlin.sourceSets {
        def name = variant.name
        getByName(name) {
            kotlin.srcDir(&amp;quot$buildDir/generated/ksp/$name/kotlin&amp;quot)
        }
    }
}می‌خواییم کانفیگ داشته باشیم.برای این کار باید کافیگ‌هامون رو توی بلاک اندروید ماژول اصلی بنویسیم و از با شی option بهشون دسترسی داریم.android {
    ...
    ksp {
        arg(&amp;quotmyConfig1&amp;quot, &amp;quottrue&amp;quot)
        arg(&amp;quotmyConfig2&amp;quot, &amp;quotmyText&amp;quot)
        arg(&amp;quotmyConfig3&amp;quot, &amp;quot1&amp;quot)
    }
}من کد زیر رو برای استفاده از کانفیگ استفاده می‌کنم. https://gist.github.com/Darvishiyan/4df1b97755e5372e6824ddce6e52f1e5 می‌خوام پارامتر رو پردازش کنم.وقتی می‌خواییم یک پرامتر رو پردازش کنیم تابع visitValueParameter از اینترفیس KSVisitor ما صدا زده می‌شه. در ورودی یکی شی داریم از نوع KSValueParameter.-- پراپرتی isVararg به ما میگه که این پرامتر از نوع vararg هستش یا نه-- پراپرتی hasDefault بهمون می‌گه که مقدار پیشفرض داره یا نه ولی مقدار رو نمی‌تونیم از جایی بدست بیاریم یا من پیدا نکردم ??‍♂️-- متد resolve در پراپرتی type اطلاعت خوبی می‌ده، مقدار بازگشتی این متد از نوع KSType هستش که میشه متوجه بشیم که------ اون پارامتر nullable هستش یا نه------ با استفاده از پراپرتی qualifiedName توی پراپرتی declaration می‌تونیم نوع پارامتر رو بدست بیاریمتوجه کنید که متد resolve بسیار پر هزینه هستش و سعی کنید کمتر ازش استفاده کنید.دوتا از چالش‌ها هم پردازش type های جنریک و import کردن type ها بود که توی مثال توضیح دادم.محدودیت ها:من تا اینجا با محدودیتی بجز اینکه به مقدار پیشفرض پارامترها دسترسی نداشتم روبرو نشدم. برای حل این مشکل هم می‌تونید یک انوتیشن دیگه تعریف کنید و مقدار پیشفرض رو با انوتیشن برای هر پارامتر مشخص کنید. https://github.com/google/ksp/issues/268 نمونه:توی ریپوهای زیر می‌تونید به سورس کد دسترسی داشته باشید، یه چندتا ریپوی دیگه هم اگه شد اضافه می‌کنم تا دید بهتری بهتون بده.استار بزنید که ببینم چند نفر به این پروژه سر میزنن ? https://github.com/Darvishiyan/KSP-Builder-Sample  https://github.com/Darvishiyan/KSP-DiffCallback-Sample اگه سوالی داشتید که چالشی بود بپرسید اگه بلد بودم، این مقاله رو بروز می‌کنم و جوابش رو می‌دم یا اگه با محدودتی رو برو شدید اون رو هم بگید اینجا بنویسم که قبل از شروع دیگران بدونن چه کار هایی می‌تونن بکنن و چه کار هایی نمی‌تونن.لینک‌های مرتبط و منابع: https://kotlinlang.org/docs/ksp-overview.html  https://github.com/google/ksp  https://proandroiddev.com/so-how-do-i-write-a-kotlin-symbol-processor-ksp-b9606e9e3818 </description>
                <category>حسام درویشیان</category>
                <author>حسام درویشیان</author>
                <pubDate>Sat, 30 Jul 2022 15:53:09 +0430</pubDate>
            </item>
                    <item>
                <title>معماری جاوا</title>
                <link>https://virgool.io/@darvishiyan/%D9%85%D8%B9%D9%85%D8%A7%D8%B1%DB%8C-%D8%AC%D8%A7%D9%88%D8%A7-bm4u6telzi5y</link>
                <description>دونستن معماری و ساختار جاوا به ما کمک می‌کنه برنامه های بهینه‌تری بنویسیم و وقتی با مشکلات مواجه می‌شیم فرضیاتی راجع به ریشه مشکل داشته باشیم.کد جاوا رو با هر چیزی می‌تونیم بنویسیم، از ویرایشگر های ساده تا IDE های خفن، هیچ فرقی نمی‌کنه. فقط باید دستور زبان جاوا رو رعایت کنیم و فایل مون رو با پسوند java ذخیره کنیم.اینکه ما می‌تونیم با یکبار نوشتن برنامه اون رو بر روی پلتفرم‌های مختلف اجرا کنیم بزرگترین نقطه قوت جاواست که بهش می‌گم WORA که مخفف write once, run anywhere هستش. همون طور که می‌دونید زبان‌هایی مثل C برای یک پلتفرم خاص و متناسب با سخت‌افزار کامپایل می‌شن. اما جاوا به یک زبان دیگه تبدیل می‌کنه که بهش می‌گن ‌bytecode با پسوند class و برای این کار از کامپایلر جاوا یعنی javac استفاده می‌کنه. این فایل های hexadecimal هایی هستن که JVM می‌تونه اونها رو بدون نیاز به کامپایل مجدد به زبان قابل درک برای هر سیستم عامل و سخت افزاری تفسیر کنه. برای همین می‌گن bytecode غیر وابسته به پلتفرم هستش و قابلیت جابجایی بین JVM های مختلف رو داره. فقط لازمه ما JVM مناسب با سیستم عامل و سخت افزارمون رو انتخاب کنیم.توی این مقاله می‌خوام اجزای مختلف JVM رو براتون شرح بدم، به نظر من شناخت بهتر JVM می‌تونه کمک کنه تا برنامه‌های کارآمدتری بنویسیم و توی پیدا کردن خطاها هم بهمون کمک می‌کنه.پیاده سازی: JVM معمولا بین دستگاه مختلف تغییراتی توی پیاده سازی داره ولی متداول ترین حالت همینی هستش که می‌خوام توضیح بدم.یک: Class Loader Subsystemتوضیح: JVM داخل رم سیستم بارگذاری می‌شه و با استفاده از Class Loader Subsystem کلاس های مورد نظر رو وارد رم می‌کنه و بهش می‌گن dynamic class loading که کلاس‌ها رو load و link و initialize می‌کنه. البته این کار رو فقط یک بار در زمان اجرا انجام می‌ده.یک، یک: Loading: مسئولیت اصلیش بارگذاری فایل ها توی رم هستش. در ابتدا با بارگذاری کلاس اصلی پروژه شروع می‌کنه. کلاسی که حاوی static main هستش. و بعد با توجه به دستورها کلاس‌های بعدی رو توی رم بارگذاری می‌کنه. سه class loader داریم که اونها از ۴ اصل پیروی می‌کنن:اصل اول: Visibility Principle: این اصل می‌گه که child class loader می‌تونه کلاس هایی که parent class loader بارگذاری کرده رو ببینه ولی parent class loader نمی‌تونه کلاس هایی رو که child class loader بارگذاری کردند رو پیدا کنه.اصل دوم: Uniqueness Principle: این اصل به بارگذاری یکتا کلاس ها اشاره می‌کنه و می‌گه یک child class loader نباید بتونه کلاسی که توسط پدرش بارگذاری شده رو دوباره بارگذاری کنه. و هیچ کلاسی نباید بیش از یکبار بارگذاری بشه.در ادامه بجای نوشتن کامل اسم لایه از مخفف استفاده می‌کنم:از ACL بجای Application Class Loaderاز ECL بجای Extension Class Loaderاز BCL بجای Bootstrap Class Loaderاصل سوم: Delegation Hierarchy Principle: این اصل برای اطمینان از دو اصل قبل است. JVM به صورت سلسله مراتبی کلاس ها رو بارگذاری می‌کنه و برای هر بارگذاری یک درخواست می‌فرسته. ACL درخواست رو دریافت می‌کنه و اون رو برای ECL ارسال می‌کنه و اون هم سپس درخواست رو برای BCL ارسال می‌کنه. اگر کلاس درخواست شده در Bootstrap path پیدا شد یعنی کلاس پیدا و بارگذاری شده است. در غیر این صورت درخواست برگشت داده می‌شه به ECL تا کلاس را در Extension path یا custom specific path جستجو و بارگذاری کنه. اگر این تلاش موفقیت آمیز نباشه درخواست برگشت داده می‌شه به ACL تا کلاس را در System class path جستجو و بارگذاری کنه، اگر این جستجو موفقیت آمیز نباشه ما با خطای ClassNotFoundException در زمان اجرا روبرو می‌شویم.اصل چهارم: No Unloading Principle: یک class loader می‌تونه کلاس ها رو بارگذاری کنه ولی نمی‌تونه اون رو تخلیه کنه. بجای تخلیه کلاس های بارگذاری شده ما می‌تونیم class loader رو حذف کنیم و یک class loader جدید ایجاد کنیم.لایه های Class Loader:لایه Bootstrap Class Loader: کلاس های استاندارد JDK و هسته جاوا را در آدرس JAVA_HOME/jre/lib بارگذاری می‌کنه. همچنین با زبان ها محلی مثلا C پیاده‌سازی شده و در جاوا به عنوان والد تمام class loader هاست.لایه Extension Class Loader: وظیفه داره درخواست بارگذاری را برای BCL ارسال کند و در صورت موفقیت آمیز نبودن آن را در آدرس JAVA_HOME/jre/lib/ext یا هر آدرس دیگری که در java.ext.dirs در تنظیمات سیستم قرار داره جستجو و بارگذاری می‌کنه. همچنین با زبان جاوا پیاده‌سازی شده و از ExtClassLoader مشتق شده است.لایه Application Class Loader: بارگذاری کلاس‌های خاص برنامه را از system class path بر عهده داره که می‌تونیم این آدرس را در زمان اجرا با فرمان cp یا classpath تغییر بدیم. به صورت پیشفرض از آدرس java.class.path استفاده می‌کنه. همچنین با زبان جاوا پیاده‌سازی شده و از AppClassLoader مشتق شده است.علاوه بر اینها می‌توانیم با ساخت یک User-defined Class Loader در کد برنامه. کاملا مستقل کلاس ها را بارگذاری کنیم. هر class loader از یک namespace استفاده می‌کنه که کلاس های بارگذاری شده خود رو در اون با روش Fully Qualified Class Name ذخیره می‌کنه. زمانی که یک class loader می‌خواهد یک کلاس را بارگذاری کنه، اون رو تو namespace خودش با روش FQCN جستجو می‌کنه. اگر اون رو پیدا کنه ولی namespace آن متفاوت باشد اون رو کلاس دیگه‌ای در نظر می‌گیره. namespace متفاوت به این معنی است که class loader دیگری این کلاس را بارگذاری کرده.یک، دو: Linking: در این مرحله کلاس ها و اینترفیس‌های بارگذاری شده در مرحله قبل به شرط اینکه کامل بارگذاری شده باشن، بررسی و آماده میشن. باید به این نکته کاملا توجه کنیم‌ که اگه توی این مرحله خطایی رخ بده، این خطا به سمت برنامه پرتاب خواهد شد. این مرحله از سه بخش زیر تشکیل شده:بخش اول: Verification: این سخت‌ترین و سنگین ترین قسمت هستش و زمان زیاری می‌بره البته بهینه هستش و فقط یک بار انجام میشه. در این مرحله مطمئن می‌شیم که کلاس های بارگذاری شده قواعد جاوا رو دارند و با یک کامپایلر معتبر کامپایل شدن یا نه. اگه مشکلی توی این مرحله به‌وجود بیاد خطای java.lang.VerifyError پرتاب می‌شه.بخش دوم: Preparation: در این مرحله حافظه مورد نیاز کلاس‌ها شامل فضای استاتیک و فضای داده‌های کلاس به اونها تخصیص داده می‌شه. دقت کنید متغیر های استاتیک در این مرحله ساخته نمی‌شن و این کار بر عهده قسمت دیگه‌ای از برنامه‌ست.بخش سوم: Resolution: در این مرحله نماد رفرنس داده ها با رفرنس مستقیم اونها جایگزین می‌شه.یک، سه: Initialization: در این قسمت کلاس های بارگذاری شده ساخته می‌شوند (تابع سازنده آنها صدا زده می‌شود). این فرایند multi thread است ولی به صورت thread safe پیاده‌سازی شده و مانع از ساخت شدن چندباره کلاس‌ها می‌شود. این مرحله نهایی بارگذاری کلاس‌ها و اینترفیس‌هاست. متغیرهای استاتیک در این مرحله مقدار دهی می‌شوند و بلاک‌های استاتیک اجرا می‌شوند. به صورت سلسله مراتبی کد ما خط به خط از بالا به پایین اجرا می‌شود، در کلاس‌ها و فرزندان آنها.دو: Runtime Data Areaتوضیح: JVM داخل رم یک فضا برای بارگذاری داده‌ها در اختیار داره. class loader شی باینری متناظر هر کلاس رو تولید می‌کنه و اونها رو بصورت جداگانه و با اطلاعات زیر (class level information) توی method area ذخیره می‌کنه.- نام کامل FQCN به همراه نام پدر- تمام چیزهای مربوط به کلاس (کلاس‌های فرزند، اینترفیس‌ها، اینام‌ها و ...)- اطلاعات متد‌ها و متغیر های استاتیک هر کلاس نماینده‌ای در حافظه Heap داره که به class level information دسترسی داره.دو، یک: Method Area: این فضا بین تمام thread ها مشترک است. دسترسی به داده توابع و پردازش آنها باید به صورت thread safe باشد. این قسمت class level data و متغیر های static را ذخیره می‌کند.توضیح: class level data از بخش های زیر تشکیل شده:- Classloader reference- Run time constant pool: وقتی JVM به دنبال ادرس دقیق یک تابع یا متغیر است این قسمت استفاده می‌کند.- Field data: نام، نوع، modifier و ویژگی‌ها- Method data: نام، نوع داده بازگشتی، ورودی ها به ترتیب، modifier و ویژگی‌ها- Method code: بایت کد، سایزها، جداول و …دو، دو: Heap Area: این فضا بین تمام thread ها مشترک است. اطلاعات تمام اشیا و متغیرها و آرایه‌ها را آن ذخیره می‌کنیم. ذخیره داده‌ها در این فضا thread safe نیست. این فضایی هستش که GC ازش استفاده می‌کنه.دو، سه: Stack Area: به ازای هر thread اختصاصی است. در زمانی که یک thread  ساخته می‌شه یک فضای مجزا stack به آن اختصاص داده می‌شه. به ازای هر بار صدا زدن توابع یک stack frame ایجاد می‌شه و به بالای stack اضافه میشه (push). هر stack frame رفرنس یک آرایه از متغیر های محلی هستش و سایزش وابسته به متغیرها عوض میشه. frame ها حذف میشن (pop) وقتی توابع به صورت معمولی به پایان میرسن. وقتی خطایی رخ می‌دهد با توجه به دادهای stack آن‌ها را رهگیری می‌کنیم. همچنین این فضا thread safe است چون منابع آن مشترک نیست. بعد از نابودی هر thread فضای stack نابود می‌شه. اندازه فضای stack می‌تواند ثابت یا متغیر باشد. اگه یک thread به فضای بیشتری نیاز داشته باشه خطای StackOverflowError پرتاب می‌کنه و اگه یک thread بخواد یک frame جدید درست کنه و فضای کافی نداشته باشه خطای OutOfMemoryError پرتاب می‌کنه. هر stack frame از سه قسمت تشکیل شده.یک: Local Variable Array: یک آرایه است که ایندکس ۰ (صفر) رفرنس کلاسی است که متد در آن است و از ایندکس ۱ (یک) پارامتر هایی که به متد ارسال می‌شن شروع می‌شن و سپس متغیر های محلی در آن قرار دارد.دو: Operand Stack: به عنوان یک فضای کاری در زمان اجراست که اگر نیاز باشد برای انجام عملیات استفاده می‌شود. تمام متد‌ها داده‌ها را بین operand stack و local variable array و دیگر متد‌ها تبادل می‌کنند. اندازه این فضا را در زمان اجرا مشخص می‌شود مگر اینکه در زمان کامپایل تعیین شده باشد.سه: Frame Data: تمام نماد‌های متد و بلاک های catch در این فضا نگهداری می‌شود.دو، چهار: PC Registers: به ازای هر thread اختصاصی است. برای نگهداری آدرس های دستورات در حال اجرا استفاده می‌شود (آدرس حافظه در Method Area). اگه متد به صورت native باشد این فضا به آن اختصاص نمی یابد. بعد از پایان دستور جاری با آدرس دستور بعدی بروز می‌شود.دو، پنج: Native Method Stack: به ازای هر thread اختصاصی است. یک نگاشت مستقیم بین thread جاوا و thread سیستم عامل است و داده های متد های native را نگهداری می‌کند که از JNI استفاده می‌کند. زمانی که یک native thread ساخته و اجرا می‌شه.این فضا بهش اختصاص داده می‌شه و زمانی که thread جاوایی که این متد رو فراخوانی کرده بسته می‌شه این native thread هم بسته می‌شه و تمام حافظه‌ای که گرفته بودند هم آزاد می‌شه. زمان‌بندی و ارسال thread ها به CPU بر عهده سیستم عامل هستش.سه: Execution Engineتوضیح: ‍bytecode ها اینجا اجرا می‌شن. Execution Engine دستورات رو خط به خط اجرا می‌کنه‌. و از بخش‌های زیر تشکیل شده.سه، یک: Interpreter: این بخش bytecode ها رو تفسیر می‌کنه و دستورها رو خط به خط اجرا می‌کنه. تفسیر یک خط کار خیلی سریعی هستش ولی اجرای اون کنده. عیبش این هستش که وقتی ما یک متد رو چند بار صدا بزنیم هر بار کندتر میشه.برداشت شخصیم متدهای بازگشتی هستش! ?سه، دو: Just-In-Time Compiler: اگه فقط مفسر وجود داشته باشه وقتی یک متد رو چند بار فراخوانی کنیم هر بار تفسیر می‌شه و که اگه درست کنترل بشه یک عمل بی‌فایده‌ست. دلیل وجود JIT این هستش که این مشکل رو حل کنه. در ابتدا کل bytecode رو به زبان ماشین  کامپایل می‌کنه، بعدش برای متدهای تکراری کد از قبل کامپایل شده رو ارائه می‌ده که خیلی سریعتر از اونی هستش که بخواد دوباره کد رو تفسیر کنه. کد کامپایل شده رو توی cache نگهداری میشه تا بشه سریع اجرا بشه.باید توجه کنیم که JIT به زمان بیشتری برای کامپایل نیاز داره تا interpreter برای تفسیر کد. اگه ی قطعه کد فقط یک بار لازمه اجرا بشه بهتر تفسیر بشه بجای اینکه کامپایل بشه و کد کامپایل شده توی cache ذخیره می‌شه که پر هزینه هستش. برای حل این مشکل JIT خودش چک می‌کنه و متد های که زیاد اجرا می‌شن رو پیدا می‌کنه و اونها رو برای کامپایل انتخاب می‌کنه. اسم این کار adaptive compiling هستش و توی Oracle Hotspot VM استفاده می‌شه.توضیح: JVM کلی بهینه‌ساز عملکرد (performance optimization) داره که چهارتاشون خیلی خوبن:- Intermediate Code Generator: کد میانی درست می‌کنه- Code Optimizer: کی که ICG ساخته رو بهینه می‌کنه- Target Code Generator: کد ماشین رو تولید می‌کنه- Profiler: نقطه ضعف‌هایی که پرفورمنس رو کاهش می‌دن رو پیدا می‌کنهدوتا رویکرد برای بهینه‌سازی کامپایل داریم:رویکرد اول: Oracle Hotspot VMs: اوراکل دوتا پیاده سازی از کامپایلر EES توی JVM داره که بهشون می‌گه Hotspot Compiler. تو مرحله profiling که می‌تونه نقطه ضعف‌ها رو پیدا کنه به JIT می‌گه کدوم قسمت از کدها رو به کد ماشین کامپایل کنه و cache کنه، بعد یک مدت اگه ببین اشتباه کرده و این کدها پرکاربرد نیستن، اونها رو از cache پاک می‌کنه و اجرای اون قسمت از کد ها رو به interpreter واگذار می‌کنه. این کار با جلوگیری کردن از کامپایل بی‌مورد باعث بالا رفتن بازدهی می‌شه. در ضمن Hotspot Compiler خودش در لحظه تصمیم از چه تکنیکی برای کامپایل استفاده کنه. آنالیز عملکرد در زمان اجرا برنامه به ما این امکان رو می‌ده که قاطعانه تصمیم بگیریم کدوم تکنیک بهتره.پیاده سازی اول:‌ Oracle Java Hotspot Client: این تکنولوژی بهینه شده تا با کاهش زمان اجرا و حافظه مصرفی بازدهی رو برای سرویس گیرنده ها بیشتر کنه.پیاده سازی دوم: Oracle Java Hotspot Server: این تکنولوژی برای بالاترین بازدهی بر روی سرورها طراحی شده است و بهش می‌گن Advanced Dynamic Optimizing Compiler و از کلی تکنیک‌های بهینه سازی پیچیده استفاده می‌کنه و موقع اجرا کردنش توی خط فرمان مثلا باید بگیم java server MyAppاین تکنولوژی اوراکل معروف هستش به اینکه خیلی سریع حافظه رو تخصص می‌ده و خیلی سریع اون رو آزاد می‌کنه و به صورت خیلی مقیاس‌پذیری می‌تونه پردازش‌های موازی رو سرورهایی با CPU های خفن مدیریت کنه.رویکرد دوم: Ahead-Of-Time Compiling: این تکنولوژی رو IBM معرفی کرده و اینجوری هستش که کد کامپایل شده رو می‌ریزه تو cache تا هر موقع لازم بود کد ازش استفاده کنه و البته میشه این کد کامپایل شده رو هم باقی JVM ها بدون نیاز به کامپایل انتقال داد. و ضمنا IBM یه راه سریع هم برای اجرا کدها ارائه داده که بهش می‌گه JXE که مخفف Java Executable هستش. فقط باید دقت کنید ک برای استفاده از این قابلیت باید با AOT کدتون رو کامپایل کرده باشید.سه، سه: Garbage Collector: تا زمانی برنامه که به یک شی رجوع می‌کند (خوندن، تغییر دادن یا مقدار دهی مجدد کردن)، JVM اون شی رو زنده در نظر می‌گیره. وقتی پس از گذشت زمانی معین هیچکی به اون شی سر نزنه، اون شی رو غیر قابل دسترس در نظر می‌گیره و GC اون شی رو حذف می‌کنه و حافظه اون رو آزاد می‌کنه. در حقیقت GC به صورت یک daemon thread هستش و خود JVM استارت می‌کنه ولی ما هم می‌تونیم با system.gc اون رو فراخوانی کنیم.چهار:‌ Java Native Interfaceاین اینترفیس برای تعامل با متد‌های native هستش. JVM با JNI متدهای native رو صدا میزنه و بیشتر برای ارتباط با سخت افزار ازش استفاده می‌کنه.پنج: Native Method Librariesیک مجموعه از کتابخانه های native هستن که Execution Engine به اونها برای دسترسی به JNI نیاز داره.درباره JVM Threadsما در مورد اینکه برنامه‌ها چجوری اجرا می‌شن صحبت کردیم ولی درباره اجرا کننده برنامه‌ها هیچ صحبتی نکردیم. JVM همزمان چندین thread را اجرا می‌کند. بعضی از اونها منطق یک برنامه هستن و به وسیله برنامه‌ها ساخته می‌شن که بهشون می‌گن application thread و باقی thread ها رو خود JVM برای کارهای خودش ایجاد می‌کنه که بهشون می‌گن system thread.یک: application thread همون main thread هستش و تمام thread های برنامه به وسیله این thread ساخته می‌شن. به عنوان مثال اجرای برنامه، ساخت اشیا توی heap و … وظیفه Application thread هستش.دو: system thread از قسمت‌های زیر تشکیل شده:- Compiler threads: کامپایل bytecode به native code در زمان اجرا رو این thread انجام می‌ده.- GC threads: تمام کارهایی که GC انجام می‌ده رو این thread انجام می‌ده.- Periodic task thread: رخدادهای وابسته به زمان و کارهایی که به صورت دوره ای انجام میشه رو این thread انجام می‌ده.- Signal dispatcher thread: دریافت سیگنال‌هایی که به JVM ارسال می‌شه، مدیریت و پردازش اونها در درون JVM با فراخوانی متد مناسب در JVM- VM thread: بعضی کارها به JVM نیاز دارن تا اونها رو به یک نقطه درست از Heap برسونه، جایی که تغییرات زیاد نیست. مثلا: stop-the-world garbage collections یا thread stack dumps یا thread suspension یا biased locking revocation. این دسته از عملیات‌ها برای اجرا به این thread نیاز دارند.نکات پایانی:جاوا یک زبان مفسری و کامپایلری هستش.طراحی جاوا جوری هستش که در پیوند‌های پویا (dynamic linking) و تفسیر در زمان اجرا (run-time interpreting) کند هستش.کامپایلر JIT نقطه ضعف جاوا رو در تفسیر کدها رو با cache کردن کد‌های کامپایل شده بجای bytecode پوشش می‌دهتوجه داشته باشید JVM فقط یک سند هستش، ارائه دهنده های اون می‌تونن چیزی رو تغییر بدن، نوآوری داشته باشن و یا در زمان پیاده سازی چیزی رو بهبود ببخشن.لطفا اگه اشتباهات املایی یا انشایی داره بهم پیام بدید تا اصلاح کنم.</description>
                <category>حسام درویشیان</category>
                <author>حسام درویشیان</author>
                <pubDate>Fri, 15 Jul 2022 19:32:04 +0430</pubDate>
            </item>
                    <item>
                <title>Kotlin Classes Cheat Sheet</title>
                <link>https://virgool.io/@darvishiyan/kotlin-classes-cheat-sheet-ocallhrdchuh</link>
                <description>کلاس خالی میتونه {} نداشته باشه.class MyClassمتد سازنده یا constructor کلاس رو می‌شه توی هدر نوشتclass MyClass constructor( … ) { … }اگه بخوایم constructor کلاس از بیرون در دسترس نباشد باید آن را private کنیمclass MyClass private constructor( … ) { … }اگه constructor ما annotations یا visibility modifiers نداشته باشه میتونیم اون رو ننویسیم.class MyClass( … ) { … }اگه کلاس ما توی ورودی چیزی لازم نداشته باشه بگیره میشه () رو نزاریمclass MyClass { … }وقتی از constructor توی هدر استفاده می‌کنیم. باید کدی که میخوایم در ابتدای ساخته شدن کلاس اجرا بشه رو توی یک {} در بدنیه کلاس بنویسیم. فقط دقت کنید که قبلش باید عبارت init رو بنویسیم و ما میتونیم چند init توی بدنه کلاس داشته باشیم که به ترتیب از بالا به پایین اجرا می‌شن.class MyClass {
    init { // first }
    init { // second }
}اگه قبل از ورودی‌های constructor از val یا var استفاده کنیم اونها تبدیل به property می‌شن. در غیر این صورت فقط به صورت یک متغیر در بدنه init در دسترس هستند.ورودی‌های constructor می‌تونن مقدار پیش فرض داشته باشن.در constructor از trailing comma پشتیبانی می‌کنه.اگه بخوایم کلاسمون چند تا constructor داشته باشه میتونیم متدش رو بنویسیم. فقط توجه داشته باشید که اگه تو هدر constructor داشته باشیم باید بعد از متد constructor حتما this رو صدا بزنیم و متد constructor هدر رو پیاده سازی کنیم.class MyClass( … ) {
    init { … }
    constructor( … ) : this( … ) { ... }
    constructor( …, ... ) : this( … ) { ... }
}بلاک init قبل از constructor ها اجرا می‌شود.کلاس ها با : از کلاس های دیگه ارث می‌برن یا اینترفیس ها رو پیاده سازی می‌کنن.برای توسعه کلاس یا باید از modifier های open یا abstract استفاده کنیم. کلاس ها توی کاتلین به صورت پیش فرض final هستند یعنی نمی‌شه اونها رو توسعه داد. توجه کنید که از کلاس abstract نمی‌شه یک نمونه ساخت و فقط باید اون رو به وسیله کلاس های دیگه توسعه داد.بعد از توسعه یک کلاس، اگه کلاس پدر ورودی داشت یا باید توی هدر argument ها رو ارسال کنیم یا باید در متد سازنده super رو صدا بزنیم.open class MyParent( … ) { … }
class MyClass( … ) : MyParent( … ) { … }class MyClass : MyParent {  constructor( … ) : super( … ) { … } }برای اینکه کلاس فرزند بتونه function ها یا value ها رو بازنویسی کنه باید قبل از تعریف اونها از کلمه open استفاده کنیم.open val MyValue = “value”
open fun MyFunction( … ) { … }زمانی که ما یک کلاس رو توسعه می‌دیم و از subclass اون یک نمونه می‌سازیم قبل از ساخته شدن اون، یک نمونه از superclass ساخته می‌شه. که این به این معنی هستش که متد constructor یا بلاک init مربوط به superclass زودتر اجرا می‌شن. به همین دلیل، متغیرهایی که ما توی subclass مقداردهی یا بازنویسی کردیم هنوز داده مورد نظر ما رو ندارن. به همین دلیل استفاده از متغیرهای open توی متد constructor یا بلاک init اشتباه هستش.توی یک کلاس برای دسترسی به superclass از عبارت super باید استفاده کنیم.وقتی از کلاس های تو در تو استفاده می‌کنیم میتونیم برای اشاره درست به superclass مورد نظر از @ استفاده کنیم.super@Superclass.method()وقتی یک subclass بیشتر از یک superclass دارد برای اشاره به superclass مورد نظر از &lt;&gt; باید استفاده کنیم.super&lt;Superclass&gt;.method()در زمان پیاده سازی یک اینترفیس می‌تونیم متغیرها رو توی هدر override کنیم.interface MyInterface { val myValue: String }
class MyClass( override val myValue: String ) : MyInterface {}اگه توابع هم ساختار توی کلاس پدر و یا اینترفیس ها وجود داشته باشه هیچ مشکلی پیش نمیاد و فقط لازمه یکی از اونها رو بنویسیم و با استفاده از &lt;&gt; می‌تونیم به superclass مورد نظر دسترسی داشته باشیم.برای پیاده سازی interface ها یا abstract class ها می‌تونیم از object ها هم استفاده کنیم.interface MyInterface { fun myFunction() }
val myObject = object : MyInterface { override fun myFunction() {} }اگه یک اینترفیس فقط یک متد داشته باشد برای پیاده سازی آن نیازی به استفاده از object نداریم. که به آن SAM که مخفف Single Abstract Method است هم می‌گن.interface MyInterface { fun myFunction() }
val mySAM = MyInterface {}توی اینترفیس‌ها میشه متد‌ها رو هم پیاده سازی کرد و اینجوری لازم نیست اون متد پیاده سازی شده رو توی subclass پیاده سازی کرد.با typealias ما می‌تونیم برای یک متغیر با اسم بزرگ و سخت یک اسم راحت انتخاب کنیم. فقط دقت کنید که اونها رو فقط میشه به صورت top level تعریف کرد.typealias MyList = MutableList&lt;MutableList&lt;String&gt;&gt;
val myValue : MyList? = mutableListOf()به تعریف کلاس های توی هم میگن inner class و به صورت پیشفرض static هستند.کلاس ها نمی‌تونن متغیر های private داخل inner class های خودشون رو ببین.به متدها و متغیرهایی که بیرون کلاس ها نوشته می‌شن top level می‌گنبه متدها و متغیرهایی که توی کلاس های نوشته می‌شن member می‌گنبه متدها و متغیرها و کلاس‌هایی که توی متدها نوشته می‌شن local می‌گن.برای استفاده از متدها و متغیرهای top level کلاس های دیگه باید package آنها را import کنیم.متدها و متغیرها و کلاس‌های local نمی‌تونن modifier داشته باشن.تنها modifier متفاوت کاتلین internal هستش که شی رو توی ماژول در دسترس قرار می‌ده.تو کاتلین data class ها اشیای بهتری برای نگهداری داده های هستند و در اونها تغییراتی برای افزایش قابلیتهاشون بوجود اومده.متد toString توی data class ها اسم کلاس به همراه اسم متغیرها و مقدار اونها رو چاپ می‌کنه در حالی که توی کلاس های معمولی اسم و رفرنس کلاس رو چاپ می‌کنه.متد copy به اونها اضافه شده که می‌شه با اون یک کپی از شی بگیریم و البته میتونیم هر پارامتری رو هم که خواستیم به این متد بفرستیم و اون رو توی شی جدید تغییر بدیم ولی باید اسم اون رو هم ذکر کنیم.به ازای هر متغیر در data class ها اونها به صورت خودکار یک متد component می‌سازن و اون ها رو به ترتیب از ۱ شماره میزنن که هر کدوم از این متد ها به داده یکی از متغیر ها متصله بهش میگن componentN.یک قابلیت داریم به اسم destructuring declarations﻿  که می‌تونه اشیا رو بشکنه به متغیر هاdata class MyDataClass(x: String, y: Int)
val myData = MyDataClass(“”, 0)
val (name, age) = myDataمتد equals که توی کلاس Any پیاده سازی شده که superclass تمام اشیاست به رفرنس شی اشاره می‌کنه ولی تو data class با استفاده از متد hashCode که اون هم به صورت پیشفرض تو data class ها پیاده سازی شده به داده شی اشاره می‌کنه و اینجوری میتونه دوتا شی با رفرنس متفاوت ولی با داده یکسان رو با هم برابر قرار بده.دوتا شی Pair و Triple که به صورت پیشفرض تو کاتلین وجود دارن data class هستن.کاتلین یک شی جالب داره به اسم object. می‌شه تو اونها متغیر، ثابت، ثابت compile time، متد، کلاس و حتی object تعریف کنیم. ولی اونها رو فقط می‌شه به صورت top level ایجاد کرد.برای دسترسی به اونها لازم نیست یک نمونه از اونها داشته باشیم. این به این معنی نیست که نمی‌شه از اونها نمونه ساخت.در تعریف Object شی به صورت single در پروژه ایجاد می‌شن و یکتا هستن. تابع سازنده ندارن ولی بلاک init دارن و از قوانین ارث بری پیروی می‌کنن. این اشیا به صورت lazy هستند و فقط وقتی برای اولین بار صدا زده می‌شن ساخته می‌شن.object MyObject { … }
object MyObject : MyInterface { … }از Object expressions﻿ برای inheriting anonymous  و anonymous objects و anonymous return value استفاده می‌شن. در این شرایط به داده‌های scope خود دسترسی دارند. این اشیا بلافاصله وقتی ازشون استفاده می‌شه ساخته و اجرا می‌شن.Anonymous objects ⇒ val myobject = object { ... }
Inheriting anonymous ⇒ window.addMouseListener(object : MouseAdapter() { … }) 
Anonymous return value ⇒ fun myFunction() = object { … }تو کاتلین ما static نداریم یعنی به اشیای یک کلاس ( متد و متغیر ) نمیشه بدون ایجاد یک شی از اون کلاس دسترسی داشت ولی. همینطور ما نمی‌تونیم که object توی کلاس بسازیم. ولی با استفاده از عبارت companion می‌تونیم یک object توی کلاس ایجاد کنیم که رفتاری مشابه static داره یعنی بدون نیاز به ایجاد یک نمونه از اون شی می‌تونیم به متدها و متغیرهاش دسترسی داشته باشیم.از درون companion object میشه به اطلاعات private دسترسی داشت، همچنین این object می‌تونه نام نداشته باشه.class MyClass { companion object { … } }این اشیا از قوانین اشیای static در جاوا پیروی می‌کنن و زمانی که کلاس اصلی داره بارگذاری می‌شه ساخته می‌شن.با هدف جلوگیری از استفاده از ثابت‌های رشته ای که احتمال خطا توی اونها خیلی زیاد بوده و دامنه اونها هم مشخص نبوده enum ها بوجود اومدن.توی کاتلین enum class ها بین class و object هستند. کلاس اصلی یک constructor داره که تمام اشیا باید اون رو پیاده سازی کنن. همچنین میشه متد‌های abstract و یا open یا متغیر تو کلاس اصلی تعریف کنیم. که همه اشیا object هایی هستند که از کلاس اصلی ارث برده اند. اشیای درون enum ها همه object هستند و به صورت یکتا در پروژه ایجاد می‌شن. و این بزرگترین نقطه ضعف enum هستش. اگه داده ای در یکی از اونها تغییر کنه داده در کل پروژه تغییر می‌کنه.توجه کنید enum ها می‌تونن اینترفیس ها رو پیاده سازی کنن ولی کلاس ها رو نه!برای جدا کردن object های enum از متغیرها و متد‌ها باید در انتهای اونها ; بزاریم.enum class MyEnum(value:Int) : MyInterface {
    FIRST(1) { override fun myFunction() { ... } },
    SECOND(2) { override fun myFunction() { … } },
    THIRD(3) { override fun myFunction() { … } }
}یک مشکل بزرگ enum داشت یکتا بودنش در پروژه بود. برای رفع این مشکل ما sealed ها رو داریم (وابسته به نیاز ما می‌تونن کلاس یا اینترفیس باشن) که اشیای اونها یکتا نیست.اشیایی (subclassهایی) که یک شی sealed رو توسعه می‌دن باید می‌تونن به صورت تودرتو باشن یا توی همون فایلی باشن که شی اصلی هستش و یا توی یک پکیج.اشیای sealed رو object ها خیلی راحت توسعه می‌دن. ولی باید توجه داشته باشیم که اگه از object ها توی sealed کلاس ها استفاده کنیم رفتار اونها کاملا شبیه enum ها می‌شه.اگه یک class معمولی بخواد یک sealed رو توسعه بده باید حتما متدهای equal و hashCode رو بازنویسی کنه.اشیای sealed می‌تونن از قوانین ارث بری پیروی کنن. اگه یک sealed class از یک اینترفیس ارث بری کند تمام اشیا باید آن را پیاده سازی کنن مگر اینکه خود کلاس اصلی آن را پیاده سازی کرده باشد.توی کاتلین sealed class ها مثل کلاس های abstract هستند و الزامی به پیاده سازی متد ها یا متغیرهای abstract را ندارند.توی کاتلین Nested که میشه همون تو در تو کاملا پشتیبانی میشه و ما میتونیم کلاس ها و اینترفیس ها رو به هر ترتیبی که دوست داریم توی هم ایجاد کنیم.برای دسترسی به کلاس های تو در تو نیازی به داشت یک رفرنس از شی پدر نیست. اونها به صورت پیش فرض static هستندحالا اگه ما قبل از کلاس ها یا اینترفیس های توی یک کلاس عبارت inner رو بزاریم حتما باید یک نمونه از کلاس پدر رو برای دسترسی به اونها داشته باشیم.دقت کنید anonymous inner classes﻿ همون inheriting anonymous تو object expressions﻿ هستش فقط اسمش رو عوض کردن.یادآوری:داده primitive یا داده اولیه داده های هستن مثل int و float و byte و char و boolean و double و …کلاس‌های Wrapper کلاس هایی هستند که داده های primitive رو به object تبدیل می‌کنند و بالعکس.از نسخه ۵ جاوا به بعد ی قابلیتی به اسم autoboxing و unboxing اضافه شد که wrapper ها رو انجام میداد. که autoboxing یا boxing میشه تبدیل داده primitive به object و unboxing میشه تبدیل داده object به primitive.یک مفهوم دیگه برای wrapper ها در زمان کار کردن با کلاس های final هستش. چون ما اونها رو نمیتونیم توسعه بدیم می‌تونیم با استفاده از یک wrapper این کار رو انجام بدیم. به این صورت که یک شی از اون توی کلاسمون میسازیم به صورت private و متدهایی هم نام متدهای شی اصلی درست می‌کنیم و پیاده سازی های خودمون رو ایجاد می‌کنیم.گاهی ما نیاز داریم که یک object از داده primitive متناسب با ساختار برنامه خودمون ایجاد کنیم. این کار از نظر پردازشی خیلی کار پرهزینه هستش به قولی runtime overhead داره که به خاطر additional heap allocation هستش. برای حل این مشکل از inline class ها استفاده می‌کنیم که منطقش شبیه inline function هاست.نکته: از نظر نوشتاری inline class به value class تغییر کرده ولی هنوز بهشون می‌گن inline class. و باید از انوتیشن JvmInline استفاده کنیم.باید حتما و فقط یک ورودی در constructor بگیرند که داده primitive باشه.از متغیر و متد و بلاک init هم پشتیبانی می‌کنن. البته متغیرها از backing field پشتیبانی نمی‌کنن و نمیتونیم lateinit var داشته باشیم.می‌تونن اینترفیس ها رو پیاده سازی کنن ولی نمی‌تونن تو سلسله مراتب وراثت باشن به همین ترتیب کسی نمی‌تونه اونها رو توسعه بده و به نوعی final هستند.تو کاتلین inline class ها وقتی کامپایل میشن به داده داخلیشون تبدیل می‌شن که بهش می‌گن underlying type. اگه موقع استفاده از اونها دقت نکنیم ممکنه خطا های مبهمی بوجود بیاریم.@JvmInline value class UInt(val x: Int)
fun compute(x: Int) { }
fun compute(x: UInt) { }
// Represented as &#039;public final void compute(int x)&#039; on the JVMتو مثال بالا هر دو متد ما در JVM به یک تابع مشابه تبدیل میشن. که خوب برای رفع این مشکلی هم hasecode شی UInt به انتهای نام متد اضافه می‌شه. علاوه بر این خودمون هم می‌تونیم با JvmName به این تابع نامی که می‌خوایم رو اختصاص بدیم.شاید فکر کنید که این خیلی شبیه type alias هستش ولی با هم یک تفاوت بزرگ دارن. type alias فقط نام اون رو برای ما در زمان برنامه نویسی تغییر میده در حالی که inline class واقعا یک نوع جدید ایجاد می‌کنه. https://kotlinlang.org/docs/classes.html </description>
                <category>حسام درویشیان</category>
                <author>حسام درویشیان</author>
                <pubDate>Tue, 04 Jan 2022 20:00:58 +0330</pubDate>
            </item>
                    <item>
                <title>دقیقا Volatile توی Java چیست؟</title>
                <link>https://virgool.io/@darvishiyan/java-volatile-zrp1lhco2w2x</link>
                <description>تو کامپیوتر CPU مسئول اجرای دستورات هستش و برای بازیابی دستورات و داده های به RAM نیاز داره. CPU توانایی زیادی در اجرای دستورات داره و سرعت دسترسی به داده های RAM مناسب با سرعت پردازش اونها نیست. به همین دلیل از یکسری تکنیک برای بهینه کردن فرآیند ها استفاده می‌کنه.تکنیک‌ها:تکنیک Out-of-order execution: یک از تکنیک های CPU برای بهینه کردن زمان اجرا برنامه هاست و بجای اینکه منتظر داده‌های دستور جاری بشه. دستورات بعدی را که قابلیت اجرا داره رو اجرا می‌کند.تکنیک Branch predictor: یک مدار دیجیتال هستش برای پیش بینی بلاکی که قراره در دستورات شرطی اجرا بشه. در ابتدا شاید زیاد کار آمد به نظر نرسه ولی با گذشت زمان و نگهداری از تاریخچه و … احتمال انتخاب درست افزایش پیدا می‌کنه و در زمان اجرا صرفه جویی می‌کند.تکنیک Speculative execution: یکی دیگر از تکنیک های بهینه سازی زمان در CPU هستش. این تکنیک در زمان های انتظار خود شروع به اجرای و نگهداری نتیجه دستوراتی می‌کند که هنوز زمان اجرای انها فرا نرسیده. با این کار وقتی لازم به اجرا آن دستورات باشد از قبل آنها اجرا شده و نتیجه مشخص است.تکنیک Caching: یکی دیگر از تکنیک های افزایش سرعت پردازش است که نتیجه داده های محاسبه شده یا برخی داده های ضروری در یک حافظه بسیار پرسرعت در کنار پردازنده ذخیره می‌شوند.سلسله مراتب cache وقتی بیش از یک هسته شروع به اجرای دستورات و تغییر داده‌ها می‌کند. اونها داده‌های موجود تو cache رو با هم تغییر می‌دن.با توجه به memory hierarchy، در پردازش های موازی زمانی که داده ای بین core ها مشترک هستش ما نمی‌تونیم بگیم که همیشه همه کارها به همون ترتیبی که نوشتن شدن اجرا می‌شن. دلیل اصلی هم memory visibility و reordering هستش. https://gist.github.com/Darvishiyan/cc153e5ada0107140ed56d9bdcd2f42a قبل از شروع به مثال بالا نگاه کنید و فرض کنید که پردازنده thread ها رو توی core های متفاوتی اجرا می‌کنه.توی main thread یک کپی از متغیر های number و ready وجود داره.توی reader thread هم یک کپی از متغیر های number و ready وجود داره.در پردازنده های جدید دستور نوشتن بلافاصله بعد از صادر شدن اجرا نمی‌شه. در واقع CPU دوست داره این دستورات رو بزاره تو صف توی special write buffer (بافر مخصوص نوشتن). و بعد از مدتی همه اونها رو یک مرتبه توی حافظه اصلی بنویسه.این به این معنی هستش که وقتی در یک thread داده ای تغییر می‌کنه، هیچ تضمینی نیست که توی باقی thread ها هم اون داده تغییر کنه. به عبارت دیگه در مثال بالا ممکنه reader thread تغییرات داده ها رو بلافاصله یا با تاخیر دریافت کنه یا هرگز دریافت نکنه.داده ها در یک thread به همون ترتیبی که توی یک thread دیگه داده تغییر می‌کنه تغییر رو دریافت نمی‌کنن. این یک روش بهینه سازی برای بهبود عملکرد هستش. قسمت های مختلف این بهینه سازی رو انجام می‌دن. و بهش می‌گیم reordering.پردازشگر ممکنه داده های رو به ترتیبی غیر از ترتیبی که توی برنامه نوشته شده بنویسه.پردازشگر ممکنه در اجرای برنامه از تکتیک out-of-order execution استفاده کنه.کامپایلر JIT هم ممکنه با هدف بهینه سازی تغییری در ترتیب اجرای دستورات بده.هدف volatile اطمینان از بروز شدن متغیرها توی باقی فضاهای حافظه استفاده هستش. با استفاده از این modifier برنامه در حال اجرا به پردازنده می‌گه که این متغیر و هر جایی که ازش استفاده شده رو reorder نکن. همچنین بلافاصله بعد از تغییر این متغیر همه cache ها رو بروز کن.در برنامه نویسی multi thread دوتا قانون باید رعایت بشه.یک: Mutual Exclusion یعنی فقط یک thread یک تغییر مهم رو ایجاد می‌کنه.دو: Visibility یعنی بعد بوجود اومدن تغییر توی داده‌های مشترک، باید همه thread هایی که داده بین اونها مشترک هستش، تغییرات رو دریافت کنن.متدها یا بلاک های synchronized هر دوی این شرایط رو برای ما فراهم می‌کنن. البته با کاهش پرفورمنس.حالا زمانی که ما میخواییم چندین thread بتونن یک بلاک کد رو به صورت موازی اجرا کنن و لازمه مطمئن باشیم که همه از تغییرات متغیرهای مشترک آگاه هستن باید از volatile استفاده کنیم. تا مشکل visibility داده ها رو برای ما حل کنه.استراتژی Happens-Before Ordering: این استراتژی در رابطه به متغیر های volatile می‌گه؛ نوشتن توی متغیر های volatile قبل از خوندن اونها اتفاق می‌یوفته. این یک قانون درباره متغیر های volatile در Java Memory Model هستش JMM.تکنیک Piggybacking: با توجه به استراتژی Happens-Before در ترتیب حافظه. در بعضی شرایط ما می‌تونیم visibility یک متغیر رو piggyback (کول کردن - به دوش کشیدن) کنیم روی یک متغیر volatile دیگه. https://gist.github.com/Darvishiyan/e405d378af536fd84057c65c90a0cb7b تو مثال بالا ما هر دو متغیر رو volatile کردیم. که این کار باعث کاهش کارایی برنامه می‌شه.استراتژی Happens-Before برای این مثال می‌گه: همه چیز باید بعد از تغییر متغیر ready و قبل از خوندن مقدار این متغیر visible باشه. https://gist.github.com/Darvishiyan/e48cd1ba79684bceebe60022a823df5d اما با توجه به این استراتژی ما می‌تونیم متغیر number رو به صورت معمولی تعریف کنیم و تغییرات اون piggyback کنیم روی ready یا به عبارت دیگه بر روی دوش متغیر ready اطلاعات این متغیر رو جابجا کنیم.با توجه به این مفاهیم و با کمتر تعریف کردن متغیر های volatile ما می‌تونیم علاوه بر گارانتی کردن visibility کد بهینه تری هم بنویسیم. http://tutorials.jenkov.com/java-concurrency/volatile.html  https://www.baeldung.com/java-volatile  https://dzone.com/articles/java-concurrency-understanding-the-volatile-keyword  https://www.geeksforgeeks.org/volatile-keyword-in-java/ </description>
                <category>حسام درویشیان</category>
                <author>حسام درویشیان</author>
                <pubDate>Tue, 04 Jan 2022 19:09:50 +0330</pubDate>
            </item>
                    <item>
                <title>گردل و کاتلین</title>
                <link>https://virgool.io/MobileLab/gradlekotlindsl-y0wxyjjog7es</link>
                <description>در پست قبلیم گفتم که می‌شه با کاتلین اسکریپت گردل رو بنویسین، در این پست می‌خوام این فرایند رو توضیح بدم. https://virgool.io/@darvishiyan/gradle-1-stbcpmm1epne مزایاتکمیل خودکارکمک به محتوادسترسی به مستنداتدسترسی به سورس کدقابل بازسازیچون معادل فارسی بعضی چیزا خیلی بی‌معنا بود لینکشون رو هم براتون گذاشتم.معایبعدم ویرایش گردل از دیالوگ Project Structureاگه چیز دیگه ای دیدم میام می‌نویسمشما می‌تونین از نسخه ۱ کاتلین DSL در گردل ۴.۱۰ و بالاتر همراه اندروید استدیو ۳.۱.۴ و بالاتر استفاده کنید. https://blog.gradle.org/gradle-kotlin-dsl-release-candidate برای شروع باید نام فایل‌های .gradle رو به .gradle.kts تغییر بدیم و متحوای آنها را آپدیت کنیم.پسوند فایل‌های اسکریپت گردل به زبان کاتلین KTS است.برای تغییر نام فایل‌ها می‌تونید از کلید ترکیبی (Shift + F6) استفاده کنید.اولین فایل settings.gradle رو انتخاب می‌کنیم. نامش را به setting.gradle.kts تغییر می‌دیم و محتوای آن هم مطابق نمونه زیر تغییر می‌کنه. // beforeinclude &#x27;:app&#x27;// afterinclude(&quot;:app&quot;)فایل بعدی build.gradle در ریشه پروژه رو انتخاب می‌کنیم و بعد از تغییر نام مطابق همان الگویی که قبلا گفته بودیم محتوای آن را مثل تصویر زیر تغییر می‌دیم.و در انتها هم فایل build.gradle در شاخه ماژول پروژه را انتخاب می‌کنیم و پس از تغییر نام محتوای آن را مثل تصویر زیر تغییر می‌دیم.سورس کدی از نمونه این تغییرات رو می‌تونید در آدرس زیر ببینید. https://github.com/Darvishiyan/GradleKotlinDSL </description>
                <category>حسام درویشیان</category>
                <author>حسام درویشیان</author>
                <pubDate>Fri, 01 Mar 2019 14:19:15 +0330</pubDate>
            </item>
                    <item>
                <title>اندروید و گردل: معرفی ساختار</title>
                <link>https://virgool.io/MobileLab/gradle-1-stbcpmm1epne</link>
                <description>اندروید استدیو برای بیلد پروژه‌ها از ابزاری به نام gradle استفاده می‌کند. زبان این ابزار groovy نام داره (البته با کاتلین هم میشه برای این ابزار کد نوشت) و یکی از قدرتمند ترین ابزارهای بیلد پروژه‌هاست. فرایند بیلد پروژه در gradle به این صورت ذیل می باشد.همان گونه که در تصویر فوق مشخص است داده‌های برنامه به همراه کتابخانه‌هایی که در آن استفاده شده کامپایل شده و فایل dex تولید می‌شود، سپس با کلید مورد نظر sign می‌شود و فایل قابل نصب بدست می‌آید. بیلد یک پروژه جنبه‌های مختلفی دارد:یک: Build Typesمراحل فرایند ساخت پروژه را مشخص می‌کند. برای مثال در حالت دیباگ کلیدی که مورد استفاده قرار می‌گیرد، شرایط درهم ریزی کد و کوچک شدن و… را مشخص می کند. بیلد تایپ‌های پیشفرض debug و release هستند ولی شما می‌تواند به آنها اضافه کنید.  دو: Product Flavorsبا اضافه کردن به flavor های پروژه شما می‌توانید نسخه‌های تفکیک شده‌ای از محصول خود داشته باشید. برای مثال از یک سورس کد نسخه دمو و اصلی برنامه را خروجی بگیرید. توجه داشته باشید از نام‌هایی رجیستر شده برای flavor مانند test، debug، main و… استفاده نکنید.سه: Build Variantsاین قابلیت بیلد به شما این اختیار را می‌دهد که ریسورس‌های دو flavor را از هم جدا کنید. برای مثال این امکان را برای شما فراهم می کند که از دو آیکن متفاوت برای نسخه اصلی برنامه و نسخه دمو برنامه استفاده کنید. برای این کار شما باید هم نام flavor خود یک پوشه در کنار پوشه main ایجاد کنید و در پوشه ساخته شده پوشه هایی هم نام ریسورس‌های پوشه main بسازید، تنها نکته‌ای که باید به آن توجه داشته باشید این است که از هم‌نامی برای جایگزین شدن فایل‌ها در زمان بیلد استفاده کنید.چهار: Manifest Entriesاین مفهوم به شما کمک می‌کند تا از چندین فایل منیفست بهرمند شوید. با استفاده از این قابلیت می‌توانید یک فایل منیفست را برای هر کدام از flavor ها به صورت مجزا پیکربندی کنید.پنج: Dependenciesاین قابلیت که معادل فارسی اون میشه وابستگی به شما کمک می‌کنه تا از کتابخانه‌های منتشر شده در اینترنت به سادگی استفاده کنید. فقط کافی لینک اونها رو توی فایل پیکربندی پروژتون قرار بدید.شش: Signingبا استفاده از این ویژگی gradle شما می‌توانید امضا فایل خروجی پروژه خود را مشخص کنید، تا در زمان بیلد پروژه از فایل امضا مشخص شده برای پروژه استفاده شود. امضا کردن فایل خروجی برنامه باعث می‌شود تا شما کلیدی منحصر به فرد برای پروژه داشته باشید. فایل امضا همان keyStore است. اگه فایل امضا برنامه‌ای به هر دلیلی تغییر کنه کاربرها دیگر قادر به بروزرسانی برنامه نیستند و باید برای نصب نسخه جدید برنامه قبلی خود را حذف کنند.هفت: ProGuardیکی از قابلیت های خوب gradle پروگارد است. شما می‌تونید در پروگارد تعدادی روال تعریف کنید که gradle در زمان بیلد پروژه با استفاده از آنها کدهای شما رو کوچک و مبهم کنه. این کار باعث می‌شود تا علاوه بر کاهش حجم پروژه در صورتی که شخصی کد برنامه شما را دیکامپایل کند قادر به خواندن کد شما نباشه.هشت: Multiple APK Supportاین ویژگی به شما این امکان را می‌دهد که همزمان چند فایل خروجی با داده‌های مختلف بدست بیاورید. برای مثال همزمان فایل خروجی نسخه اصلی و نمایشی را می‌تونید خروجی بگیرید. ساختار فایل های پیکربندی:شما میتوانید فایل‌های پیکربندی شخصی خودتان را داشته باشید، پیکربندی را تقسیم کنید به چند فایل یا همه دستورات را در یک فایل بنویسید. برای تغییر در ساختار استاندارد پیکربندی پروژه لازم است که به میزان تغییرات فایل‌ها، پیکربندی پیشفرض رو دستکاری کنید و مطابق نیاز آنها را ویرایش کنید. ساختار پیکربندی پیشفرض یک پروژه اندروید را می‌توانید در تصویر زیر مشاهده کنید. شما می‌توانید این پیکربندی را تغییر دهید اما باید قبل از این کار حتما حوزه و هدف هر فایل را به خوبی بشناسید و از حداقل های زبان groovy آگاهی داشته باشید.معرفی فایل های پیکربندی پروژه:یک: settings.gradleاین فایل در ریشه اصلی پروژه قرار دارد و ماژول‌های برنامه در آن تعریف می شود. یک نمونه ساده از آن را می توانید مشاهده کنید.include &#039;:app&#039;در صورتی که شما هر ماژولی به برنامه خود اضافه کنید باید نام آن را در ادامه این فایل بنویسید.دو: build.gradle سطح پروژهاین یک فایل سطح بالا است، همانگونه که در تصویر می‌بینید این فایل در ریشه پروژه قرار دارد. این فایل پیکربندی بر روی تمام ماژول‌ها اعمال می شود و همه ماژول‌ها به آن دسترسی دارند. در بلاک buildscript شما می توانید تمام مخازن و وابستگی‌های کل ماژول‌های خودتان را تعریف کنید. در بلاک allprojects شما می توانید تمام مخازنی که کل ماژول‌های پروژه به آنها نیاز دارند را تعریف کنید، برای مثال third-party ها، کتابخانه‌ها و…. یکی دیگر از قابلیت های جذاب این فایل پیکربندی بلاک ext‌ هست، که به شما اجازه می‌دهد پیکربندی خود را توسعه دهید. برای این کار شما در این بلاک متغییر هایی که نیاز دارید را تعریف می‌کنید و در دیگر قسمت‌های فایل‌های پیکربندی از این متغییرها استفاده می کنید.ext {
    propertyName = 28
    ...
}
android{
    compileSdkVersion rootProject.ext.propertyName
    ...
}سه: build.gradle سطح ماژولاین فایل پیکربندی در سطح ماژول است و در آدرس project/{module}/build.gradle قرار دارد. تنظیمات این فایل بر روی ماژول جاری اعمال می‌شود. این تنظیمات به شما اجازه می‌دهد تا ماژول سفارشی تولید کنید. برای مثال تنظیمات مربوط به flavor ها در این فایل نوشته می شود. در خط اول این فایل با دستور زیر به gradle معرفی می‌کنیم که این پیکربندی برای پلاگینی اندرویدی است. بلاک android که فقط خاص پروژه های اندروید است قابل شناسایی می‌شود. در این بلاک، پیکربندی ساخت ماژول را مشخص می کنیم.apply plugin: &#039;com.android.application&#039;شما همچنین می‌توانید مخازن و وابستگی‌های مورد نیاز این ماژول را در این فایل پیکربندی بنویسید.معرفی فایل‌های پیکربندی gradle:یک: gradle.propertiesاین فایل برای پیکربندی gradle استفاده می‌شود. برای مثال داده‌های پراکسی، سایز رم مورد نیاز برای بیلد پروژه و… را در این فایل می توانید تنظیم کنید.دو: local.propertiesاین فایل برای پیکربندی محیط بیلد پروژه است. برای مثال آدرس SDK و NDK در این فایل نوشته شده است. همگام سازی پروژه:در زمانی که شما تغییری در هر کدام از فایل های پیکربندی ایجاد کنید باید gradle را همگام سازی کنید. در بیشتر مواقع در بالای فایل های پیکربندی در نواری زرد رنگ عبارت Sync Now نمایش داده می شود که فقط لازم است بر روی آن کلیک کنید.در صورتی که خواستید gradle را همگام سازی کنید و لینک فوق برای شما نمایش داده نشده بود میتوانی از نوار ابزار بر روی آیکن همگام سازی کلیک کنید تا پیکربندی شما همگام سازی شود.  منابع بیلد:همانطور که قبلا گفتیم شما می توانید build type ها و product flavor ها متفاوتی داشته باشید. در صورتی که بخواهید منابع این دو نوع را از پروژه اصلی جدا کنید، باید به صورت زیر در ساختار پوشه‌های برنامه تغییر ایجاد کنید.ساختار پیشفرض پروژهsrc/main/تغییر در منابع برای یک build type خاصsrc/buildType/تغییر در منابع برای یک flavor‌ خاصsrc/productFlavor/ترکیب یک build type و flavorsrc/productFlavorBuildType/ترکیب دو flavorsrc/productFlavor1ProductFlavor2/مثال:src/main/
src/full/
src/debug/
src/fullDebug/برای تغییر در build type و product flavor فعال اندروید استدیو میتونید از پنجره build variant‌ استفاده کنید.</description>
                <category>حسام درویشیان</category>
                <author>حسام درویشیان</author>
                <pubDate>Sun, 26 Aug 2018 14:24:50 +0430</pubDate>
            </item>
                    <item>
                <title>رشته ها و استایل دادن به اونها در اندروید</title>
                <link>https://virgool.io/@darvishiyan/strings-rbl17dyvmrch</link>
                <description>اولین و معروف‌ترین کلاس String هست، این کلاس تغییر ناپذیر هستش یعنی هر بار که مقدارش رو تغییر بدید یک شی جدید در از این کلاس ساخته میشه. در این نوع از رشته‌ها شما هیچ تغییری در استایل نمی‌تونین ایجاد کنین.کلاس بعدی StringBuilder‌ هستش، این کلاس قابلیت تغییر رو داره و با هربار تغییر اون یک شی جدید ساخته نمیشه، اما باز هم در این نوع از رشته‌ها شما هیچ تغییری در استایل نمی‌تونید بدید.کلاس بعدی SpannedString هست، این کلاس مانند String تغییر ناپذیر است، اما بر خلاف اون استایل میگیره اما استایل این نوع از رشته‌ها نیز قابل تغییر نیست، فکر نکنم لازم باشه بگم با هر تغییری در این شی یک نوع جدید از اون ساخته میشود.کلاس بعدی SpannableString هست، این کلاس تمام خصوصیاتش مانند کلاس SpannedString هست با این تفاوت که استایل رشته قابل تغییر است. کاربرد این کلاس در زمانی هستش که شما نیازی به تغییر متن ندارید اما نیاز دارید استایل متن را تغییر دهید.کلاس بعدی SpannableStringBuilder نام داره و از نامش کاملا مشخصه که در این کلاس هم متن و هم استایل قایل تغییر هستش، این کلاس زمانی کاربرد داره که شما نیاز دارید که متن و استایل رو تغییر بدید.یه نکته هم راجه به CharSequence میخوام بهتون بگم. CharSequence یک اینترفیس هستش که تمام کلاس‌های بالا اون رو implement کردن. شما میتونید با استفاده از این شی طیف وسیعی رو پوشش بدید و کدهایی با انعطاف بالا بنویسید. شما میتونید اون رو به هر نوع دیگه‌ای که لازم دارید downcast کنید و از اون استفاده کنید. همه اینها رو گفتم تا یکم براتون از SpannableString بگم، با استفاده از متد setSpan این کلاس میتونید هر استایلی که میخواین به متنتون بدین. این متد چهارتا ورودی میگیره، ورودی اول اون ستایل هست و ورودی های بعدی به ترتیب اندیس شروع، اندیس پایان و فلگ است. یکی از مهمترین پارامتر های setSpan پارامتر فلگ هستش، این پارامتر در SpannableStringBuilder استفاده میشه و مشخص می‌کنه که استایل چه عکس‌العملی در زمان اضافه کردن متن در اندیس شروع و پایان داشته باشه. یکی دیگر از راههای استایل دادن به متون استفاده از کلاس Html‌ هست، با استفاده از متد fromHtml می‌تونید کد html خودتون رو تبدیل به یک شئ از نوع Spanned کنید. البته باید بگم که محدودیت‌های این کار خیلی زیاده و خیلی از دستورات html معتبر نیست. اما در جاهای محدود کاربرد دارد؛ مثلا زمانی که یک متن با استایل خیلی ساده رو می‌خواید از سرویس‌دهنده بگیرید و نمایش دهید.سورس این پروژه در آدرس زیر در دسترس شما خواهد بود. https://github.com/Darvishiyan/Strings </description>
                <category>حسام درویشیان</category>
                <author>حسام درویشیان</author>
                <pubDate>Tue, 07 Aug 2018 00:25:47 +0430</pubDate>
            </item>
            </channel>
</rss>