<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>پست‌های انتشارات ImAndroid</title>
        <link>https://virgool.io/ImAndroid/feed</link>
        <description>برنامه نویسی اندروید</description>
        <language>fa</language>
        <pubDate>2026-04-15 04:34:29</pubDate>
        <image>
            <url>https://files.virgool.io/upload/publication/genuhmgjnheo/yz6hre.png</url>
            <title>ImAndroid</title>
            <link>https://virgool.io/ImAndroid</link>
        </image>

                    <item>
                <title>اپراتورهای == و === و .equals در کاتلین و جاوا</title>
                <link>https://virgool.io/ImAndroid/%D8%A7%D9%BE%D8%B1%D8%A7%D8%AA%D9%88%D8%B1%D9%87%D8%A7%DB%8C-%D9%88-%D9%88-equals-%D8%AF%D8%B1-%DA%A9%D8%A7%D8%AA%D9%84%DB%8C%D9%86-%D9%88-%D8%AC%D8%A7%D9%88%D8%A7-xkj4piodvpdh</link>
                <description>کدام یک از گزینه های زیر صحیح است؟ (https://t.me/imandroid/51)اپراتور == در جاوا و کاتلین یه یک معنی می باشنداپراتور == در جاوا محتوا و مقدار دو متغیر یا شی را مقایسه می کنداپراتور === در کاتلین معادل اپراتور == در جاوا است&amp;amp;amp;amp;lt;br/&amp;amp;amp;amp;gt;تابع .equals() در جاوا معادل اپراتور === در کاتلین است✅(سطح سوال متوسط) - جواب صحیح گزینه ی ۳ است.❇️عملگر === در کاتلین و عملگر == در جاوا هر دو رفرنسهای دو طرف را مقایسه میکنند.نصف کنیم؟? عملگر == در کاتلین محتوای دو متغیر را با هم مقایسه میکند در حالی که در جاوا اصلا اینطور نیست و این عملگر رفرنس دو متغیر را مقایسه می کند.بگذارید اول تکلیف مون را با جاوا مشخص کنیم بعد بریم سراغ کاتلین(اگه جاوا اوکی اید برید سراغ بخش کاتلین) :? فرض کنید در جاوا یک شی به نام person داریم که توی سازنده ش هم اسم رو میگیره :Person person1 = new Person(“Iman”)Person person2 = new Person(“Iman”)— —(person1 == person2) —&gt; falseهمانطور که میدونید اینجا person1 و person2 صرفا یک رفرنس هستند به آدرس اصلی شی ساخته شده در حافظه ی Heap که مسلما با هم برابر نیستند.(در واقع آدرس ها یک عدد هستند)? اما اگر به جای شی ، دو متغیر پایه ای (primitive variable) داشتیم:int a = 10;int b = 10;— —(a == b) —&gt; trueنتیجه true است چرا که در primitive variable ها دقیقا خود مقدار درون متغیر ذخیره می شود ( در حافظه ی stack)? اما تابع .equals در جاوا محتوای اون دو خانه ی حافظه رو بر میداره و با هم مقایسه میکنه:(person1.equals(person2) ) —&gt; falseباز هم جواب false است. اینجا در محتوای هر دو خانه شی هایی از مدل Person ساخته شده که اسم هر دوی آنها هم Iman است! اما خب اینها دو شی جدا هستند و قطعا یکی نیستند! ( خب این همه Iman داریم همه شون یکی ان؟?)? اما خب راجع به String ها کمی داستان متفاوت است.اول از همه به این تعریف نگاه کنید:String name1 = “iman”;حالا به این هم نگاه کنید:String name1 = new string(&quot;Iman&quot;);? در واقع String یک کلاس است و یک متغیر primitive نیست پس قاعدتا نحوه ی صحیح تعریف یک متغیر از string حالت دوم است اما نکته ای که وجود داره اینه که جاوا برای string یک استثنا قائل شده و اجازه داده که به صورت اول هم بتونیم از روش شی بسازیم.? که خب البته تفاوت فقط توی همین نوشتن نیست و توی نحوه ی ذخیره سازی هم تفاوت دارند. جاوا توی حالت اول میاد و مقدار رو توی یک string pool ذخیره میکنه توی این حالت اگه شما به مجددا یک مقدار مشابه رو بخواید توی یک متغیر استرینگ بریزید دیگه یه خونه ی جدید از حافظه رو بهش اختصاص نمیده و به همون خونه ی قبلی از حافظه اشاره میکنه. فقط کافیه به عکس زیر نگاه کنید تا دیگه همه چی روشن بشه.این هم اضافه کنیم تمومه - s1.equals(s3) --&gt; true? اما در کاتلین اوضاع از چه قرار است؟? عملگر === در کاتلین دقیقا همان نقش عملگر == در جاوا رو ایفا میکند چرا که رفرنس های دو طرف را فقط مقایسه می کند ( که هر دو به یک خانه از حافظه اشاره میکنند یا نه یا به عبارتی آیا هردو دقیقا یک شی هستند یا نه) و خب نقیض این عملگر هم ( ==! ) است.?اما همانطور که در ابتدای متن هم اشاره کردم عملگر == در کاتلین را رسما میتونیم بگیم مشابه .equals در جاوا است چرا که مقدار دو طرف را باهم مقایسه میکند.اما نکته ی مهمی این وسط توی کاتلین راجع به data class ها وجود داره! خوب به این مثال دقت کنید :class Person (val name: String)val person1 =  Person(“Iman”)val person2 =  Person(“Iman”)— —(person1 == person2) —&gt; false(person1 === person2) —&gt; false(person1.name == person2.name) —&gt; true?همونطور که می بینید دقیقا مثل جاوا  در دو طرف تساوی دوی شی person که همنام هم هستند قرار دارند که چون دو شی متفاوت هستند با هم برابر نیستند. اما کاتلین در data class خیلی با شعور می شود و میاد و ویژگی های دو شی را با هم مقایسه میکند. دقت کنید:data class Person (val name: String)(person1 == person2) —&gt; true (person1 === person2) —&gt; true (person1.name == person2.name) —&gt; true?اما تابع equals در کاتلین به چه معنی است؟ این هم دقیقا مثل ==  در کاتلین عمل میکنه یعنی مقدار و محتوای دو طرف رو مقایسه میکنه. اما خب یک تفاوت ریز هم داره که اون هم توی اعداد اعشاری هستش که برای توضیحش به چندتا پیش زمینه نیاز داریم:یک اینکه قرارداد IEEE754 چی هستش ، که راجع بهش توی پست های اول کانال تلگرام کلی صحبت کردم.( اینجا رو ببینید)دوم اینکه در اعداد اعشاری Nan ها چی هستند دقیقا که این رو همینجا یه مروری میکنیم:در واقع Nan مخفف Not a number است . همین ۳۴ سال پیش (سال ۱۹۸۵) برای اینکه cpu ها برای محاسبات شون از یک استاندارد پیروی کنند سازمان IEEE میاد و یک استاندارد رو به نام IEEE754 اعلام میکنه که الان تقریبا همه ی cpu ها از اون پیروی می کنند.به طوری کلی توی این استاندارد راجع به نحوه ی محاسبه و نمایش اعداد اعشاری قرارداد هایی شده که یکی از موارد این قرارداد مشخص میکنه که یک سری از اعداد که غیر قابل نمایش یا بدون تعریف هستند(یا حتی زمانی که خطایی رخ میدهد) باید Nan نشان داده شوند.(مثلا تقسیم بر صفر)توی جاوا هم Double.NaN و Float.NaN رو هم میتونید پیدا کنید.که در تعریفشون هم گفته شده:?حالا نکته ی کار ما اینجاست که این Nan ها امکان مقایسه با هم رو هم دارند و این رفتاری که توی مقایسه کردنها از خودشون نشون میدن کلی بحث ایجاد کرده که آیا مطابق با قرارداد IEEE754 رفتار میکنند یا نه. که اینجا در کاتلین تابع equal برای Nan ها مخالف با قانون IEEE754 رفتار میکند . به طور مثال : val negZero = -0.0f val posZero = 0.0f println(negZero == posZero)         //true println(negZero.equals(posZero))    //false println(negZero === posZero)        //trueبرای توضیحات بیشتر به لینک های زیر میتونید سر بزنید:https://medium.com/@agrawalsuneet/equality-in-kotlin-and-equals-d8373ef529f1https://kotlinlang.org/docs/reference/equality.html#floating-point-numbers-equality</description>
                <category>ImAndroid</category>
                <author>ایمان صدریان</author>
                <pubDate>Fri, 18 Oct 2019 15:03:09 +0330</pubDate>
            </item>
                    <item>
                <title>الگوی Event Handling و CallBack در اندروید</title>
                <link>https://virgool.io/ImAndroid/%D8%A7%D9%84%DA%AF%D9%88%DB%8C-event-handling-%D9%88-callback-%D8%AF%D8%B1-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-mcpl8fqpkydx</link>
                <description>یکی از الگوهای معروف و ساده ای که میشه با اینترفیس ها پیاده سازی کرد همین Event Handling هست. و احتمالا جاهای مختلفی هم از آنها استفاده کردید. به خصوص وقتی دو تا کلاس داریم که ارتباط تنگاتنگی با هم دارند. درو واقع الگوهای &quot;listener&quot; و &quot;observer&quot; از رایج ترین استراتژی ها برای ایجاد callback (صدا کردن یا مشاهده کردن نتیجه ای از یک قطعه کد) به صورت موازی در برنامه نویسی اندروید هستند.یکی از اینترفیس هایی که به همین منظور استفاده می شود همین setOn ClickListener معروف هست: https://gist.github.com/imansdn/14d3d54a1338b3f71a0be4741cdf1121 ما اینطوری میتونیم پیچیدگی های کد رو با مجزا سازی قسمتهای مختلف کد در قالب کلاس های مختلف کم کنیم (پیروی از قانون کپسوله سازی) و  در جای درست و منطقی به هر قسمتی هم که بخواهیم دسترسی داشته باشیم.مراحل ساخت یک listener سفارشی در قالب یک مثال  یک کلاس داریم (کلاس child) که یه سری عملیات برای ریکوئست به سرور رو داریم اونجا انجام میدیم.و میخواهیم فقط نتیجه ی این عملیات رو به محض اینکه انجام شد به یک کلاس دیگه (کلاس parent) خبر بدیم.یک اینترفیس به نام NetworkRequestListener درون کلاس child می سازیم که درون آن یک متد به نام onResult می نویسیم.public class ChildClass {
    public interface NetworkRequestListener {
      public void onResult(SomeData data); // این متد میتواند ورودی هم نداشته باشد
      }
  }یک نمونه از اینترفیس NetworkRequestListener را در همین کلاس child (کلاسی که عملیات انجام می شود) می سازیم:public class ChildClass {
private NetworkRequestListener listener;
    public interface NetworkRequestListener {
     public void onResult(SomeData data); // این متد میتواند ورودی هم نداشته باشد
        }
  }کار دیگه ای که باید اینجا انجام بشه اینه که توی سازنده ی کلاس child این instant ای که به نام listener ساختیم را null کنیم .چرا؟ چون  قصد داریم با یک متد setter این listenr را مقدار بدهیم و از آنجایی که امکان دارد که این setter از جاهای مختلفی صدا زده شود ، هر بار در سازنده مقدارش را به null بر میگردانیم.public class ChildClass { 
private NetworkRequestListener listener;   
 public ChildClass() {
    this.listener = null; 
 }
 public interface NetworkRequestListener {    
  public void onResult(SomeData data); // این متد میتواند ورودی هم نداشته باشد    
       } 
  }حالا این setter ای که ازش صحبت کردیم هم به این صورت تعریف میکنیم:public class ChildClass {  
 private NetworkRequestListener listener;  
 public ChildClass() {  
    this.listener = null;  
     } 
       public void setResultListener(NetworkRequestListener listener) {
        this.listener = listener;
        }

   public interface NetworkRequestListener {  
   public void onResult(SomeData data); // این متد میتواند ورودی هم نداشته باشد
       }  
     }حالا در این کلاس یک متد  برای ارتباط با سرور داریم که loadData نام دارد و ما باید متد result از متغیرlistener ای که ساختیم را درست جایی که result را می گیریم صدا بزنیم:  public void loadData() {
      AsyncHttpClient client = new AsyncHttpClient();
      client.get(&amp;quothttps://mycustomapi.com/data/get.json&amp;quot, new JsonHttpResponseHandler() {         
         @Override
          public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
                          SomeData data = SomeData.processData(response.get(&amp;quotdata&amp;quot));
               if (listener != null)
                listener.onResult(data); 
                }
                    });
     }توی این کلاس دیگه کاری نداریم ، حالا بگذارید کلاس parrent را بررسی کنیم  . کارهایی که باید  در کلاس parent انجام بدیم :اولا متد setter رو بتونیم صدا بزنیم. دوما از متدهای پیاده سازی شده استفاده کنیم!public class MyParentActivity extends Activity {
  @Override
     protected void onCreate(Bundle savedInstanceState) {
     ChildClass child = new ChildClass();
    //اینجا کلاس ستر رو صدا میزنیم 
    child.setResultListener ( new  ChildClass.NetworkRequestListener() {
      @Override
        public void onResult(SomeData data) {
        	 
        }
        });
         }
         }خب ما اینجا اینترفیس listener مان را از طریق متد setter مقدار دهی کردیم . حقیقت اینه که همیشه حتما نیاید یک متد setter بنویسیم ، دو راه دیگر هم وجود دارد برای این کار  :مقدار دهی از طریق سازنده :برای این کار باید در کلاس child به این صورت عمل می کردیم:private ChildClass listener;
