টুল ও পারফর্ম্যান্স

Compose-এ নিজেকে আরও উন্নত করুন

স্পিকার

সম্পর্কে

টক সম্পর্কে

Jetpack Compose-এর সাহায্যে খুব ভাল কোয়ালিটির ইউজার ইন্টারফেস ডিজাইন করা সহজ হলেও, UI-এর পারফর্ম্যান্সকে প্রভাবিত করে এমন সমস্যা ট্র্যাক করা কঠিন হতে পারে। এই ধরনের সমস্যার কারণে আপনার ব্যবহারকারীরা কিছু সমস্যা লক্ষ্য করতে পারেন, যেমন স্টার্টআপ লেটেন্সি এবং ড্রপ করা ফ্রেম যা স্ক্রল জ্যাঙ্ক বা চপি অ্যানিমেশন হিসেবে দেখা যায়।

এই আলোচনায়, আমরা এমন টুল নিয়ে কথা বলব যা আপনার UI-এর পারফর্ম্যান্সকে কী প্রভাবিত করছে তা খুঁজে বের করতে সাহায্য করবে, বিশেষ করে Perfetto এবং (রি-)কম্পোজিশন ট্রেসিংয়ের উপর ফোকাস করে। তারপর আমরা নির্দিষ্ট অ্যান্টি-প্যাটার্নগুলি এক্সপ্লোর করব যা আপনি ব্যবহার করছেন এবং যার জন্য আপনাকে গোপনে খরচ করতে হচ্ছে, কীভাবে আপনি সেগুলি আপনার কোডে খুঁজে পেতে পারেন এবং কোন পজিটিভ প্যাটার্ন দিয়ে আপনি সেগুলি প্রতিস্থাপন করতে পারেন। এই আলোচনার শেষে, আপনি বুঝতে পারবেন কীভাবে পারফর্ম্যান্সের কথা মাথায় রেখে Compose-এ চিন্তা করতে হয় এবং কীভাবে আপনার অ্যাপে পারফর্ম্যান্স অপ্টিমাইজেশন প্রোফাইল, বিশ্লেষণ এবং যাচাই করতে হয়।

সারাংশ

  • Perfetto ট্রেস অন-ডিভাইস অ্যাক্টিভিটি রেকর্ড করে এবং কম্পোজিশন ও লেআউটের মতো Compose স্লাইস মূল থ্রেডের সাথে দেখায়। ফ্রেম টাইমলাইন পরীক্ষা করতে এবং ফেজের সময়সীমা ট্র্যাক করতে এগুলি ব্যবহার করুন।
  • কম্পোজেবলের মধ্যে প্রতিটি অপারেশনের জন্য খরচ হয়, যার মধ্যে কোরুটিন চালু ও বাতিল করাও অন্তর্ভুক্ত। সাইড এফেক্ট API অডিট করুন এবং কম্পোজিশন ওভারহেড কমাতে একই কী সহ এফেক্ট মার্জ করার কথা বিবেচনা করুন।
  • কম্পোজিশন ট্রেসিং কম্পোজেবল ফাংশন অ্যানোটেট করে এবং রিকম্পোজিশন ট্রেসিং (১.১৩+) স্টেট রিড ও রাইট ট্র্যাক করে যার ফলে রিকম্পোজিশন হয়। এগুলি Perfetto ট্রেসের মধ্যে সরাসরি অপ্রত্যাশিত কাজ ডায়াগনসিস করতে সাহায্য করে।
  • ComputedState (Compose 1.13+) অবাঞ্ছিত ইনভ্যালিডেশন এড়ায় এবং সাধারণত রিড-আফটার-রাইট ইনভ্যালিডেশনের সময় DerivedState-এর চেয়ে দ্রুত কাজ করে। DerivedState তখনই উপযোগী থাকে যখন ক্যাশিং থেকে ব্যয়বহুল গণনা বা বরাদ্দ উপকৃত হয়।
  • কম্পোজেবল এড়িয়ে গেলে রক্ষণাবেক্ষণের খরচ ও প্যারামিটার তুলনা করার ওভারহেড বহন করতে হয়। স্টেবিলিটি জোর করে প্রয়োগ করার পরিবর্তে, স্ট্রং স্কিপিং এবং অবজেক্ট আইডেন্টিটি ইকুয়ালিটির উপর নির্ভর করুন অথবা সম্পূর্ণভাবে ইনভ্যালিডেশন এড়িয়ে চলুন।

দক্ষতা

রিসোর্স

Gemini Notebook

বিষয়

  • jetpack-compose
  • android-performance
  • perfetto
  • বেঞ্চমার্কিং
  • coroutines
  • কম্পোজিশন-ট্রেসিং
  • android-cli

ট্রান্সস্ক্রিপ্ট করা

ভূমিকা

  • হ্যালো।

  • হ্যালো, সবাইকে স্বাগত।

  • আশা করি আপনার ছুটি ভালো কেটেছে।

  • আশা করি আপনি কফি খেয়েছেন, ময়েশ্চারাইজ করেছেন এবং আরও অনেক কিছু।

  • আজকে আমরা একটু গভীরে গিয়ে আলোচনা করব।

  • হ্যাঁ, এই যে।

  • আজ একটু গভীরে ডুব দেওয়া যাক।

  • আমার নাম আন্দ্রেই শিকভ এবং আমার সাথে আজ আছেন অ্যান্ড্রু বেইলি।

  • আমরা দুজনেই কম্পোজ কম্পাইলার রানটাইম টিমে কাজ করি, তবে পারফর্ম্যান্স সহ আরও অনেক কিছুতে কাজ করি।

  • এবং, আজকের আলোচনার থিম হল আপনার প্রশ্নের উত্তর দেওয়া, পারফর্ম্যান্স সম্পর্কে প্রশ্ন, কারণ Jetpack Compose Android ডেভেলপমেন্টের জন্য ডিফল্ট UI টুলকিট হিসেবে প্রতিষ্ঠিত হয়েছে।

  • এবং, এখন অনেক লোক জিজ্ঞাসা করছেন যে কীভাবে আমরা নিশ্চিত করতে পারি যে আমাদের Compose UI যতটা সম্ভব পারফর্ম্যান্ট।

  • তাই আজ, আমি আগেই যেমন বলেছি, আমরা গভীর চিন্তন ইন-ডেপথ ডাইভ করছি।

  • এছাড়াও, Compose-এ আপনার পারফর্ম্যান্স আরও উন্নত করতে আমরা কিছু টুল নিয়ে আসতে চলেছি।

  • প্রথমেই আমি বলতে চাই যে পারফর্ম্যান্স আমাদের কাছে কেন গুরুত্বপূর্ণ।

  • আপনি যখন কোয়ালিটি এবং কোয়ালিটি অ্যাপ তৈরির কথা ভাবেন, তখন সাধারণত অ্যানিমেশনের কথা ভাবেন, আমরা রিচ ফিচার সেটের কথা ভাবি এবং কখনও কখনও পারফর্ম্যান্সের কথা ভুলে যাই, কিন্তু ব্যবহারকারীর ধারণা সত্যিই আপনার অ্যাপের পারফর্ম্যান্সের উপর নির্ভর করে।

  • তাই অ্যানিমেশন স্টাটার হলে, পারসেপশন সাথে সাথে কমে যায়।

  • তাই, আজ আমরা যেসব মেট্রিক ও সংখ্যা উল্লেখ করব, সেগুলি আসলে প্রক্সি মেট্রিক যা আমরা বেছে নিয়েছি যাতে বোঝা যায় যে অ্যাপ, অ্যানিমেশন ও স্ক্রিনে যা কিছু ঘটছে সেই সম্পর্কে ব্যবহারকারীর অভিজ্ঞতা কেমন।

  • তাই, মূলত, আপনার অ্যাপ অপ্টিমাইজ করার অর্থ হল আরও ভালো অভিজ্ঞতার জন্য অপ্টিমাইজ করা।

  • তাই, আমি চাই যে আপনি এই মানসিকতা নিয়ে আজকের সেশনটি শুনুন, কারণ আজ আমরা অনেক বিষয়ে গভীরভাবে আলোচনা করব।

  • এখন, আপনি যখন আপনার অ্যাপের পারফর্ম্যান্স দেখতে শুরু করবেন, আমি চাই আপনি তিনটি দ্রুত কাজ করুন, তিনটি দ্রুত দ্রুত কাজ করুন।

  • প্রথমত, আপনি যদি পারফর্ম্যান্স পরিমাপ করেন, তাহলে আপনি এটি রিলিজ মোডে পরিমাপ করেন, তাই আমাদের কাছে প্রচুর ডিবাগ করার মতো তথ্য নেই এবং এই সব কিছুই আমাদের অ্যাপকে ধীর করে দিচ্ছে।

  • দ্বিতীয়ত, আপনি R8 বা অন্যান্য মিনিফায়ার চালু করেন।

  • এই বছরই আমরা একটি অপ্টিমাইজেশন চালু করেছি যা কোরুটিনের পারফর্ম্যান্স দ্বিগুণ করে এবং আমরা আরও অনেক কিছু করি।

  • Compose অপ্টিমাইজ করার সময় আমরা R8-এর উপর অনেক বেশি নির্ভর করি।

  • আর শেষ কথা, বিশেষ করে স্টার্টআপ মেট্রিক্সের জন্য, আপনি বেসলাইন প্রোফাইল ব্যবহার করছেন কিনা তা নিশ্চিত করতে হবে।

  • তাই, স্টার্টআপে আপনি যে ক্লাস লোড করেন, অ্যাপ চালু হওয়ার সময় সেগুলি প্রি-কম্পাইল ও প্রি-লোড করা হয়।

  • সুতরাং, আপনি দেখতে পাচ্ছেন যে, এটি আপনার অ্যাপের সাধারণ ডিবাগেবল বিল্ডের থেকে ৬ গুণ আলাদা।

  • এবং, আপনি যখন সেইসব জিনিস পরিমাপ করবেন, তখন সেগুলি আপনার কোডের মধ্যে করা অন্যান্য জয়ের সাথে একত্রিত হবে।

  • এখন, আপনি এই সব কিছু করেছেন, অ্যাপ এখনও একটু ল্যাগ করছে, বা পারফর্ম্যান্সের সাথে এখনও অন্যান্য সমস্যা আছে, এবং এখানেই আপনি এই পারফর্ম্যান্স লুপে যেতে চান।

  • আপনি নির্দিষ্ট কিছু পরিস্থিতিতে কিছু মেট্রিক দেখতে চান।

  • যেমন, ধরুন আপনার অ্যাপ লোড হতে অনেক সময় নিচ্ছে, তাই আপনি হয়ত অ্যাপ রিসেট করতে চান, সাধারণ লঞ্চারের মতো এটি শুরু করতে চান এবং প্রথম ডেটা স্ক্রিন আসতে কত সময় লাগছে তা চেক করতে চান।

  • অথবা অ্যাপটি হয়ত একটু আটকে আটকে চলছে, তাই আপনি স্ক্রল করে নিশ্চিত করেন যে এই স্ক্রলটি বারবার করা যায় এবং স্টেবল।

  • তাই এই স্লাইডে দেখানো স্থিতিশীল পরিবেশটি খুবই গুরুত্বপূর্ণ, কারণ আপনি পরে অপ্টিমাইজ করার সময়, আপনার মেট্রিক্সে উন্নতি দেখতে পাচ্ছেন কিনা তা নিশ্চিত করতে চাইবেন এবং সেই অপ্টিমাইজেশনগুলি আসলে উদ্দেশ্য অনুযায়ী কাজ করছে কিনা তা কনফার্ম করতে পারবেন।

  • বেঞ্চমার্ক এর জন্য সত্যিই ভালো, কারণ বেঞ্চমার্ক ইতিমধ্যেই অনেক ডেটা ক্যাপচার করে, আপনার ডিভাইসে যাতে খুব বেশি নয়েজ না থাকে তা নিশ্চিত করার জন্য তারা অনেক ইটারেশন করে এবং তারা অনেক ডিভাইস সেটআপও করে যা আপনাকে সাহায্য করে।

  • এছাড়াও, বেঞ্চমার্ক হল ডিফল্ট হিসেবে পুনরাবৃত্তিযোগ্য পরিস্থিতি এবং আমরা এখানে এটিই করার চেষ্টা করছি।

  • তবে, আপনি চাইলে একগুচ্ছ স্ক্রিপ্ট ব্যবহার করেও এটি করতে পারেন।

  • আর শেষ কথা হল, আপনার প্রোফাইল, আপনি অ্যাপে কিছু উন্নত করেন, ডেটা দেখেন এবং তারপরে আবার রিপিট করেন এবং হয়ত আবার রিপিট করেন, যেমন বিভিন্ন সিনারিও মেট্রিক যেখানে আপনার অ্যাপ স্ট্রাগল করে।