public ChildClass(NetworkRequestListener listener) {
 this.listener = listener; 
    }و در کلاس parent به این صورت داشتیم:ChildClass child = new ChildClass ( new ChildClass.NetworkRequestListener() {
  @Override
    public void onResult(SomeData data) {
    //we have result here!
      });
      }مقدار دهی از طریق lifeCycle event ها :این مورد که بیشتر در استفاده از Fragment ها مرسوم است . به این صورت است که ما در اکتیویتی به جای استفاده از setter و یا سازنده برای مقدار دهی listener کلاس child ( که اینجا همان fragment است) از یکی از متدهای چرخه ی حیات اندروید به نام onAttach استفاده میکنیم و از آن می پرسیم که آیا fragment ای به این اکتیویتی attach شده است یا خیر و در صورتی که فرگمنت یافت شد ، آن وقت listener درون آن را مقدار دهی میکنیم.کمی پایین تر یکی از مثال ها ی گوگل را برای ارتباط بین fragment و اکتیویتی بررسی میکنیم که آنجا از onAttach استفاده شده است.استفاده های مرسوم و معروف مثلا بعضی ها چون میخواهند در اکتیویتی ای که recyclerView رو دارند همانجا یک clickListener برای هر آیتم لیست بنویسند و نه در adapter ، به خصوص زمانی که محاسباتی در هنگام کلیک روی هر آیتم نیاز است انجام شود که جای آن در adapter نیست. می شود یک اینترفیس تعریف کرد و event کلیک شدن رو در اکتیویتی هندل کرد.یا وقتی از FragmentDialog استفاده میشه و Dialoge یک کلاس جدا هست و میخواهیم توی اکتیویتی که دیالوگ باز میشه بگیم وقتی روی هر قسمت دیالوگ کلیک شد یک کار مشخص انجام بده که احتمالا اون کار وابسته به اکتیویتی باشد. میتوانیم برای رخداد هایی که میخواهیم  اینترفیس callback بسازیم و تک تک آنها را درون اکتیویتی هندل کنیم.یا وقتی یک Fragment از قسمت منوی file --&gt; new --&gt;fragment میسازید میبینید که خود اندروید استودیو یک اینترفیس callback به صورت پیش فرض می سازد و از ما میخواهد که آن را در اکتیویتی میزبان اون فرگمنت پیاده سازی کنیم . در واقع میخواهد به ما یاد بدهد که برای ارتباط بین فرگمنت و اکتیویتی میزبان و یا همچنین برای ارتباط بین دو فرگمنت ، میتونیم از این الگو استفاده کنیم. اگر چه که اگر از معماری MVVM استفاده کنید و یک viewModel را بین هر دو فرگمنت Share کنید راه بهتری برای این ارتباط است.این مثالی است که گوگل برای ارتباط بین Fragment و اکتیویتی میزبان داده است ، بیایید با هم بررسی اش کنیم:HeadlinesFragmentpublic class HeadlinesFragment extends ListFragment {  OnHeadlineSelectedListener callback;    public void setOnHeadlineSelectedListener(OnHeadlineSelectedListener callback) {        this.callback = callback;    }    public interface OnHeadlineSelectedListener {        public void onArticleSelected(int position);    }@Overridepublic void onListItemClick(ListView l, View v, int position, long id) {    // Send the event to the host activity callback.onArticleSelected(position);}    // ...}MainActivitypublic static class MainActivity extends Activity implements HeadlinesFragment.OnHeadlineSelectedListener{
    // ...

    @Override
    public void onAttachFragment(Fragment fragment) {
        if (fragment instanceof HeadlinesFragment) {
            HeadlinesFragment headlinesFragment = (HeadlinesFragment) fragment;
            headlinesFragment.setOnHeadlineSelectedListener(this);
        }
    }

  public void onArticleSelected(int position) {
            ArticleFragment newFragment = new ArticleFragment();
            Bundle args = new Bundle();
            args.putInt(ArticleFragment.ARG_POSITION, position);
            newFragment.setArguments(args);

            FragmentTransaction transaction =             
            getSupportFragmentManager().beginTransaction();

            transaction.replace(R.id.fragment_container, newFragment);
            transaction.addToBackStack(null);

            transaction.commit();
    }
}یکی دیگه از مواردی که از این الگو استفاده میکنیم و خیلی هم مفیده و به درد میخورد زمانی است که یک callback برای یک کلاس asynchronous می نویسیم و نتیجه ی error یا success رو فقط ازش میگیریم.مثلا فکر کنید یک کلاس مجزا ساختید برای ارتباط با سرور و اونجا یک نمونه از اینترفیس تون میسازید و در جای درست onSuccess و  رو صدا میزنید. اینطوری بیرون از آن کلاس میتونید به اون لحظه که عملیات موفق آمیز بوده و یا با شکست رو به رو شده دسترسی داشته باشید و اکشن مناسبی رو نشون بدید.نام گذاری هانام گذاری اینترفیس callback معمولا به صورت PascalCase هستند و با On یا SetOn شروع می شود سپس یک اسم مرتبط با آن افزوده می شود و در نهایت با یک Listener پایان می یابد : On + {select} + ListenerSetOn + {select} + Listenerنام گذاری متد های درون اینترفیس هم طبق معمول camelCase هستند ، با on به علاوه ی یک نام مرتبط و کوتاه که وظیفه ی آن متد را با یک نگاه برساند نوشته می شوند: on+{Edit}on+{Delete}on+{Exit}منابع https://guides.codepath.com/android/Creating-Custom-Listenershttps://developer.android.com/training/basics/fragments/communicating.html </description>
                <category>ImAndroid</category>
                <author>ایمان صدریان</author>
                <pubDate>Wed, 31 Jul 2019 19:41:22 +0430</pubDate>
            </item>
                    <item>
                <title>خطای نهان در محاسبات با double و float !</title>
                <link>https://virgool.io/ImAndroid/%D8%A2%DB%8C%D8%A7-double-%D9%88-float-%D8%AF%D8%B1-%D8%AC%D8%A7%D9%88%D8%A7-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%B9%D9%85%D9%84%DB%8C%D8%A7%D8%AA-%D8%B1%DB%8C%D8%A7%D8%B6%DB%8C-%D9%85%D9%86%D8%A7%D8%B3%D8%A8-%D9%87%D8%B3%D8%AA%D9%86%D8%AF-osnle7dhsjux</link>
                <description>در این پست  به سوال مهم زیر می پردازیم:&quot; آیا نوع داده ی double و float برای عملیات ریاضی مناسب هستند؟ &quot;?پاسخ کوتاه اینه که در انجام عملیات ریاضی این دو نوع متغیر دقیق عمل نمی کنند و بعضی اوقات حاصل بسیار نزدیک به جواب اصلی است اما دقیقا همان نیست.?این دو نوع متغیر نباید برای مقادیر مالی وهرآنچیزی که دقتش اهمیت دارد استفاده شود. و برای مواردی که مقدار نیاز است دقیق باشد، باید از متغیر BigDecimal در جاوا استفاده کرد.?اما باید در نظر داشت که BigDecimal بسیار  کند تر عمل می کند! و اگر دقت خیلی مورد اهمیت نیست بهتر است از double یا float استفاده کرد و در نهایت اعداد را گرد کرد.? اما اگر مایلید علت را بدانید بقیه ی متن رو مطالعه کنید.? فرض کنید دو متغیر از جنس float یا double تعریف کنید و مقدار یکی را 2.1 و اون یکی رو 3.3 بگذارید. مجموع دو متغیر را چاپ کنید.چه میبینید؟?بر خلاف انتظار نتیجه 5.4 نیست! نتیجه 5.3999996 است.(می توانید امتحان کنید!)این بار مقدار هر دو را 2.5 بگذارید. مجموع را چاپ کنید. نتیجه 5.0 است!?این قضیه در سایر عملیات های ریاضی هم برای float و double پیش میاد. تا اینجا فهمیدیم که این دو نوع متغیر در جاوا نتیجه ی دقیقی به ما نمیدن!?اما ، واقعا چرا؟??قاعدتا کسانی که رشته شون کامپیوتر هست باید این رو بهتر بدونن و البته اینجا من فقط به کلیت موضوع  اشاره میکنم و در آخر چندتا رفرنس برای اطلاعات بیشتر معرفی می کنم.?اول به این دو تعریف یه نگاه بندازید:? عدد ممیز شناور(float point number) چیست؟? “اعداد ممیز شناور برای نمایش کمیت هایی استفاده می شوند که توسط اعداد صحیح قابل نمایش نیستند؛ چون یا آن ها دارای مقادیر کسری هستند یا این که خارج از محدوده قابل نمایش از نظر اندازه ی پهنای بیتی سیستم قرار دارند.”?استاندارد IEEE754 چیست؟? “ در سال 1985 استاندارد 754 IEEE مطرح شداين استاندارد واگرايي شيوه هاي به كار رفته براي نمايش مميزشناور را كاهش داد.بدين ترتيب برنامه هاي نوشته شده براي مقاصد علمي قابل حمل شدند.بسیاری از واحدهای ممیز شناور اکنون از استاندارد IEEE (بخوانید آی‌تریپل‌ئی) استفاده می‌کنند.. ”? خب پس از دانستن این دو تعریف باید بگیم که ،‌در علوم کامپیوتر اعداد صحیح را خیلی ساده میتونیم به باینری تبدیل کنیم. اما برای اعداد اعشاری چالش بزرگی پیش رو هست تا علاوه بر قابل فهم بودن باینری شده ی اعداد اعشاری برای کامپیوتر ، دامنه ی خوبی از اعداد رو هم شامل بشن ، دقتشون بالا باشه و سرعت پردازششون خوب باشه تا سریع بشه باهاشون کار کرد و...? اولین بار که دانشمندان علوم کامپیوتر با این چالش رو به رو شدند راه های مختلفی برای پردازنده های مختلفی ارایه می کنند  که هر کدومش دقت خاص خودش رو داشته.? در نهایت اتفاقی که میافته اینه که IEEE میاد و یک استانداردی رو با الگو گیری از نماد علمی اعداد ارایه می کنه به نام STD IEEE754.( که std همون standard هست)❇️ اما علت روی دادن این خطا چیست؟ به طور کلی وقتی یک محاسبه مقداری را ایجاد می کند که نمی تواند دقیقا به وسیله ی قالب ممیز شناور ارایه شده توسط IEEE نمایش داده شود، سخت افزار باید نتیجه را به مقداری که به درستی نمایش داده می شود، گرد کند!در استاندارد IEEE 754، روش پیش فرض برای این کار این است که به نزدیک ترین عدد گرد شود.?امروزه همه کامپیوترهای مدرن از نمایش ممیز شناور که در استاندارد IEEE 754 مشخص شده برای تمامی اعدادی که با یک مانتیس و یک توان نمایش داده می شوند، بهره می‌برند.?اگر دوست دارید که بیشتر درمورد IEEE 754 بدونید لینک های فوق العاده ی زیر رو از دست ندید:? yon.ir/Yfcx4? yon.ir/oQx0p? yon.ir/bKVim? yon.ir/X6oR4? yon.ir/ZsF14? yon.ir/UfABs</description>
                <category>ImAndroid</category>
                <author>ایمان صدریان</author>
                <pubDate>Mon, 24 Jun 2019 18:10:22 +0430</pubDate>
            </item>
                    <item>
                <title>???‍?? تا حالا با نویز سفید کد زدی ؟</title>
                <link>https://virgool.io/ImAndroid/%D8%AA%D8%A7-%D8%AD%D8%A7%D9%84%D8%A7-%D8%A8%D8%A7-%D9%86%D9%88%DB%8C%D8%B2-%D8%B3%D9%81%DB%8C%D8%AF-%DA%A9%D8%AF-%D8%B2%D8%AF%DB%8C-xqivxudyzhtf</link>
                <description>?واسه یه سری کارا میشه با موزیک کار کرد اینجوری علاوه بر اینکه کیف میده تمرکز و انرژی هم میاره! مثل زمانی که بخوای یه چیزی رو طراحی کنی یا کارایی که زیاد پردازش و تجزیه تحلیل نخواد.? اما یه سری کارا دقیقا برعکس هستن و باید محیط آروم باشه و موزیک هم تمرکز رو بهم میریزه.مثل کد زدن به خصوص زمانی که میخوای دیباگ کنی. حداقل من خودم واقعا به سکوت نیاز دارم تا بتونم تمرکز کنم .?با این حال گاهی در بعضی مکانها ممکنه کسی باشه که این سکوت رو بهم بزنه و اصلا هم تذکر شما واسش اهمیت نداشته باشه! اینجاست که من هندزفری میذارم و میرم سراغ سلاحی به نام نویز سفید!?این نویز سفید در فیزیک معانی دقیق و درست حسابی داره اما یه سایتی که در آخر لینکشو میذارم یک تعریف خیلی خوب و ساده ازش گفته به این صورت:?&quot;فرض کنید که در نقطه‌ای از ایران، در یک بازار محلی شلوغ و پر هیاهو مشغول قدم زدن هستید. در این صورت احتمالا سرو صداهای نافهومی از حرف زدن ده‌ها و شاید صدها انسان مختلف با یکدیگر به گوش شما می‌رسد. همهمه‌ای که صدای جا به جایی اجسام مختلف یا حرکت اتومبیل‌ها و بوق زدنشان نیز آن را همراهی می‌کند.سر و صدایی که از گوشه و کنار بازار به گوش شما می‌رسد در حالت عادی برایتان تفکیک پذیر نیست و همهمه‌ای نافهوم را در ذهن شما ایجاد می‌کند. این همهمه‌ی نافهوم می‌تواند یک مثال ساده برای آشنایی افراد نا آشنا با ماهیت نویز سفید یا وات نویز یا سر و صدای سفید باشد.  حال فرض کنید که شما به عنوان یک مسافر در هتلی مجاور با همان بازار شلوغ و پر سر و صدا اقامت گزیده‌اید. اگر در اتاق کناری شما دو نفر مشغول صحبت با یکدیگر باشند و شما هم نسبت به سر و صدا حساس باشید، این موضوع قطعا می‌تواند در کیفیت خواب و استراحت شما تاثیرگذار باشد. در این شرایط مغز شما صدای آن دو نفر را از هم تفکیک کرده و روی یکی از آنها متمرکز خواهد شد. اما اگر پنجره‌ را باز کنید تا هیاهوی بازار به درون اتاق هجوم بیاورد، دیگر هیچ کدام از صداها از یکدیگر قابل تفکیک نیستند.به همین دلیل تنها پس از گذشت چند لحظه، حالت آزار دهنده بودن صدای افرادی که در اتاق مجاور شما مشغول صحبت با یکدیگر هستند از بین می‌رود یا به اصطلاح در پس صدای هیاهوی بازار گم می‌شود. در واقع این یکی از مواردی است که می‌توان توسط آن از ویژگی‌های منحصر به فرد نویز سفید بهره برد&quot;?حتی میگن بعضی اوقات نویز سفید باعث بهبود در یادگیری میشه و از سکوت هم بهتره.در آخر چندتا سایت نویز سفید که توی بوکمارکم هستن و ازشون استفاده میکنم رو اینجا میذارم که صداهای مختلف بارون ،پرنده ، خیابون ، کافه ، همهمه ی مردم،جاده و ماشین و... رو دارن !?:?https://www.noisli.com/?https://musicforprogramming.net/?https://mynoise.net/?https://noises.online/?https://www.rainymood.com/اطلاعات بیشتر در مورد نویز سفید:yon.ir/whitenoise</description>
                <category>ImAndroid</category>
                <author>ایمان صدریان</author>
                <pubDate>Mon, 24 Jun 2019 17:59:33 +0430</pubDate>
            </item>
                    <item>
                <title>? همه چیز در مورد نوتیفیکیشن در اندروید ۸ یا Oreo!</title>
                <link>https://virgool.io/ImAndroid/notificationandroidoreo-mmtjkqq3z7q5</link>
                <description>?اینکه پیاده سازی نوتیفیکیشن در اندروید ۸ تغییر کرده و اینکه از این به بعد باید از notification Channle استفاده کنیم رو احتمالا میدونیم اما خود نوتیفیکیشن چنل چیست؟?چندباری دیدم بعضی از برنامه نویسها نحوه ی پیاده سازیش رو اوکی کردن اما دقیقا نمیدونن چیه. ?البته خودم هم بار اولی که یک اپ سازمانی دست مدیر سازمان که گوشیش اندروید ۸ بود به خاطر همین قضیه فورس کلوز داد فقط سریعا مشکل رو برطرف کردم بدون اینکه دقیقا بدونم چیه داستان ! :))?دیدم که بلاگ پوشه(blog.pushe.co) خیلی خوب یه توضیح اجمالی نوشته که اینجا همون رو میارم:?“ در اندروید ۸ به بعد قابلیت جدیدی برای تعریف کانال نوتیفیکیشن در اپلیکیشن ایجاد شده، به این شکل که می‌تونید در برنامه خودتون یک یا چند کانال نوتیفیکیشن تعریف کنید و در زمان ارسال اعلان پیشرفته با وارد کردن Channel-Id آن کانال، اعلان را برای آن کانال خاصی ارسال کنید و کاربرانی که به انتخاب خودشون آن کانال‌ها را فعال گذاشته‌اند آن را دریافت می‌کنند.مزیت مهم آن این هست که دیگر نیاز نیست کاربر دریافت نوتیفیکیشن برنامه‌ای را بخاطر علاقه نداشتن به دریافت اعلان خاصی غیرفعال کند، درعوض فقط بعضی کانال‌ها را غیرفعال می‌کند و همچنان از یک یا چند کانال دیگر اعلان می‌گیرد.این امکان برای شناسایی سلایق کاربر نیز برای توسعه دهندگان بسیار مفید است.کاربرد آن برای کاربر به این صورت هست که با کلیک به مدت چند ثانیه بر روی پوش نوتیفیکیشن،اعلانی باز می شود و در آن امکان غیرفعال کردن کانال اعلان رسیده وجود دارد، همچنین با کلیک بر دکمه all categories وارد تنظیمات دسته بندی کانال‌ها شده و آن ها را بر اساس نیاز و علایق خود فعال و یا غیر فعال می‌کند.”کانال ها ی یک اپلیکیشن در اندروید ۸  که پس از نگاه داشتن دست بر روی یک نوتیفیکیشن نمایش داده می شوند در اندروید ۸ یک چیز باحال دیگه هم اضافه شده به badge که و وقتی یک اپلیکیشن نوتیفیکیشنی داشته باشه که شما هنوز نخوندینش یک نقطه میاد روی آیکنش و با زدن روی اون، نوتیفیکیشن ها را بالاش نشون میده مثل عکس زیر:badge in android 8 ? بریم سراغ  نحوه ی تعریف یک نوتیفیکیشن به همراه channel :قبل از هرچیز notificationManagerCompat و notificationManager رو به صورت سراسری تعریف کنید و در onCreate به صورت زیر مقدار دهی کنید: notificationManagerCompat = NotificationManagerCompat.from(this);