Perfetto ট্রেসের সাহায্যে প্রোফাইলিং করা

  • আপনি ডেটা দেখার সময়, প্রথম যে টুলটি আমরা আজ নিয়ে এসেছি এবং আপনি যেটির সাথে পরিচিত হতে চান সেটি হল Perfetto ট্রেস।

  • আপনি যখন ট্রেস রেকর্ড করেন তখন ডিভাইসে যা কিছু ঘটে তা পারফেটো ট্রেস রেকর্ড করে, যেমন, ম্যাক্রোবেঞ্চমার্ক রান করার সময় বা আপনি রেকর্ড করছেন এমন কিছু স্ক্রিপ্ট।

  • Android-এর পারফর্ম্যান্স নিয়ে কাজ করা প্রত্যেক ইঞ্জিনিয়ারের জন্য এটি অত্যন্ত সহায়ক।

  • আমার ক্ষেত্রে, আমি আজকাল আমার দিনের বেশিরভাগ সময় Perfetto ট্রেস দেখে কাটাই।

  • সেগুলি দেখতে এইরকম হয়।

  • এটি অনেক ডেটা।

  • আমি যেমন বলেছি, ডিভাইসে যা কিছু ঘটে তা তারা ক্যাপচার করে।

  • তাই, আপনার অ্যাপটি ঠিক কোথায় আছে তা খুঁজে বের করতে প্রথমে আপনাকে কিছুটা বেগ পেতে হতে পারে, তাই আমি এই সুবিধাজনক সার্চ বারটি ব্যবহার করার সাজেশন দিচ্ছি।

  • Compose, আপনার অ্যাপ প্যাকেজ ও এই ধরনের অন্যান্য জিনিস সার্চ করুন।

  • পরিচিত কোনও বিষয়ে নিজেকে স্থির করুন।

  • এবং আপনি যখন নিজের অ্যাপ প্রসেস খুঁজে পাবেন, তখন আপনি ফ্রেম টাইম লাইন এবং আপনার অ্যাপে অনেক কিছু করতে কত সময় লাগে তা দেখতে পাবেন।

  • আমরা যদি এর মধ্যে একটিকে আলাদা করি, তাহলে আপনি এইরকম কিছু দেখতে পাবেন।

  • প্রথমটি হল প্রধান থ্রেডের কাজ।

  • এখানেই Compose তার বেশিরভাগ কাজ করে।

  • তারপর RenderThread আছে।

  • এখানে আমরা ক্যানভাস কমান্ড প্রসেস করি, GPU-তে এনকোড করি।

  • তারপর GPU তার কাজ করে এবং তারপর সিস্টেম সেটিকে কম্পোজিট করে।

  • আজ আমরা শুধু মূল থ্রেডটি দেখব।

  • কারণ, Compose এখানেই কাজ করে।

  • আমরা Compose সম্পর্কে কথা বলছি, তাই শুধুমাত্র সেটির উপর ফোকাস করা যুক্তিযুক্ত।

  • এবং আমরা প্রধান থ্রেডে সেই একটি ফ্রেমকে আলাদা করার সাথে সাথে, আমরা আসলে এখন কম্পোজ স্লাইস দেখতে শুরু করি।

  • আমি আপনার জন্য এর মধ্যে থেকে কয়েকটি বেছে নিয়েছি।

  • এটি কম্পোজিশন, পরিমাপ, লেআউট, ড্রয়ের মতো।

  • আপনি যদি Compose ফেজ সম্পর্কে শুনে থাকেন, আপনি আগে পারফর্ম্যান্স দেখে থাকেন, তাহলে আপনি সম্ভবত সেগুলি দেখতে পাবেন।

  • তাই Perfetto ট্রেসে এগুলির আলাদা স্লাইস থাকে এবং প্রতিটি ফেজে কত সময় লাগে এবং প্রতিটি নির্দিষ্ট ফ্রেমে কোন ফেজ রান করে তা খুঁজে বের করা খুব সহজ।

  • তাই, আমরা এই কাজের কিছু অংশ অপ্টিমাইজ করার ব্যাপারে অনেক এবং বিস্তারিত আলোচনা করেছি এবং আপনি নিশ্চিত করতে চান যে সঠিক পর্যায়ে সঠিক কাজ করছেন।

  • যেমন, আপনার কাছে যদি এমন অ্যানিমেশন থাকে যা আপনার বক্সের রঙ বা এই ধরনের কিছু আপডেট করে, তাহলে আপনি শুধুমাত্র ড্র ফেজ বাতিল করতে চান, কম্পোজিশন এবং লেআউট বা এই ধরনের কিছু নয়।

  • এটি হল পারফর্ম্যান্স ১০১ এবং আজ আমরা একটু গভীরে গিয়ে কথা বলছি বা কিছু বিষয়ে একটু গভীরে গিয়ে আলোচনা করছি এবং আমরা বিশেষ করে কম্পোজিশনের উপর ফোকাস করছি।

  • এবার অ্যান্ড্রু আমাদের এই বিষয়ে বিস্তারিত জানাবেন।

  • ধন্যবাদ, আন্দ্রেই।

  • আন্দ্রে যেমন উল্লেখ করেছেন, আমরা আগে পারফর্ম্যান্সের প্রসঙ্গে অপ্টিমাইজেশন সম্পর্কে কথা বলতে অনেক সময় ব্যয় করেছি, যেমন ব্যাকওয়ার্ড রিড এড়ানো, কম্পোজিশন লাইফ সাইকেলের সঠিক ফেজে স্টেট রিড ডিফার করা এবং অপ্টিমাইজ করা এবং আপনার কম্পোজেবলগুলি আপনার প্রত্যাশা অনুযায়ী ইনভ্যালিডেট হচ্ছে কিনা তা নিশ্চিত করা, যাতে আপনি প্রতিটি ফ্রেমে খুব বেশি কাজ না করেন।

  • এটি শুরু করার জন্য সত্যিই একটি ভাল পয়েন্ট, তবে আমাদের কাছে ইতিমধ্যেই এই বিষয়ে অনেক মেটেরিয়াল রয়েছে এবং আমরা এই কথোপকথনটিকে একটু এগিয়ে নিয়ে যেতে চাই।

  • তাই, আজ আমরা সেইসব অপ্টিমাইজেশন করার পরে কম্পোজিশনে যা বাকি আছে তা নিয়ে কাজ করব এবং আপনার কম্পোজেবলগুলি নিজেরাই কী করছে তা নিয়ে কাজ করব।

  • আপনার কম্পোজ কোডের মধ্যে থাকা সবকিছুর দুর্ভাগ্যজনক বাস্তবতা এবং পারফর্ম্যান্সের ক্ষেত্রে আপনার অ্যাপের সাথে আপনি যা কিছু পাঠান, তার সাথে একটি খরচ যুক্ত থাকে।

  • আপনার অ্যাপে যে কোড শিপ করেন তার কোনওটিই ফ্রি নয় এবং এমনকি রিডিং স্টেট ও কম্পোজিশনের মধ্যে সাইড এফেক্টের মতো জিনিস কম্পোজ করার মতো তুচ্ছ জিনিসের সাথেও কিছু বাস্তব খরচ যুক্ত থাকে এবং সেগুলি সম্পর্কে সচেতন থাকা গুরুত্বপূর্ণ, বিশেষ করে যখন আপনি কম্পোজেবলগুলি আসলে কী করছে তা বিশ্লেষণ করতে শুরু করেন এবং আপনার অ্যাপের মধ্যেই আরও পারফর্ম্যান্স বের করতে শুরু করেন।

  • সবচেয়ে মাইক্রোস্কোপিক স্কেলে এটি আসলে কেমন দেখায় তা দেখানোর জন্য, এখানে কিছু সবচেয়ে ছোট অপারেশন দেখানো হল যা আপনি আপনার কোডের যেকোনও জায়গায় করতে পারবেন, বিশেষ করে আপনার কম্পোজেবলের মধ্যে এবং এই রেজোলিউশনে, আমরা ন্যানোসেকেন্ড স্কেল সম্পর্কে কথা বলছি, এই জিনিসগুলির জন্য মোটামুটি কত খরচ হয় সেই মানসিকতার পরিপ্রেক্ষিতে।

  • আপনার পারফর্ম্যান্সের উপর প্রভাব ফেলতে চাইলে, আপনার কাছে দুটি বিকল্প আছে।

  • আপনি হয় অনেক বেশি সংখ্যক সস্তা অপারেশন অথবা কম সংখ্যক বেশি দামি অপারেশন সরাতে পারেন।

  • বিশেষ করে এই চার্টে, এই অপারেশনগুলির ক্ষেত্রে কোরুটিনগুলি m-- আরও বেশি ব্যয়বহুল দিকে রয়েছে এবং এটি কোথায় দেখা শুরু করতে হবে তার একটি ভাল উদাহরণ তৈরি করে, কারণ আমরা যদি এই উদাহরণগুলির কয়েকটি সরিয়ে ফেলি, তাহলে আমরা আমাদের অ্যাপ্লিকেশনে আরও বাস্তব সুবিধা দ্রুত দেখতে শুরু করতে পারি।

  • কোরুটিনের ব্যাপারে আরেকটি জিনিস মনে রাখতে হবে, স্লাইডে যেমন দেখানো হয়েছে, কোরুটিন লঞ্চ করার জন্য যেমন খরচ হয়, তেমনই কোরুটিন বাতিল করার জন্যও খরচ হয়।

  • বাতিল করার খরচ বিশেষভাবে উল্লেখযোগ্য কারণ এটি মূলত তখনই ঘটে যখন আপনি কন্টেন্ট সরিয়ে দিচ্ছেন এবং সম্ভবত আপনার অ্যাপ্লিকেশনের মধ্যে অন্যান্য জায়গায় চলে যাচ্ছেন।

  • অনেক অ্যাপ্লিকেশনের ক্ষেত্রে নেভিগেট করে বেরিয়ে আসা অত্যন্ত ব্যয়বহুল, যেখানে আপনাকে ফ্রেম টাইম থেকে সর্বাধিক সুবিধা পেতে হবে এবং আপনার কাছে যা আছে তার বেশিরভাগই ব্যবহার করছেন কিনা তা নিশ্চিত করতে হবে।

  • তাই এই দুটি খরচের ব্যাপারে সচেতন থাকা জরুরি।

  • এইসব, আমরা যাই দেখি না কেন, কাজ করার জন্য প্রায় ১৬ মিলিয়ন ন্যানোসেকেন্ডের এই স্কেলে যোগ করা হবে।

  • তাই আমাদের এখানে কিছু বাজেট আছে যা আমাদের কমাতে হবে এবং কোরুটিন শুরু করার জন্য একটি ভাল উদাহরণ হতে চলেছে।

পার্শ্ব প্রতিক্রিয়া ম্যানেজ করা

  • Compose-এ, এফেক্ট API-এর সাথে কো-রুটিন সবচেয়ে বেশি দেখা যায়।

  • এখানে API-এর একটি স্পেকট্রাম রয়েছে যা আপনি SideEffects-এর সাথে হাই ফাংশনালিটি থেকে লো লেটেন্সি পর্যন্ত ব্যবহার করতে পারবেন।

  • এই স্পেকট্রামের সবচেয়ে ফাংশনাল সাইডে, আমাদের কাছে LaunchedEffect আছে, যার মধ্যে অ্যাসিঙ্ক্রোনাস কাজের জন্য সবকিছু অন্তর্ভুক্ত আছে, বিশেষ করে অ্যানিমেশনের মতো, যার জন্য আপনার একটি কোরুটিন স্কোপ প্রয়োজন।

  • তবে, আপনার যদি সেটির প্রয়োজন না হয় এবং আপনি কম খরচের API ব্যবহার করে আপনার কাজ সম্পন্ন করতে পারেন, তাহলে আপনার ব্যবহারের ক্ষেত্রে সেটি উপযুক্ত হলে, এর পরিবর্তে সেটি ব্যবহার করার কথা বিবেচনা করা যেতে পারে।

  • বাস্তবে এটি কেমন দেখায় তা দেখানোর জন্য, এখানে, আমি একটি কম্পোজেবল মিডিয়া প্লেয়ার পেয়েছি যা সমস্ত বিভিন্ন SideEffects এবং কখন সেগুলি প্রদর্শিত হতে পারে তা দেখায়।

    @Composable
    fun MediaPlayer(contentSource: Uri, playbackRate: Float) {
        val mediaPlayer = rememberMediaPlayer()
    
        // Asynchronous work and animations
        LaunchedEffect(contentSource) { mediaPlayer.load(contentSource) }
    }
  • আমরা LaunchedEffect দিয়ে শুরু করতে পারি।

  • এই উদাহরণে, মিডিয়া প্লেয়ারের মধ্যে অ্যাসিঙ্ক্রোনাসভাবে ডেটা লোড করার জন্য এটি ব্যবহার করা হচ্ছে।

  • আপনার যদি কোনও কো-রুটিন স্কোপের প্রয়োজন হয়, বা সাধারণভাবে কো-রুটিনের প্রয়োজন হয় বা সাসপেন্ডিং কল করতে হয়, তাহলে LaunchedEffect ব্যবহার করুন।

  • যদিও এটি এখনও আরও ব্যয়বহুল এবং কোরুটিনের সাথে একটি খরচ যুক্ত রয়েছে, যতক্ষণ না আপনি এটির সুবিধা নিচ্ছেন এবং এটিকে যুক্তিযুক্ত করছেন, কাজের জন্য সঠিক API ব্যবহার করুন।

  • তবে, আপনি যদি এমন পরিস্থিতিতে পড়েন যেখানে আপনি LaunchedEffect ব্যবহার করছেন, কিন্তু কোরুটিন ব্যবহার করছেন না, তাহলে এটি এমন অন্যান্য API বিবেচনা করার জন্য একটি ভাল জায়গা হতে পারে যা একই কাজ করতে পারে, তবে কম খরচে।

  • সেই জন্য, স্পেকট্রামের নিচের দিকে গেলে, আমরা DisposableEffect-এর মতো পার্শ্বপ্রতিক্রিয়ার অন্যান্য উদাহরণ দেখতে পাই।

    @Composable
    fun MediaPlayer(contentSource: Uri, playbackRate: Float) {
        val activity = LocalActivity.current
    
        // Setup and teardown
        DisposableEffect(Unit) {
            activity.requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE
            onDispose {
                activity.requestedOrientation = SCREEN_ORIENTATION_UNSPECIFIED
            }
        }
    }
  • আপনার এফেক্টের সাথে সেট-আপ ও টিয়ারডাউন প্রসেস যুক্ত থাকলে DisposableEffect ব্যবহার করা ভাল।

  • এখানে, একই মিডিয়া প্লেয়ারের উদাহরণে, আমার কাছে একটি উদাহরণ রয়েছে যা কম্পোজেবল উপস্থিত থাকলে অ্যাক্টিভিটির ওরিয়েন্টেশনকে ল্যান্ডস্কেপে লক করে এবং তারপরে কিছু সময় পরে এটি চলে গেলে সেই ওরিয়েন্টেশন লকটি রিলিজ করে।

  • আপনি যদি LaunchedEffect এবং DisposableEffect-এর এককালীন এফেক্ট চান, কিন্তু আপনার কো-রুটিনের প্রয়োজন না থাকে এবং আপনার কাছে ডিসপোজ এফেক্ট না থাকে, তাহলে আপনি Compose 1.12-এ আমাদের চালু করা'কী' API সহ নতুন SideEffect-ও ব্যবহার করতে পারেন।

    @Composable
    fun MediaPlayer(contentSource: Uri, playbackRate: Float) {
        val mediaPlayer = rememberMediaPlayer()
    
        // One-shot events
        SideEffect(Unit) { mediaPlayer.play() }
    }
  • আপনি যদি অন্য দুটি API-এর জন্য পৌঁছে থাকেন, তাহলে এটি একটি দুর্দান্ত বিকল্প, হয় LaunchedEffect সুবিধার বাইরে, অথবা DisposableEffect ওয়ান-শট ইফেক্টের প্রয়োজনের বাইরে, SideEffect with keys API-তে নেভিগেট বা মাইগ্রেট করা কম ওভারহেড এবং উন্নত পারফর্ম্যান্সের সাথে একই জিনিস সম্পন্ন করতে পারে, বিশেষ করে যদি একটি সম্পূর্ণ অ্যাপের স্প্যান জুড়ে একাধিকবার মাইগ্রেট করা হয়।

  • এবং সবশেষে, সবচেয়ে কম খরচের API হল ভ্যানিলা SideEffect API।

    @Composable
    fun MediaPlayer(contentSource: Uri, playbackRate: Float) {
        val mediaPlayer = rememberMediaPlayer()
    
        // Synchronize the outside world to the state of composition
        SideEffect { mediaPlayer.playbackRate = playbackRate }
    }
  • কম্পোজিশনে যা চলছে তার সাথে বাইরের জগতের স্টেট সিঙ্ক করতে চাইলে এটি সবচেয়ে উপযুক্ত।

  • তাই এখানে, আবার মিডিয়া প্লেয়ারের উদাহরণে, আমার কাছে আরেকটি উদাহরণ আছে যা কম্পোজিশনের মাধ্যমে পাওয়া কিছু প্যারামিটারের সাথে কিছু প্লেব্যাক স্টেট সিঙ্ক করা দেখায়।

  • একটি বিষয় মনে রাখবেন, আপনি যদি সাইড এফেক্ট ব্যবহার অডিট করার এবং কম খরচের কোনও একটিতে মাইগ্রেট করার সিদ্ধান্ত নেন, তাহলে মনে রাখবেন যে আমরা যে অন্যান্য আচরণ এবং ব্যবহারের কেস সম্পর্কে কথা বলেছি, তার পাশাপাশি সাইড এফেক্ট সহ অর্ডারিং গ্যারান্টির ক্ষেত্রেও পার্থক্য রয়েছে।

  • সব ডিসপোজেবল এফেক্ট প্রথমে এক্সিকিউট হয়, তারপরে রেগুলার সাইড এফেক্ট, কীড বা কীড নয়, এবং তারপরে ফ্রেম সম্পূর্ণ হওয়ার পরে সব লঞ্চ করা এফেক্ট রান করে কারণ সেখানে ডিসপ্যাচ জড়িত থাকে।

  • আপনার লঞ্চ করা এফেক্টের জন্য এই টাইমিংয়ের উপর নির্ভর করলে, মাইগ্রেট করার কথা বিবেচনা করার সময় এটি মনে রাখবেন।

  • এছাড়াও, যেকোনও মাইগ্রেশনের জন্য, আপনার কোড পরীক্ষা করে দেখে নিন এবং নিশ্চিত করুন যে আপনি এই টাইমিং গ্যারান্টির উপর নির্ভর করছেন না এবং আপনার কোড এর পরেও কাজ করছে।

  • আপনি যদি পার্শ্ব প্রতিক্রিয়ার জটিলতা কমাতে না পারেন, তাহলে আপনি একাধিক পার্শ্ব প্রতিক্রিয়াকে একসাথে মার্জ করে সেগুলির সংখ্যা কমাতে পারেন।

    @Composable
    fun ShoppingCartScreen(
        viewModel: CartViewModel
    ) {
        LaunchedEffect(Unit) { viewModel.loadCart() }
        LaunchedEffect(Unit) { viewModel.loadPaymentMethods() }
        LaunchedEffect(Unit) { viewModel.loadDeliveryAddresses() }
    
        CartContent(...)
    }
  • আপনার কাছে একই 'কী' ব্যবহার করে এমন একাধিক এফেক্ট থাকলে, এটি বিবেচনা করা বিশেষভাবে ভালো।

  • একই সময়ে এক্সিকিউট করা যায় বলে এগুলি একসাথে মার্জ করার কথা বিবেচনা করা যেতে পারে।

  • এখানে, এই উদাহরণে, আমি বেশ কয়েকটি লঞ্চ করা এফেক্ট পেয়েছি যার প্রতিটি কিছু ভিউ মডেলে একটি অ্যাসিঙ্ক্রোনাস কল করছে।

  • আমি যদি সেগুলিকে একটিমাত্র LaunchedEffect দিয়ে রিপ্লেস করি এবং তারপরে সেটির মধ্যে অন্যান্য লঞ্চ কল করি, যদিও আমার কাছে এখনও একই সংখ্যক কোরুটিন আছে যা এখানে চলছে, তবুও এটিতে কম ওভারহেড আছে কারণ এটি কম্পোজিশনের পরিবর্তে কোরুটিনে কাজ করে।

    @Composable
    fun ShoppingCartScreen(
        viewModel: CartViewModel
    ) {
        LaunchedEffect(Unit) {
            launch { viewModel.loadCart() }
            launch { viewModel.loadPaymentMethods() }
            launch { viewModel.loadDeliveryAddresses() }
        }
    
        CartContent(...)
    }
  • তাই, এই ধরনের পরিস্থিতিতে, সম্ভব হলে, প্রভাবের সংখ্যা কমাতে, মাইগ্রেট করার কথা বিবেচনা করা ভাল।

  • ইফেক্ট ও কোরুটিন হল আপনার অ্যাপ্লিকেশনের মধ্যে অডিট করতে পারেন এমন একটি জায়গার উদাহরণ মাত্র, তবে প্রতিটি কম্পোজেবল ও প্রতিটি অ্যাপ্লিকেশন আলাদা হবে এবং সেগুলির মধ্যে আলাদা সুযোগ থাকবে।

  • আপনার অ্যাপ্লিকেশনের জন্য কী প্রাসঙ্গিক তা বুঝতে, আমাদের পরবর্তী টুল সম্পর্কে কথা বলতে হবে যা আন্দ্রেই পরিচয় করিয়ে দিতে চলেছে, যা হল কম্পোজিশন ট্রেসিং।