if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.O) {
notificationManager=getSystemService(NotificationManager.class);
} ?حالا میخواهیم  یک متد بنویسیم که کارش تعریف channel هست فقط دقت کنید که از اندروید ۸ به بعد برای اولویت بندی نوتیفیکیشن ها دیگه از setpriority استفاده نمیکنیم و اینجا موقع ساختن channel باید بهشون importance بدیم :         private void createNotificationChannel1 () {   
               if ( Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.O ) {    
                CharSequence name = &quot;Name of Channel 1&quot;;                     
                String description = &quot;desc about Channel 1&quot;;    
                int importance = NotificationManager.IMPORTANCE_DEFAULT; 
                NotificationChannel channel = new NotificationChannel(CHANNEL_ID1, name, importance);                    
               channel.setDescription(description); 
               notificationManager.createNotificationChannel(channel);  
                }         
     }و بعد موقع تعریف یک نوتیفیکیشن کافیه به این صورت عمل کنیم:createNotificationChannel1();
Notification newMessageNotification = new NotificationCompat.Builder(MainActivity.this, CHANNEL_ID1 )
        .setSmallIcon(R.drawable.ic_launcher_foreground)
        .setContentTitle(&quot;Title3&quot;)
        .setContentText(&quot;Content Text3&quot;)
        .build();