কম্পোজিশন ও রিকম্পোজিশন ট্রেসিং

  • ঠিক আছে।

  • তাই, কম্পোজিশন ট্রেসিং, আপনি যদি Perfetto ফ্রেমের এই বিশ্বস্ত রিক্রিয়েশন দেখেন যা আমরা আগে অন্য স্লাইডে দেখেছি, তাহলে আপনি দেখতে পাবেন যে এটি আমাদের বিভিন্ন ফেজের সাথে টাইমিং সংক্রান্ত তথ্য দেয়, কিন্তু আসলে কী ঘটছে সে সম্পর্কে আমাদের অনেক বিবরণ দেয় না।

  • কি?

  • হ্যাঁ, কম্পোজিশনের মধ্যে কী ঘটছে, যার কম্পোজেবল ফাংশন রান করা হয়।

  • এবং কম্পোজিশন ট্রেসিং আমাদের এই কাজে সাহায্য করে।

  • তাই, আমরা Compose কম্পাইলারে কিছু মার্কার যোগ করেছি যা মূলত প্রতিটি ফাংশন অ্যানোটেট করে এবং Perfetto ট্রেসে তা দেখায়, যাতে আপনি প্রতিটি ফাংশন কতক্ষণ সময় নেয় তা চেক করতে পারেন।

  • কোন ফাংশনটি রিকম্পোজ হচ্ছে তা আপনি এর মাধ্যমে বুঝতে পারবেন।

  • তবে, এর জন্য কিছুটা ওভারহেড আছে, তাই আপনি যদি সবচেয়ে সঠিক পারফর্ম্যান্স ডেটা ক্যাপচার করতে চান, তাহলে আপনাকে নিয়মিত Perfetto ব্যবহার করতে হবে অথবা Perfetto ক্যাপচার ছাড়াই রান করতে হবে এবং অন্যান্য মেট্রিক ব্যবহার করতে হবে।

  • তবে, প্রতিটি কম্পোজেবল কত সময় নেয় তা জানতে চাইলে কম্পোজিশন ট্রেসিং খুবই উপযোগী।

  • এখন, কখনও কখনও আপনিও জানতে চান যে কেন জিনিসগুলি আবার কম্পোজ করা হচ্ছে এবং কম্পোজ ট্রেসিং রানটাইম ট্রেসিংয়ের পরবর্তী রিলিজ, অর্থাৎ, 1.13-এ আমরা এই সমস্যার সমাধান করার চেষ্টা করছি।

  • আমরা এখন রিকম্পোজিশন ট্রেসিং চালু করছি, যা প্রতিটি স্টেট রিড এবং স্টেট রাইটকে অ্যানোটেট করে যার ফলে রিকম্পোজিশন হয়।

  • সুতরাং, আপনি আপনার Perfetto ট্রেসে এইরকম কিছু পাবেন, যেখানে আপনি প্রতিটি স্টেট রাইট এবং কল স্ট্যাক দেখতে পাবেন যেখানে রাইট এবং রিড হয়, যাতে আপনি আপনার কোডের প্রকৃত লাইনের সাথে সেগুলি মেলাতে পারেন যেখানে সেইসব স্টেট অ্যাক্সেস বা পরিবর্তন করা হয়েছে।

  • এখন, আপনি আরও জানতে চাইলে, এখানে দেওয়া লিঙ্কটি দেখুন।

  • এতে কম্পোজিশন ট্রেসিং ও রিকম্পোজিশন ট্রেসিং, দুটিরই সব ডকুমেন্টেশন আছে।

  • এখন, অ্যান্ড্রু বলবেন যে স্টেট রাইট এড়াতে আমরা কীভাবে এটি আরও দক্ষতার সাথে ব্যবহার করতে পারি।