notificationManagerCompat.notify(NOTIFICATION_ID, newMessageNotification);دیگه اینطوری با توجه به شرطی که گذاشتیم برای چک کردن ورژن اندروید ، همیشه میتونیم از این روش استفاده کنیم تا اگه اندروید ۸ به بالاس نوتیفیکیشن با channel ساخته بشه!? اما نکته ی دیگه ای که شاید یکم گیج کننده باشه راجع به group ها در نوتیفیکیشن هست و باید بدونیم که کلا دو مدل group داریم:۱)گروه channel های notification که با کلاس NotificationChannelGroup  معرفی می شوند. شما میتونید یک NotificationChannleGroup بسازید! اینطوری وقتی کاربر وارد دستشو روی نوتیفیکیشن نگه میداره تا channle ها رو ببینه اونها رو دسته بندی شده توی گروه های مختلف میبینه!:مثلا در زیر گروه Timeline برای یک دسته از کانال ها تعریف شده است و سایر نوتیفیکیشن هایی که گروه ندارن توی دسته ی other قرار می گیرند:channel groupsگروه Business و personal ساخته شده اند و آنهایی که گروه ندارند در other نمایش داده شده اندبرای ساخت یک همچین گروهی کافیه همونجایی که بالا چک میکردیم که اندروید بالای ۸ هست، یه channelgroup بسازیم که بعد موقع ساختن channel بیاییم و به این گروه setgroup ش کنیم :   if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.O) {
            notificationManager = getSystemService(NotificationManager.class);
            notificationChannelGroup1 = new NotificationChannelGroup(CHANNEL_GROUP_ID1 , CHANNEL_GROUP_NAME1);
        }و بعد کافیه به متدی که بالا نوشتیم برای ساخت channel d یک setgroup اضافه کنیم و id گروه رو بهش بدیم:    private void createNotificationChannel1 () {  
               if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.O) {     
                CharSequence name = &quot;Channel 1&quot;;         
                String description = &quot;Channel 1&quot;;             
                int importance = NotificationManager.IMPORTANCE_DEFAULT;     
                NotificationChannel channel = new NotificationChannel(CHANNEL_ID1, name, importance);                 
                channel.setDescription(description);      
                channel.setGroup(CHANNEL_GROUP_ID1);            
                notificationManager.createNotificationChannel(channel);         
        }         
    }۲) نوع گروه دیگری که در نوتیفیکیشن ها داریم مربوط میشه به نشان دادن چند نوتیفیکیشن در یک منوی باز شونده مثل چیزی که در واتس اپ و تلگرام میبینیم:راجع به این نوع نوتیفیکیشن ها میتونید با کلید واژه هایی مثل group Notification , cluster Notification ,  bundle Notification و یا Expandable Notification جستجو کنید:bundle notifications? قبل از هرچیز باید بدونیم که این گروه هیچ ربطی به NotificationChannleGroup نداره . از اندروید ۷ به بعد، به صورت پیش فرض وقتی بیش از ۴ نوتیفیکیشن از یک اپلیکیشن ظاهر میشه، به صورت خودکار در یک گروه قرار داده می شوند.وقتی ما یک سری نوتیفیکیشن خاص را می خواهیم در یک گروه قرار بدیم باید هنگام ساختنشون با متد setgroup به همه شون یک groupID یکسان بدیم.در خود داکیومنت گوگل راجع به نحوه ی ساخت این گروه ها توضیحی داده شده است که آنطور که گفته شده عمل نمی کند! این موضوع رو بعد از اینکه خودم تست کردم به دوستم هم گفتم و اون هم همین نتیجه رو گرفت و در نهایت دیدیم که برنامه نویس Trello هم توی بلاگش به این موضوع اشاره کرده.خلاصه اینکه در نهایت روشی که کارامد بود به این صورت است:ببینید شما اینطوری به قضیه نگاه کنید که گروه خودش یک نوتیفیکیشن هست که یک متد اضافه تر دارد به نام  :.setGroupSummary(true)
.setGroup(GROUP_ID_1) و دقت کنید که setgroup رو باید به همه ی نوتیفیکیشن هایی که میخواهید عضو این گروه باشند بدید و به همه شون هم یک groupID یکسان بدید. پس ما میاییم و builder یک نوتیفیکیشن رو مخصوص یک گروه به صورت زیر  تعریف میکنیم :Notification groupBuilder1 =     
    new NotificationCompat.Builder(this , CHANNEL_ID1)     
            .setSmallIcon(R.drawable.ic_launcher_foreground)       
           .setContentTitle(&quot;My App Group1&quot;)                 
           .setContentText(&quot;Group Title1&quot;)             
           .setGroupSummary(true)            
          .setGroup(GROUP_ID_1)            
          .setStyle(new NotificationCompat.BigTextStyle().bigText(&quot;Big Text1&quot;)).build();همانطور که میدونید نوتیفیکیشن ها زمانی ساخته می شوند که متد notify از Notification manager صدا زده شود و همانطور که میبینید اینجا ما فقط builder یک نوتیفیکیشن رو تعریف کردیم ، اما پس کی باید بسازیمش؟هر وقت که میخواهید نوتیفیکیشن بسازید این رو قبلش notify  کنید تا مرتب ساخته بشه! خب اینطوری باعث نمیشه کلی نوتیفیکیشن ساخته بشه؟ نه! و اتفاقا نیازه! چون با هر بار ساختن نوتیفیکیشن مربوط به گروه اون رو آپدیت میکنید! و دوباره روی خودش ساخته میشه و توی دلش نوتیفیکیشن های مربوط به گروه خودشو نشون میده!فقط باید به چند نکته که البته بدیهی هم هستند دقت کنید:۱- همیشه id گروهی که ساختید و id ای که به setgroup نوتیفیکیشن میدید یکسان باشند.۲-گروه و نوتیفیکیشن در یک channel باید باشند ، پس channeID هر دو باید یکسان باشد.حالا فرض کنید میخوایم یک نوتیفیکیشن بسازیم که توی گروه بالا باشه:createNotificationChannel1();  Notification newMessageNotification = new NotificationCompat.Builder(MainActivity.this, CHANNEL_ID1)       
 .setSmallIcon(R.drawable.ic_launcher_foreground)         
.setContentTitle(&quot;Title4&quot;)         
.setContentText(&quot;Content Text4&quot;)         
.setGroup(GROUP_ID_1)         
 .build(); 
 notificationManagerCompat.notify(GroupID1, groupBuilder1);    notificationManagerCompat.notify(notificationID1, newMessageNotification); 
در نهایت از دوستم حیدر صاکی که  ازش خواستم که این حالات رو تست کنه تا سریعتر به نتیجه برسیم تشکر میکنم.</description>
                <category>ImAndroid</category>
                <author>ایمان صدریان</author>
                <pubDate>Mon, 19 Nov 2018 14:08:06 +0330</pubDate>
            </item>
            </channel>
</rss>