স্টেট অপ্টিমাইজেশন ও ইনভ্যালিডেশন

  • ধন্যবাদ, আন্দ্রেই।

  • এই তদন্ত থেকে আপনি যে ফলাফল পাবেন তার উপর ভিত্তি করে, আপনি হয়ত দেখতে পাবেন যে আপনার কম্পোজিশনে এমন কিছু ইনভ্যালিডেশন আছে যা আপনার অ্যাপ্লিকেশনের জন্য উপযোগী নয় এবং প্রথম থেকেই এড়ানো যেত।

  • এখানে, উদাহরণস্বরূপ, আমি যে সবচেয়ে সাধারণ উদাহরণটি পেয়েছি তা হল কিছু স্ক্রল টু টপ বোতাম যা দৃশ্যমানতা বা এর দৃশ্যমানতার জন্য স্ক্রল প্রগ্রেসের উপর নির্ভর করে।

    @Composable
    fun ScrollToTopButton(
        scrollState: ScrollState
    ) {
        val showScrollToTopButton = scrollState.value > 0
        val coroutineScope = rememberCoroutineScope()
    
        if (showScrollToTopButton) {
            FloatingActionButton(
                onClick = {
                    coroutineScope.launch { scrollState.animateScrollTo(0) }
                }
            ) {
                Icon(Icons.Default.ArrowUpward, "Scroll to Top")
            }
        }
    }
  • এখানে, যেহেতু আমি কম্পোজিশনের মধ্যে স্ক্রলিং স্টেট সংক্রান্ত ভ্যালু পড়ছি, তাই এটি খুব ঘন ঘন পরিবর্তনশীল স্টেট, এটি প্রতিটি ফ্রেমে একবার করে পরিবর্তন হতে পারে এবং এর ফলে অনেক রিকম্পোজিশন হবে যা এড়ানো যেতে পারে কারণ এই কন্ডিশন, যদিও স্ক্রল স্টেট নিজেই পরিবর্তিত হচ্ছে, তবে আমরা এখানে যে প্রকৃত কন্ডিশন নিয়ে চিন্তিত তা প্রায়শই পরিবর্তিত হয় না।

  • এটি এমন একটি উদাহরণ যেখানে আমরা কম্পিউটেড স্টেটের মতো কিছু ব্যবহার করার সাজেশন দেব, যা আপনার অ্যাপ্লিকেশনের জন্য গুরুত্বপূর্ণ নয় এমন স্টেট পরিবর্তনের জন্য ইনভ্যালিডেশন এড়াতে পারে।

  • তাই এই উদাহরণে, আমি এখানে যা করেছি তা হল আমি গণনাটিকে একটি কম্পিউটেড স্টেটের মধ্যে রেখেছি এবং যখন আমরা এই স্টেটটি পড়ি, তখন স্ক্রোল পজিশনের উপর ভিত্তি করে অবৈধ করার পরিবর্তে, এটি সম্পূর্ণ অবস্থার উপর ভিত্তি করে এই কম্পোজেবলটিকে শর্তসাপেক্ষে অবৈধ করবে এবং অন্য স্টেট থেকে এটি গ্রহণ করবে।

    @Composable
    fun ScrollToTopButton(
        scrollState: ScrollState
    ) {
        val showScrollToTopButton by remember { computedStateOf { scrollState.value > 0 } }
        val coroutineScope = rememberCoroutineScope()
    
        if (showScrollToTopButton) {
            FloatingActionButton(
                onClick = {
                    coroutineScope.launch { scrollState.animateScrollTo(0) }
                }
            ) {
                Icon(Icons.Default.ArrowUpward, "Scroll to Top")
            }
        }
    }
  • আপনি যদি এই প্যাটার্নটি আগে দেখে থাকেন, তাহলে সম্ভবত আপনি এটি ডেরাইভড স্টেটের সাথে ব্যবহার করতে দেখেছেন।

  • Compose 1.13-এ ComputedState নতুন এবং ComputedState ও DerivedState, দুটিরই লক্ষ্য হল, তাদের গণনা পরিবর্তিত হলে শর্তসাপেক্ষে বাতিল করা, তবে তারা কীভাবে এটি করে তার মধ্যে খুব সূক্ষ্ম পার্থক্য রয়েছে।

  • DerivedState, যা আমরা Compose-এর শুরু থেকেই ব্যবহার করছি, এটি যে ভ্যালু গণনা করে তা ক্যাশে করে এবং এর ডিপেন্ডেন্সি পরিবর্তন না হওয়া পর্যন্ত এটি আবার ব্যবহার করে।

  • ComputedState-এর মাধ্যমে, আপনি যতবার এটি পড়েন ততবার এটি ভ্যালু গণনা করে।

  • ক্যাশিংকে দরকারী বলে মনে হলেও, আসলে অনেক পরিস্থিতিতে, ক্যাশিং শুধু ফলাফল পড়ার চেয়ে বেশি ব্যয়বহুল।

  • এটি কীভাবে হয় তা বুঝতে, আপনার অ্যাপ্লিকেশনের মধ্যে কীভাবে এইসব স্টেট ব্যবহার করা হতে পারে তার একটি উদাহরণ আমরা দেখতে পারি এবং এর মধ্যে প্রতিটি আসলে কী করছে তা খুঁটিয়ে দেখতে পারি।

  • এখানে, আমি একই স্টেট পেয়েছি যা স্ক্রল টু টপ বোতামে আমরা যা করছিলাম তা মোটামুটিভাবে মিরর করে, যেখানে এটি অন্য কোনও স্টেটের উপর ভিত্তি করে কিছু শর্ত পেয়েছে এবং আমি এটি DerivedState এবং ComputedState উভয় হিসাবেই পেয়েছি।

    var a by mutableStateOf(0)
    
    val derivedState = derivedStateOf { a > 0 }
    val computedState = computedStateOf { a > 0 }
    
    // First read
    derivedState.value
    computedState.value
    
    // Second read
    derivedState.value
    computedState.value
  • আমিও তখন স্টেট দুবার পড়ছি এবং আমরা দুবারই একই ভ্যালু পাব, তবে দুটির মধ্যে যা চলছে তা আলাদা।

  • Perfetto-র মতো কোনও টুলে এখানে আসলে কী দেখা যাবে তার ট্রেস সহজ করতে, আপনি এই দুটি স্ট্যাটাস পড়ার সময় আসলে কী ঘটে তা আমরা পরীক্ষা করতে পারি।

  • এখানে, আমরা computedState.value-এ কল করার মাধ্যমে শুরু করি।

  • এটি ক্যালকুলেশন ল্যাম্বডা এক্সিকিউট করবে, যা পরে স্টেট ভ্যালু রিড করবে এবং রিড করা হয়েছে তা জানানোর জন্য সামান্য রক্ষণাবেক্ষণও করবে।

  • Compose-এ সব স্ন্যাপশট স্টেটের ক্ষেত্রে এটি প্রযোজ্য হবে।

  • দ্বিতীয়বার পড়ার সময় প্রথমবার পড়ার মতোই আচরণ করে এবং পুরো সময় জুড়ে একই পারফর্ম্যান্স বৈশিষ্ট্য থাকে।

  • তুলনা করলে, DerivedState-এর প্রথম রিড একই কাজ করে, যেখানে এটিকে এখনও ক্যালকুলেশন ল্যাম্বডা কল করতে হয় এবং এখনও অন্যান্য বিজ্ঞপ্তি পাঠায়, তবে এতে কিছুটা ক্যাশে ম্যানেজমেন্ট ওভারহেড রয়েছে, যা প্রথমবার কিছুটা শর্ট-সার্কিট হয় কারণ চেক করার জন্য কোনও ক্যাশে নেই।

  • তাই এটি ক্যাশিংয়ের জন্য কিছুটা রক্ষণাবেক্ষণ করে এবং তারপরে সামান্য বেশি সময়ে একই কাজ সম্পন্ন করে।

  • তবে, DerivedState-এর জন্য দ্বিতীয় রিড, ComputedState-এর জন্য দ্বিতীয় রিডের থেকে ভাল পারফর্ম করে, যদিও এই দুটিই খুব সাধারণ স্টেট।

  • আগের স্লাইডে যেমন বলেছি, কিছু ক্ষেত্রে স্ন্যাপশট রিডের খরচ তুচ্ছ নয় এবং ক্যাশে থেকে রিড করা আসলে রিড করার চেয়ে দ্রুত হয়, তাই DerivedState-এর জন্য দ্বিতীয় রিডের ক্ষেত্রে আমরা এই সামান্য সুবিধা দেখতে পাচ্ছি।

  • কিন্তু আসল মজার দৃশ্যটি হল, যখন স্টেটটি বাতিল করার প্রয়োজন হয় তখন কী ঘটে।

  • আমরা একে 'রিড-আফটার-রাইট' পরিস্থিতি বলি, যেখানে আপনি গণনার জন্য ব্যবহৃত কোনও একটি স্ট্যাটাস আপডেট করেন এবং গণনাটি আবার করতে হয়।

  • কোডে এটি দেখতে কেমন লাগে তা হল, আমরা 'a' পরিবর্তন করার মতো কিছু করি, হয়ত এটি ইনক্রিমেন্ট করি এবং তারপর আবার ভ্যালু পড়ি বা হয়ত রিকম্পোজ করি।

    var a by mutableStateOf(0)
    
    val derivedState = derivedStateOf { a > 0 }
    val computedState = computedStateOf { a > 0 }
    
    ...
    
    // Read-after-write
    a++
    derivedState.value
    computedState.value
  • আসল ডায়াগ্রামে এটি দেখতে কেমন হবে তা ComputedState-এর জন্য আবার ঠিক একই রকম হতে চলেছে।

  • এটির ম্যানেজ করার মতো কোনও ক্যাশে নেই, এটি দেখতে একদম একই রকম, প্রথম, দ্বিতীয়, তৃতীয়, যাই হোক না কেন, এটি আসলে কী তা পড়ুন।

  • তবে, DerivedState-এর জন্য কাজটা সহজ নয়।

  • এটি একটি অত্যন্ত ব্যয়বহুল পথের মধ্য দিয়ে যায় যাতে দেখা যায় যে ক্যাশেটি আপডেট করার আগেই অবৈধ এবং গণনাকে নিজেই কল করে এবং তারপরে এটিকে নির্ভরতা ট্র্যাকিং করতে হবে এবং ক্যাশে মানটি আবার লিখতে এবং বুঝতে হবে যে এই সমস্ত মানগুলি আসলে পরিবর্তিত হয়েছে এবং রক্ষণাবেক্ষণ নিজেই পরিচালনা করতে হবে।

  • এইসব কিছু যোগ হয়ে যায় এবং এর ফলে ComputedState-এর তুলনায় DerivedState-কে অবৈধ করার খরচ অনেক বেশি হয়।

  • এইসব দাবির সংখ্যা নির্ধারণ করতে, ComputedState সাধারণত প্রথমবার পড়ার সময় প্রায় ২০০ ন্যানোসেকেন্ড দ্রুত হয়।

  • ComputedState, Pixel 6-এ প্রায় ৩৫০ ন্যানোসেকেন্ড হারায়, বিশেষ করে, নির্দিষ্ট বেঞ্চমার্কিং পরিস্থিতিতে।

  • তাই, দ্বিতীয়বার পড়ার সময়, DerivedState-এর তুলনায় ComputedState-এর পারফর্ম্যান্স সামান্য কম হবে।

  • কিন্তু তারপরে, যে ক্ষেত্রে আমরা আসলে যত্ন নিই, যেখানে আমরা অবৈধ করছি এবং সম্ভবত যেখানে আপনার ফ্রেমে আসলে কাজ করার আছে, ComputedState প্রায় এবং আসলে, DerivedState-এর তুলনায় দ্বিগুণেরও বেশি দ্রুত।

  • তাই আপনি কীসের জন্য স্টেট ব্যবহার করছেন তার উপর নির্ভর করে, ComputedState বেছে নেওয়া খুব ভাল প্রথম বিকল্প হতে পারে।

  • সাধারণত, DerivedState এবং ComputedState ব্যবহার করার সময় এখনও সিদ্ধান্ত নিতে হবে।

  • আমরা ComputedState বন্ধ করছি না, এখনও দুটিরই ব্যবহার আছে।

  • সাধারণত, আপনি কোনটি বেছে নেবেন তা নিশ্চিত না হলে, ডিফল্ট হিসেবে কম্পিউটেড স্টেট বেছে নেওয়া ভাল।

  • ডেরাইভড স্টেট সবচেয়ে বেশি উপযোগী হয় যখন আপনি ক্যাশিংয়ের সুবিধা নেন, অর্থাৎ আপনি জটিল অ্যালগরিদম, বড় অ্যালোকেশন, অনেক স্টেট রিডের মতো কোনও নন-ট্রিভিয়াল কাজ করেন যা ক্যাশিংয়ের মাধ্যমে উপকৃত হয়, অথবা অবজেক্ট ইকুয়ালিটি ও অবজেক্ট আইডেন্টিটি ইকুয়ালিটির মতো বিষয়ের উপর নির্ভর করে এমন কোনও নন-ট্রিভিয়াল কাজ করেন, যেখানে আপনি পার্থক্য তৈরি করেন এবং ডেরাইভড স্টেটের অফার করা ক্যাশিংয়ের সুবিধা পান।

Compose-এ স্কিপিং ও স্টেবিলিটি

  • আরেকটি গুরুত্বপূর্ণ বিষয় হল, ডিরাইভড স্টেট ও কম্পিউটেড স্টেট, উভয়ই কম্পোজেবলকে ইনভ্যালিডেট করা এড়ানোর চেষ্টা করে।

  • এটি কম্পোজেবল এড়িয়ে যাওয়ার থেকে আলাদা, যা আমরা সাধারণত শর্তসাপেক্ষে বাতিল করার কথা ভাবার সময় বা কম্পোজেবলের মধ্যে কাজ না করার সময় বলি।

  • আমি এখানে যে সত্যটি প্রকাশ করতে চাই তা হল, Compose-এর মধ্যে স্টেবিলিটি এবং স্কিপিং সম্পর্কে অনেক কথা বলা হলেও, এটিই শেষ কথা নয় এবং এটি অপ্টিমাইজ করার জন্য সবসময় সঠিক জিনিস নয়।

  • আমরা আগেই বলেছি, কম্পোজিশনের সবকিছুর সাথে কিছু খরচ যুক্ত থাকে এবং এর মধ্যে স্কিপ করাও অন্তর্ভুক্ত।

    // What you write
    @Composable fun ContactListItem(
        contact: Contact
    ) { ... }
    
    // What you get
    @Composable fun ContactListItem(
        contact: Contact,
        $composer: Composer?
        $changed: Int
    ) {
        val $dirty = $changed or
            $composer.changed(contact)
    
        if ($dirty) { /* Your function body */ }
        else $composer.skipToGroupEnd()
    }
  • এড়িয়ে যাওয়া মানেই যে তুচ্ছ তা নয়।

  • এটি চালু করার জন্য আমাদের অনেক কিছু করতে হয়।

  • আমাদের আপনার সব প্যারামিটার স্টোর করা এবং প্রাথমিক কম্পোজিশনে সেগুলির জন্য জায়গা খোঁজা এবং তারপর আপনি রিকম্পোজ করলে সেই রেকর্ড আপডেট করার মতো কাজ করতে হয়।

  • আপনার কম্পোজেবল এড়িয়ে যাওয়া উচিত কিনা তা বুঝতে, আপনার ভ্যালু আগে কেমন ছিল তার সাথেও আমাদের তুলনা করতে হবে।

  • এবং তারপরে, এই সব কিছুই হল একটি if চেকের ক্ষমতা যা কোডটি এড়িয়ে যায় কিনা।

  • এখানে কী হচ্ছে তার উপর নির্ভর করে এটি সম্ভবত ব্যয়বহুল হতে পারে।

  • কম্পাইলারের জন্য একটি অপ্টিমাইজেশন আছে, যেখানে আপনি একই প্যারামিটার পাস করলে, আমরা সমতা চেক আবার ব্যবহার করতে পারি, তবে এটিই শেষ নয় এবং এটিকে হারানো বেশ সহজ।

  • স্কিপিং আমাদের সাথে একটু বিশ্বাসঘাতকতা করছে, এর উদাহরণ দেখতে, আমরা স্ক্রোলিং তালিকার একটি ক্লাসিক্যাল উদাহরণ দেখতে পারি, যেখানে গুরুত্বপূর্ণভাবে, কিছু বিশাল অবজেক্ট রয়েছে যাতে স্ক্রিনে কম্পোজ করার জন্য সমস্ত ডেটা রয়েছে।

    data class ContactsModel(
        val header: String,
        val contacts: List<Contact>
    )
    
    data class Contact(...)
    
    @Composable
    fun ContactsScreen(model: ContactsModel) {
        Column {
            TopAppBar(title = { Text(model.header) })
            ContactsList(model.contacts)
        }
    }
    
    @Composable
    fun ContactsList(contacts: List<Contact>) {
        LazyColumn {
            items(contacts) { ContactListItem(it) }
        }
    }
    
    @Composable
    fun ContactListItem(contact: Contact) { ... }
  • সুতরাং এখানে, স্ক্রিন মডেলে হেডার স্ক্রিনের মতো কিছু থাকে এবং তারপরে পরিচিতির সমস্ত তালিকা থাকে যা এটি তারপরে কয়েকটি কম্পোজেবলের মাধ্যমে পাস করে যা-- অবশেষে একটি লেজি লিস্ট কল করে এবং তারপরে কিছু আইটেম সেলের সাথে স্ক্রিনে দেখায়।

  • এই কোডের কম্পোজিশন হায়ারার্কি কিছুটা এইরকম দেখায়, যেখানে আমরা আবার কন্ট্যাক্ট স্ক্রিন দিয়ে শুরু করি, আমরা একটু ফ্যান আউট করি এবং তারপরে অন্য কিছু কম্পোজেবল থাকে যা আমাদের আইটেমগুলিকে কল করে এবং উপস্থাপন করে।

  • আমাদের ডেটা কীভাবে পাস হয় তা যদি আমরা দেখি, তাহলে আমরা উপরে থাকা মডেল থেকে শুরু করি।

  • আমরা এটিকে একটি স্ট্রিং এবং তারপরে একটি তালিকায় ডিস্ট্রাকচার করি, সেই তালিকাটি তারপরে লেজি তালিকার জন্য একটি আইটেম ল্যাম্বডাতে রূপান্তরিত হয় এবং তারপরে লেজি তালিকাটি স্ক্রিনে প্রদর্শিত সমস্ত আইটেম কম্পোজ করবে।

  • এই তালিকার একদম শেষ পরিচিতিটি পরিবর্তন করলে কী হয় তা দেখা যাক।

  • আমরা চাই যে তালিকার শেষ আইটেমটি বাতিল করা হোক, কিন্তু এখানে তা হবে না।

  • আমরা যদি এই রিকম্পোজিশনের জন্য কম্পোজিশন ট্রেস দেখি, তাহলে এটি এরকম কিছু দেখাবে, যেখানে আমরা কন্ট্যাক্ট স্ক্রিন থেকে শুরু করি এবং শেষ পর্যন্ত এই তালিকা আইটেমে আমাদের কাজ শেষ করি।

  • আর এখানে নামার জন্য এটি বেশ ব্যয়বহুল উপায়।

  • আমরা আরও দেখতে পাচ্ছি যে এই সব বিভাগে ট্রেসের মধ্যে কিছুই ঘটছে না বলে মনে হচ্ছে।

  • যদিও এখানে এটি স্পষ্ট নয়, আসলে এখানেই কম্পোজেবলগুলি সিদ্ধান্ত নিচ্ছে যে তারা এড়িয়ে যাবে কিনা।

  • এই উদাহরণের ক্ষেত্রে, লেজি লিস্ট যেভাবে রিকম্পোজ করে তার জন্য শুধুমাত্র দুটি কম্পোজেবল এড়িয়ে যাওয়া হয়।

  • আপনি এটিকে নতুন কন্টেন্ট ল্যাম্বডা দিলে, এটিতে থাকা সব আইটেম বাতিল করে দেবে।

  • তাই এটি এমন দুটি পরিচিতিকে বাতিল করবে যা পরিবর্তিত হয়নি, সাথে একটি পরিবর্তিত হয়েছে এবং সেই দুটিই এখানে একমাত্র আইটেম যা এড়িয়ে যাওয়া হয়েছে।

  • অন্য সবকিছু এই স্কিপিং ইকুয়ালিটি তুলনা করছে শুধুমাত্র এটি বুঝতে যে এটি আসলে কার্যকর করতে হবে।

  • আপনার অবজেক্টগুলি স্থিতিশীল হলে, এই তুলনাটি আসলে বেশ ব্যয়বহুল হতে পারে।

  • আপনি যদি আমাদের আপনার সমস্ত ডেটা স্ট্রাকচার দেখতে বাধ্য করেন, তাহলে এটি আসলে যোগ হতে পারে এবং দুটি অবজেক্ট সমান কিনা তা বলার জন্য একটি নন-ট্রিভিয়াল খরচ হতে পারে।

  • এবং আরও খারাপ, কারণ আমরা ডিস্ট্রাকচার করেছি, আমাদের আসলে তালিকায় একই তুলনা দুবার করতে হবে।

  • পরিবর্তে, আপনি যদি কম্পাইলারকে ডিফল্ট অ্যাকশন অনুযায়ী কাজ করতে দেন এবং স্ট্রং স্কিপিং ব্যবহার করেন, তাহলে আপনি এখনও স্কিপিং করতে পারবেন এবং আপনার কম্পোজেবল শর্তসাপেক্ষে স্কিপ করার জন্য এখনও চেক করতে পারবেন, তবে তারা স্ট্রাকচারাল ইকুয়ালিটির পরিবর্তে অবজেক্ট আইডেন্টিটি ইকুয়ালিটি ব্যবহার করার অনেক দ্রুত রুট বেছে নেয়।

  • এটি আমাদের পক্ষে গণনা করা অনেক দ্রুত এবং যদিও আমরা এই ফ্রেমে একই আইটেমগুলি পুনরায় কম্পোজ করি, যেখানে এটি আসলে গুরুত্বপূর্ণ যে আমরা সেখানে দ্রুত পৌঁছে যাই, আমরা এই কম্পোজেবলগুলি আসলে এড়িয়ে যেতে পারিনি তা খুঁজে বের করতে খুব বেশি সময় নষ্ট করি না।

  • এই কারণেই আমরা সরাসরি রিকম্পোজিশন কাউন্টের পরিবর্তে আপনার অ্যাপ্লিকেশনের ভিতরে কী ঘটছে তা বোঝার জন্য বেঞ্চমার্ক এবং ট্রেসের মতো টুল ব্যবহার করার উপর জোর দিই।

  • এগুলি একটি কার্যকর প্রক্সি হতে পারে, তবে আপনার অ্যাপ্লিকেশন অপ্টিমাইজ করার সময় এগুলির উপর হাইপার-ফিক্স বা ওভার-ইনডেক্স করার প্রয়োজন নেই।

  • মনে রাখবেন, আপনার কম্পোজেবল এড়িয়ে যাওয়ার চেষ্টা করার পরিবর্তে, শুরুতেই এটি বাতিল করা এড়িয়ে চলুন।

মেথড ট্রেসের মাধ্যমে এক্সিকিউশন বিশ্লেষণ করা

  • আমরা এই উদাহরণে দেখেছি যে কম্পোজিশন ট্রেস কী ঘটছে সে সম্পর্কে অনেক তথ্য দিতে পারে, তবে সেগুলিও সম্পূর্ণ ছবি দেখায় না।

  • সেই জন্য, আন্দ্রেই আমাদের মেথড ট্রেস সম্পর্কে বলবেন।

  • ঠিক আছে।

  • অ্যান্ড্রু আগেই বলেছেন, কম্পোজিশন ট্রেসিং সবসময় আপনাকে সবকিছু বলে না, কারণ এটি শুধুমাত্র কম্পোজেবল ফাংশন অ্যানোটেট করে এবং এমন কিছু ক্ষেত্রে আপনি কম্পোজিশন ট্রেসে ফাঁকা জায়গা দেখতে পাবেন যা Perfetto ট্রেসকে আরও উন্নত করে, কিন্তু এখনও সেখানে যা ঘটছে তার সবকিছু দেখায় না।

  • আর কখনও কখনও, এটি Compose-এর করা কিছু হতে পারে, কখনও কখনও এটি আপনার কোডের কিছু হতে পারে, এখানে কম্পোজিশন ট্রেস দেখে এটি বোঝা সত্যিই কঠিন।

  • এখন আপনি যা করতে চান তা হল মেথড ট্রেস নেওয়া।

  • প্রোফাইলারের মধ্যে একটি আইটেম থাকে, যেমন Android Studio-তে প্রোফাইলারের মধ্যে একটি আইটেম থাকে অথবা আপনি ট্রেস নেওয়ার জন্য ADB কমান্ডও ব্যবহার করতে পারেন এবং এটি আপনাকে Java-তে হওয়া প্রতিটি ফাংশন কল দেখাবে।

  • Compose Compiler সেখানে যা কিছু এনকোড করে, Compose Runtime যা কিছু করে এবং আপনার কোড যা কিছু করে, তার সবকিছুই এর মধ্যে পড়ে এবং ঠিক কী এক্সিকিউট করা হচ্ছে, সেই স্পেসে কোন ফাংশন কল করা হয়েছে, তা ট্র্যাক ও তদন্ত করার জন্য এটি খুবই উপযোগী।

  • একটা জিনিস, আমি চাই-- এই আইটেমটা মাঝখানে দেখতে।

  • আমি- আমি উল্লেখ করতে চাই যে মেথড ট্রেসিংয়ের ওভারহেড অনেক বেশি।

  • আপনার কাছে ১০ থেকে ২০ গুণ বেশি ওভারহেড আছে, যা নির্ভর করে ফাংশন ট্রি কতটা জটিল তার উপর, কারণ প্রতিটি ফাংশন কল একটু একটু করে যোগ করে।

  • এবং সেটি বোঝাতে, আমরা স্ক্রিনশট দেখতে পারি।

  • অ্যাপ চালু হওয়ার সময় মেথড ট্রেস সাধারণত এরকম দেখতে হয় এবং আপনি হয়ত জিজ্ঞাসা করতে পারেন, "আমি এটি কীভাবে বুঝব?"

  • সাধারণত কম্পোজিশন ট্রেস শুরু করার সময়, আপনি এখানে থাকা ফাংশনগুলি দেখেন।

  • সুতরাং, এটি সরলীকৃত কম্পোজিশন ট্রেসের মতো, যেখানে তাদের ScreenContent, কিছু বোতাম এবং অন্যান্য কিছু ফাংশন রয়েছে।

  • ধরা যাক, ScreenContent-এ কী ঘটছে তা আমরা জানতে চাই।

  • Perfetto-তে একটি সার্চ বার আছে।

  • আপনি Perfetto ভিউয়ারে আপনার মেথড ট্রেস লোড করেন, আপনি এখানে আপনার মতো একই ফাংশন সার্চ করেন, ScreenContent, এটি এমন কিছুতে পৌঁছাবে, যা স্ক্রিনের জন্য মেথড ট্রেস।

  • তাই, আপনি এখানে দেখতে পাচ্ছেন যে কিছু Composer.startGroup এবং গ্রুপ কল রয়েছে।

  • আপনার কম্পোজিশন যাতে সত্যিই ম্যাজিক দেখাতে পারে তা নিশ্চিত করতে রানটাইম এবং কম্পাইলার ব্যাকগ্রাউন্ডে আপনার জন্য এই কাজ করে, তবে এখানে আকর্ষণীয় কল হল Composer.changed।

  • কম্পোজেবলের আগের ইনভোকেশন এবং বর্তমান ইনভোকেশনের মধ্যে প্যারামিটার পরিবর্তন হয়েছে কিনা তা আমরা এইভাবে চেক করি।

  • এবং এই Composer.changed-এর বেশিরভাগই এই ScreenModel.equals দ্বারা প্রভাবিত।

  • তাই, ScreenModel হয়ত কোনও বড় ডেটা ক্লাস এবং হয়ত আমরা এটিকে রিকম্পোজিশন কাউন্টে সাহায্য করার জন্য স্টেবল করেছি, তাই হয়ত এটি কম্পাইলার রিপোর্টে দেখা গেছে।

  • এবং এই নির্দিষ্ট ক্ষেত্রে পারফর্ম্যান্সের জন্য এই স্টেবল অ্যানোটেশন সরিয়ে দিলে হয়ত সুবিধা হবে।

  • তাই, আপনি সেটি খুঁজতে চাইবেন এবং কম্পোজিশন মেথড ট্রেস হল এটি খুঁজে পাওয়ার সেরা টুল।

  • ঠিক আছে।

  • আজ আমরা অনেক কিছু দেখেছি, তাই এখন অ্যান্ড্রু আমাদের শেষ করতে সাহায্য করবে।

দ্রুত কম্পোজেবল ডিজাইন ও পারফর্ম্যান্স টুল

  • আজকে আমরা যেসব বিষয়ে আলোচনা করেছি তার একটি হাই-লেভেল সারসংক্ষেপ দিয়ে শেষ করতে চাই। আপনি যখন কম্পোজেবল ডিজাইন করছেন এবং তারপরে আপনার আগে থেকে থাকা অ্যাপ অপ্টিমাইজ করছেন, তখন কয়েকটি বিষয় মাথায় রাখতে হবে।

  • প্রথমত, মনে রাখবেন যে সস্তা কম্পোজেবল এবং কম্পোজেবল যা আপনি বাতিল করেন না সেগুলি আপনার এড়িয়ে যাওয়া কম্পোজেবলের চেয়ে ভাল।

  • মনে রাখবেন, কম্পোজেবল ডিজাইন করার সময়, ছোট এবং সহজে তুলনা করা যায় এমন আর্গুমেন্ট বিবেচনা করা ভালো এবং অপ্টিমাইজেশনের সুবিধা নিতে অন্যান্য ফাংশন কলের সাথে তুলনা করার সময় সম্ভবত তুলনাগুলি আবার ব্যবহার করা ভালো।

  • আপনার কম্পোজ করার উপযুক্ত আইটেমের মধ্যে API ব্যবহার করার সময়, মনে রাখবেন যে পারফর্ম্যান্স বা ফ্রেম টাইম API-এর খরচ এবং আপনি কত ঘন ঘন সেগুলি ব্যবহার করেন তার উপর নির্ভর করে।

  • এই খরচগুলি কীভাবে যোগ হয় সে সম্পর্কে সচেতন থাকুন এবং এটিও মনে রাখবেন যে তাদের সাথে সম্পর্কিত টিয়ারডাউন খরচ থাকতে পারে যা আপনার অ্যাপ্লিকেশনের জন্য সবচেয়ে কম উপযুক্ত সময়ে আপনাকে প্রভাবিত করতে পারে।

  • এছাড়াও, মনে রাখবেন যে আপনার অ্যাপের মধ্যে অপ্টিমাইজ করার সময় একজন ভালো নাগরিক হওয়া গুরুত্বপূর্ণ।

  • সঠিক সিদ্ধান্ত নিতে বেঞ্চমার্ক নেওয়া শুরু করুন, আপনার কোডের সঠিক অংশ টার্গেট করছেন কিনা তা নিশ্চিত করতে আপনার অ্যাপের প্রোফাইল তৈরি করুন এবং বেঞ্চমার্ক ও প্রোফাইলিংয়ের ফলে আপনি যে পরিবর্তন করছেন এবং তার থেকে যে ফলাফল আশা করছেন তা যাচাই করুন।

  • এছাড়াও, মনে রাখবেন যে আপনার অ্যাপ্লিকেশনের মধ্যে রক্ষণাবেক্ষণ এবং পারফর্ম্যান্সের মধ্যে একটি ট্রেড-অফ থাকতে পারে।

  • তাই, আপনার ও আপনার টিমের জন্য যা সবচেয়ে ভালো হয়, সেটিই করুন যাতে আপনি অতিরিক্ত অপ্টিমাইজ না করেন এবং রক্ষণাবেক্ষণের ক্ষেত্রে নিজেকে কোণঠাসা না করে ফেলেন।

  • এছাড়াও, আরও সাহায্যের জন্য, আপনার কাছে আরও একটি টুল আছে এবং এটি হল AI এজেন্ট যা আপনার কাছে আগে থেকেই আছে।

  • আমরা Android CLI-এর অংশ হিসেবে এবং সেখানে আমাদের পাঠানো দক্ষতার অংশ হিসেবে একটি Jetpack Compose পারফর্ম্যান্স দক্ষতা লঞ্চ করেছি, যাতে আমরা আজ যে সমস্ত তথ্য নিয়ে আলোচনা করেছি তার অনেক কিছুই রয়েছে এবং আপনার অ্যাপ্লিকেশনটি পর্যালোচনা ও অডিট করতে পারে এবং এই ধরনের অপ্টিমাইজেশনের জন্য সাজেশন দিতে পারে।

  • Android CLI ব্যবহার করে আপনার আগে থেকে থাকা এজেন্টে এটি ইনস্টল করতে পারবেন।

    android skills add jetpack-compose-performance
  • Android CLI সম্পর্কে আরও তথ্য পেতে, আপনি developer.android.com থেকে আরও জানতে পারবেন।

  • এছাড়াও, আমাদের GitHub রিপোজিটরিতে আমাদের স্কিল সম্পর্কে আরও জানতে পারবেন।

  • আর এর সাথে, নিরাপদে বেঞ্চমার্কিং করুন এবং কম্পোজ করার আনন্দ উপভোগ করুন।

কোড

কোড স্নিপেট

"Managing side effects" ভিডিওর 09:34-এ Kotlin স্নিপেট
@Composable
fun MediaPlayer(contentSource: Uri, playbackRate: Float) {
    val mediaPlayer = rememberMediaPlayer()

    // Asynchronous work and animations
    LaunchedEffect(contentSource) { mediaPlayer.load(contentSource) }
}
"সাইড এফেক্ট ম্যানেজ করা" ভিডিওর 10:15-এ Kotlin স্নিপেট
@Composable
fun MediaPlayer(contentSource: Uri, playbackRate: Float) {
    val activity = LocalActivity.current

    // Setup and teardown
    DisposableEffect(Unit) {
        activity.requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE
        onDispose {
            activity.requestedOrientation = SCREEN_ORIENTATION_UNSPECIFIED
        }
    }
}
"Managing side effects"-এ 10:36-এ Kotlin স্নিপেট
@Composable
fun MediaPlayer(contentSource: Uri, playbackRate: Float) {
    val mediaPlayer = rememberMediaPlayer()

    // One-shot events
    SideEffect(Unit) { mediaPlayer.play() }
}
"Managing side effects" ভিডিওর 11:12-এ Kotlin স্নিপেট
@Composable
fun MediaPlayer(contentSource: Uri, playbackRate: Float) {
    val mediaPlayer = rememberMediaPlayer()

    // Synchronize the outside world to the state of composition
    SideEffect { mediaPlayer.playbackRate = playbackRate }
}
"সাইড এফেক্ট ম্যানেজ করা" ভিডিওর ১২:১২-এ Kotlin স্নিপেট
@Composable
fun ShoppingCartScreen(
    viewModel: CartViewModel
) {
    LaunchedEffect(Unit) { viewModel.loadCart() }
    LaunchedEffect(Unit) { viewModel.loadPaymentMethods() }
    LaunchedEffect(Unit) { viewModel.loadDeliveryAddresses() }

    CartContent(...)
}
"Managing side effects"-এ ১২:৩৬-এ Kotlin স্নিপেট
@Composable
fun ShoppingCartScreen(
    viewModel: CartViewModel
) {
    LaunchedEffect(Unit) {
        launch { viewModel.loadCart() }
        launch { viewModel.loadPaymentMethods() }
        launch { viewModel.loadDeliveryAddresses() }
    }

    CartContent(...)
}
"স্টেট অপ্টিমাইজেশন এবং ইনভ্যালিডেশন" ভিডিওর 15:12-এ Kotlin স্নিপেট
@Composable
fun ScrollToTopButton(
    scrollState: ScrollState
) {
    val showScrollToTopButton = scrollState.value > 0
    val coroutineScope = rememberCoroutineScope()

    if (showScrollToTopButton) {
        FloatingActionButton(
            onClick = {
                coroutineScope.launch { scrollState.animateScrollTo(0) }
            }
        ) {
            Icon(Icons.Default.ArrowUpward, "Scroll to Top")
        }
    }
}
"স্টেট অপ্টিমাইজেশন এবং ইনভ্যালিডেশন" ভিডিওর ১৫:৫১-এ Kotlin স্নিপেট
@Composable
fun ScrollToTopButton(
    scrollState: ScrollState
) {
    val showScrollToTopButton by remember { computedStateOf { scrollState.value > 0 } }
    val coroutineScope = rememberCoroutineScope()

    if (showScrollToTopButton) {
        FloatingActionButton(
            onClick = {
                coroutineScope.launch { scrollState.animateScrollTo(0) }
            }
        ) {
            Icon(Icons.Default.ArrowUpward, "Scroll to Top")
        }
    }
}
"স্টেট অপ্টিমাইজেশন ও ইনভ্যালিডেশন" ভিডিওর ১৬:৪৯-এ Kotlin স্নিপেট
var a by mutableStateOf(0)

val derivedState = derivedStateOf { a > 0 }
val computedState = computedStateOf { a > 0 }

// First read
derivedState.value
computedState.value

// Second read
derivedState.value
computedState.value
"স্টেট অপ্টিমাইজেশন ও ইনভ্যালিডেশন" ভিডিওর ১৮:৩৫-এ Kotlin স্নিপেট
var a by mutableStateOf(0)

val derivedState = derivedStateOf { a > 0 }
val computedState = computedStateOf { a > 0 }

...

// Read-after-write
a++
derivedState.value
computedState.value
"Compose-এ স্কিপ করা ও স্টেবিলিটি" ভিডিওর ২১:০৭-এ Kotlin স্নিপেট
// What you write
@Composable fun ContactListItem(
    contact: Contact
) { ... }

// What you get
@Composable fun ContactListItem(
    contact: Contact,
    $composer: Composer?
    $changed: Int
) {
    val $dirty = $changed or
        $composer.changed(contact)

    if ($dirty) { /* Your function body */ }
    else $composer.skipToGroupEnd()
}
"Compose-এ স্কিপ করা ও স্টেবিলিটি" ভিডিওর ২১:৫৩-এ Kotlin স্নিপেট
data class ContactsModel(
    val header: String,
    val contacts: List<Contact>
)

data class Contact(...)

@Composable
fun ContactsScreen(model: ContactsModel) {
    Column {
        TopAppBar(title = { Text(model.header) })
        ContactsList(model.contacts)
    }
}

@Composable
fun ContactsList(contacts: List<Contact>) {
    LazyColumn {
        items(contacts) { ContactListItem(it) }
    }
}

@Composable
fun ContactListItem(contact: Contact) { ... }
"Fast composable design and performance tools"-এ 29:40-এ Shell স্নিপেট
android skills add jetpack-compose-performance