মিডিয়া প্লেব্যাক উন্নত করা: Media3-এর মাধ্যমে প্রি-লোডিংয়ের সূচনা - পার্ট ১
৮ মিনিট রিডিং
আজকের মিডিয়া-কেন্দ্রিক অ্যাপে, ব্যবহারকারীর চমৎকার অভিজ্ঞতার জন্য নির্বিঘ্নে প্লেব্যাক অভিজ্ঞতা প্রদান করা অত্যন্ত গুরুত্বপূর্ণ। ব্যবহারকারীরা আশা করেন যে তাদের ভিডিও সাথে সাথেই শুরু হবে এবং কোনও বিরতি ছাড়াই নির্বিঘ্নে চলবে।
মূল সমস্যা হল লেটেন্সি। প্রথাগতভাবে, ব্যবহারকারী প্লেব্যাকের জন্য কোনও আইটেম বেছে নেওয়ার পরেই ভিডিও প্লেয়ার তার কাজ শুরু করে—কানেক্ট করা, ডাউনলোড করা, পার্স করা, বাফার করা। বর্তমান সময়ের স্বল্প দৈর্ঘ্যের ভিডিওর ক্ষেত্রে এই প্রতিক্রিয়াশীল পদ্ধতিটি খুব ধীরগতির। এর সমাধান হল প্রোঅ্যাক্টিভ হওয়া। ব্যবহারকারী এর পরে কী দেখবেন তা আমাদের অনুমান করতে হবে এবং সময়মতো কন্টেন্ট রেডি রাখতে হবে। প্রিলোডিংয়ের মূল কথা এটাই।
প্রিলোডিংয়ের মূল সুবিধাগুলির মধ্যে এগুলি অন্তর্ভুক্ত:
- 🚀 দ্রুত প্লেব্যাক শুরু: ভিডিও আগেই রেডি হয়ে যায়, এর ফলে আইটেমগুলির মধ্যে দ্রুত ট্রানজিশন হয় এবং ভিডিও সঙ্গে সঙ্গে শুরু করা যায়।
- 📉 বাফারিং কমে যাওয়া: আগে থেকেই ডেটা লোড করার মাধ্যমে, প্লেব্যাক অনেক কম স্টল হওয়ার সম্ভাবনা থাকে, যেমন নেটওয়ার্কের সমস্যার কারণে।
- ✨ এর ফলে ব্যবহারকারীর আরও ভালো অভিজ্ঞতা হয়: দ্রুত শুরু হওয়া ও কম বাফারিংয়ের ফলে ব্যবহারকারীরা আরও সাবলীল ও নির্বিঘ্নে ইন্টার্যাক্ট করতে পারেন।
এই তিন-পার্টের সিরিজে, আমরা Media3-এর কম্পোনেন্ট (প্রি)লোডিংয়ের শক্তিশালী ইউটিলিটি সম্পর্কে জানাব এবং গভীরভাবে আলোচনা করব।
- পার্ট ১-এ, আমরা মূল বিষয়গুলি কভার করব: Media3-তে উপলভ্য বিভিন্ন প্রি-লোডিং স্ট্র্যাটেজি বোঝা, PreloadConfiguration চালু করা এবং DefaultPreloadManager সেট-আপ করা, আইটেম প্রি-লোড করার জন্য আপনার অ্যাপ চালু করা। এই ব্লগটি পড়ার পরে, আপনি কনফিগার করা র্যাঙ্কিং ও সময়সীমা সহ মিডিয়া আইটেম প্রি-লোড করতে ও চালাতে পারবেন।
- পার্ট ২-এ, আমরা DefaultPreloadManager-এর আরও উন্নত বিষয়গুলি নিয়ে আলোচনা করব: অ্যানালিটিক্সের জন্য লিসনার ব্যবহার করা, স্লাইডিং উইন্ডো প্যাটার্ন এবং DefaultPreloadManager ও ExoPlayer-এর কাস্টম শেয়ার করা কম্পোনেন্টের মতো প্রোডাকশন-রেডি সেরা প্র্যাক্টিস এক্সপ্লোর করা।
- পার্ট ৩-এ, আমরা DefaultPreloadManager-এর মাধ্যমে ডিস্ক ক্যাশিং সম্পর্কে বিস্তারিত জানব।
প্রিলোডিংয়ের মাধ্যমে সমাধান! 🦸♀️
প্রিলোডিংয়ের মূল ধারণাটি খুবই সহজ: আপনার প্রয়োজন হওয়ার আগেই মিডিয়া কন্টেন্ট লোড করে নিন। ব্যবহারকারী পরের ভিডিওতে সোয়াইপ করার আগেই, ভিডিওর প্রথম সেগমেন্ট ডাউনলোড হয়ে যায় এবং সঙ্গে সঙ্গে প্লেব্যাকের জন্য উপলভ্য থাকে।
এটি একটি রেস্তোরাঁর মতো করে ভাবুন। ব্যস্ত কিচেন পেঁয়াজ কাটার জন্য অর্ডারের অপেক্ষা করে না। 🧅 তারা আগে থেকে প্রস্তুতি নিয়ে রাখে। প্রিলোডিং হল আপনার ভিডিও প্লেয়ারের জন্য প্রস্তুতিমূলক কাজ।
চালু করা হলে, প্লেব্যাক বাফার পরবর্তী আইটেমে পৌঁছানোর আগে কোনও ব্যবহারকারী পরবর্তী আইটেমে স্কিপ করলে, প্রি-লোডিং যোগদানের লেটেন্সি কমাতে সাহায্য করতে পারে। পরবর্তী উইন্ডোর প্রথম পিরিয়ড প্রস্তুত করা হয় এবং ভিডিও, অডিও ও টেক্সট স্যাম্পেল বাফার করা হয়। প্রিলোড করা পিরিয়ড পরে প্লেয়ারে কিউ করা হয়, যেখানে বাফার করা স্যাম্পেল সঙ্গে সঙ্গে উপলভ্য থাকে এবং রেন্ডারিংয়ের জন্য কোডেকের কাছে পাঠানোর জন্য রেডি থাকে।
Media3-তে প্রি-লোডিংয়ের জন্য দুটি প্রাথমিক API আছে, প্রতিটি আলাদা আলাদা ব্যবহারের ক্ষেত্রে উপযুক্ত। সঠিক API বেছে নেওয়া হল প্রথম ধাপ।
১. PreloadConfiguration-এর মাধ্যমে প্লেলিস্ট আইটেম প্রিলোড করা
এটি একটি সহজ পদ্ধতি, যা প্লেলিস্টের মতো লিনিয়ার, সিকোয়েন্সিয়াল মিডিয়ার ক্ষেত্রে উপযোগী যেখানে প্লেব্যাকের ক্রম অনুমান করা যায় (যেমন, পর্বের সিরিজ)। আপনি ExoPlayer-এর প্লেলিস্ট এপিআই ব্যবহার করে প্লেয়ারকে মিডিয়া আইটেমের সম্পূর্ণ তালিকা দেন এবং প্লেয়ারের জন্য PreloadConfiguration সেট করেন, তারপরে এটি কনফিগার করা অনুযায়ী সিকোয়েন্সে থাকা পরবর্তী আইটেম অটোমেটিক প্রিলোড করে। প্লেব্যাক বাফার আগেই পরবর্তী আইটেমের সাথে ওভারল্যাপ করার আগে কোনও ব্যবহারকারী পরবর্তী আইটেমে স্কিপ করলে, এই API যোগদানের লেটেন্সি অপ্টিমাইজ করার চেষ্টা করে।
চলমান প্লেব্যাকের জন্য কোনও মিডিয়া লোড না করা হলে তবেই প্রি-লোডিং শুরু হয়, এর ফলে প্রাথমিক প্লেব্যাকের সাথে ব্যান্ডউইথের জন্য প্রতিযোগিতা করতে হয় না।
প্রিলোডিংয়ের প্রয়োজন আছে কিনা সেই ব্যাপারে এখনও নিশ্চিত না হলে, এই API হল এটি ব্যবহার করে দেখার জন্য একটি দুর্দান্ত লো-লিফ্ট বিকল্প!
player.preloadConfiguration =
PreloadConfiguration(/* targetPreloadDurationUs= */ 5_000_000L)উপরে দেওয়া PreloadConfiguration-এর মাধ্যমে, প্লেয়ার প্লেলিস্টের পরবর্তী আইটেমের জন্য পাঁচ সেকেন্ডের মিডিয়া প্রিলোড করার চেষ্টা করে।
অপ্ট-ইন করার পরে, প্লেলিস্ট প্রি-লোডিং বন্ধ করতে PreloadConfiguration.DEFAULT ব্যবহার করে প্লেলিস্ট প্রি-লোডিং বন্ধ করা যেতে পারে:
player.preloadConfiguration = PreloadConfiguration.DEFAULT
২. PreloadManager-এর মাধ্যমে ডায়নামিক তালিকা প্রিলোড করা
উল্লম্ব ফিড বা ক্যারোজেলের মতো ডাইনামিক UI-এর ক্ষেত্রে, যেখানে ব্যবহারকারীর ইন্টার্যাকশনের মাধ্যমে "পরবর্তী" আইটেম নির্ধারণ করা হয়, সেখানে PreloadManager API উপযুক্ত। এটি Media3 ExoPlayer লাইব্রেরির মধ্যে একটি নতুন শক্তিশালী, স্বতন্ত্র কম্পোনেন্ট যা আগে থেকেই প্রিলোড করার জন্য বিশেষভাবে ডিজাইন করা হয়েছে। এটি সম্ভাব্য MediaSource-এর একটি সংগ্রহ ম্যানেজ করে, ব্যবহারকারীর বর্তমান অবস্থানের সাথে নৈকট্যের ভিত্তিতে সেগুলিকে অগ্রাধিকার দেয় এবং কী প্রিলোড করতে হবে তার উপর গ্র্যানুলার নিয়ন্ত্রণ অফার করে, যা ছোট দৈর্ঘ্যের ভিডিওর ডায়নামিক ফিডের মতো জটিল পরিস্থিতির জন্য উপযুক্ত।
আপনার PreloadManager সেট-আপ করা
DefaultPreloadManager হল PreloadManager-এর জন্য প্রামাণিক প্রয়োগ।
DefaultPreloadManager-এর বিল্ডার, ডিফল্ট প্রি-লোড ম্যানেজার ও যেকোনও ExoPlayer ইনস্ট্যান্স তৈরি করতে পারে যা এর প্রি-লোড করা কন্টেন্ট চালাবে। DefaultPreloadManager তৈরি করতে, আপনাকে একটি TargetPreloadStatusControl পাস করতে হবে, যা প্রি-লোড ম্যানেজার কোনও আইটেমের জন্য কতটা লোড করতে হবে তা খুঁজে বের করার জন্য কোয়েরি করতে পারে। নিচের বিভাগে আমরা TargetPreloadStatusControl-এর একটি উদাহরণ ব্যাখ্যা ও সংজ্ঞায়িত করব।
val preloadManagerBuilder = DefaultPreloadManager.Builder(context, targetPreloadStatusControl) val preloadManager = val preloadManagerBuilder.build() // Build ExoPlayer with DefaultPreloadManager.Builder val player = preloadManagerBuilder.buildExoPlayer()
ExoPlayer ও DefaultPreloadManager, দু'টির জন্যই একই বিল্ডার ব্যবহার করা প্রয়োজন। এটি নিশ্চিত করে যে দু'টির কম্পোনেন্ট সঠিকভাবে শেয়ার করা হয়েছে।
এই পর্যন্তই! নির্দেশাবলী পাওয়ার জন্য এখন আপনার কাছে একজন ম্যানেজার আছেন।
TargetPreloadStatusControl-এর মাধ্যমে সময়সীমা ও র্যাংকিং কনফিগার করা
আপনি যদি ১০ সেকেন্ডের ভিডিও প্রি-লোড করতে চান, তাহলে কী করবেন? আপনি ক্যারোজেলের মধ্যে আপনার মিডিয়া আইটেমের পজিশন প্রদান করতে পারবেন এবং DefaultPreloadManager আইটেম লোড করার ক্ষেত্রে অগ্রাধিকার দেয়, এটি ব্যবহারকারী বর্তমানে যে আইটেমটি চালাচ্ছেন তার কতটা কাছাকাছি আছে তার উপর ভিত্তি করে অগ্রাধিকার দেয়।
আপনি যদি আইটেমটি কতক্ষণ প্রিলোড করতে চান তা নিয়ন্ত্রণ করতে চান, তাহলে আপনি DefaultPreloadManager.PreloadStatus ব্যবহার করে তা জানাতে পারেন।
যেমন,
- আইটেম ‘ক’ হল সবচেয়ে বেশি অগ্রাধিকার, ৫ সেকেন্ডের ভিডিও লোড করো।
- আইটেম 'খ' মাঝারি অগ্রাধিকারের, তবে এটিতে পৌঁছালে ৩ সেকেন্ডের ভিডিও লোড করুন।
- আইটেম ‘C’ কম অগ্রাধিকারযুক্ত, শুধুমাত্র ট্র্যাক লোড করুন।
- 'ঘ' আইটেমটি আরও কম অগ্রাধিকারযুক্ত, শুধু প্রস্তুতি নিন।
- অন্যান্য আইটেম অনেক দূরে আছে, কোনও কিছু প্রি-লোড করবেন না।
এই গ্র্যানুলার কন্ট্রোল আপনাকে রিসোর্স ব্যবহার অপ্টিমাইজ করতে সাহায্য করতে পারে যা নিরবচ্ছিন্ন প্লেব্যাকের জন্য সাজেস্ট করা হয়।
import androidx.media3.exoplayer.DefaultPreloadManager.PreloadStatus
class MyTargetPreloadStatusControl(
currentPlayingIndex: Int = C.INDEX_UNSET
) : TargetPreloadStatusControl<Int,PreloadStatus> {
// The app is responsible for updating this based on UI state
override fun getTargetPreloadStatus(index: Int): PreloadStatus? {
val distance = index - currentPlayingIndex
// Adjacent items (Next): preload 5 seconds
if (distance == 1) {
// Return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED and suggest loading // 5000ms from the default start position
return PreloadStatus.specifiedRangeLoaded(5000L)
}
// Adjacent items (Previous): preload 3 seconds
else if (distance == -1) {
// Return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED //and suggest loading 3000ms from the default start position
return PreloadStatus.specifiedRangeLoaded(3000L)
}
// Items two positions away: just select tracks
else if (distance) == 2) {
// Return a PreloadStatus that is labelled by STAGE_TRACKS_SELECTED
return PreloadStatus.TRACKS_SELECTED
}
// Items four positions away: just select prepare
else if (abs(distance) <= 4) {
// Return a PreloadStatus that is labelled by STAGE_SOURCE_PREPARED
return PreloadStatus.SOURCE_PREPARED
}
// All other items are too far away
return null
}
}পরামর্শ: PreloadManager আগের ও পরের আইটেম দু'টিই প্রি-লোড করে রাখতে পারে, তবে PreloadConfiguration শুধুমাত্র পরের আইটেম প্রি-লোড করার দিকেই নজর দেয়।
প্রিলোডিং আইটেম ম্যানেজ করা
আপনার ম্যানেজার তৈরি হয়ে গেলে, আপনি তাকে কী কাজ করতে হবে তা বলা শুরু করতে পারেন। আপনার ব্যবহারকারী ফিড স্ক্রল করার সময়, আপনি আসন্ন ভিডিও শনাক্ত করে সেগুলিকে ম্যানেজারে যোগ করবেন। PreloadManager-এর সাথে ইন্টার্যাকশন হল আপনার UI ও প্রিলোডিং ইঞ্জিনের মধ্যে স্টেট-পরিচালিত কথোপকথন।
১. মিডিয়া আইটেম যোগ করুন
আপনার ফিড পূরণ করার সময়, ট্র্যাক করতে হবে এমন মিডিয়ার ম্যানেজারকে সেই বিষয়ে জানাতে হবে। আপনি যদি শুরু করেন, তাহলে আপনি প্রিলোড করতে চান এমন সম্পূর্ণ তালিকা যোগ করতে পারেন। এর পরে, প্রয়োজন অনুযায়ী আপনি তালিকায় একটি করে আইটেম যোগ করতে পারবেন। প্রিলোডিং তালিকায় কোন আইটেম থাকবে তার উপর আপনার সম্পূর্ণ নিয়ন্ত্রণ থাকে, এর অর্থ হল ম্যানেজার থেকে কী যোগ করা হবে এবং কী সরানো হবে তা আপনাকে ম্যানেজ করতে হবে।
val initialMediaItems = pullMediaItemsFromService(/* count= */ 20)
for (index in 0 until initialMediaItems.size) {
preloadManager.add(
initialMediaItems.get(index),index)
)
}ম্যানেজার এখন ব্যাকগ্রাউন্ডে এই MediaItem-এর জন্য ডেটা ফেচ করা শুরু করবে।
যোগ করার পরে, ম্যানেজারকে নতুন তালিকাটি আবার মূল্যায়ন করতে বলুন (ইঙ্গিত করুন যে কিছু পরিবর্তন হয়েছে, যেমন কোনও আইটেম যোগ করা/ সরানো হয়েছে বা ব্যবহারকারী নতুন আইটেম চালাতে পাল্টেছেন)।
preloadManager.invalidate()
২. আইটেম ফিরিয়ে আনা ও চালানো
এখানে মূল প্লেব্যাক লজিক দেওয়া হল। ব্যবহারকারী যখন সেই ভিডিওটি চালানোর সিদ্ধান্ত নেন, তখন আপনাকে নতুন MediaSource তৈরি করতে হবে না। পরিবর্তে, PreloadManager-কে সেই উত্তরটি দিতে বলো যেটি সে আগেই তৈরি করেছে। আপনি MediaItem ব্যবহার করে Preload Manager থেকে MediaSource রিট্রিভ করতে পারবেন।
PreloadManager থেকে পাওয়া আইটেমটি শূন্য হলে, তার অর্থ হল mediaItem এখনও প্রিলোড করা হয়নি বা PreloadMamager-এ যোগ করা হয়নি, তাই আপনি সরাসরি mediaItem সেট করার বিকল্প বেছে নিন।
// When a media item is about to display on the screen
val mediaSource = preloadManager.getMediaSource(mediaItem)
if (mediaSource!= null) {
player.setMediaSource(mediaSource)
} else {
// If mediaSource is null, that mediaItem hasn't been added yet.
// So, send it directly to the player.
player.setMediaItem(mediaItem)
}
player.prepare()
// When the media item is displaying at the center of the screen
player.play()PreloadManager থেকে পাওয়া MediaSource প্রস্তুত করার মাধ্যমে, আপনি আগে থেকেই মেমরিতে থাকা ডেটা ব্যবহার করে, প্রি-লোডিং থেকে প্লেব্যাকে নির্বিঘ্নে ট্রানজিশন করতে পারবেন। এর ফলে স্টার্ট টাইম আরও দ্রুত হয়।
৩. UI-এর সাথে বর্তমান ইন্ডেক্স সিঙ্ক করে রাখা
আমাদের ফিড / তালিকা ডায়নামিক হতে পারে, তাই আপনার বর্তমান প্লেয়িং ইন্ডেক্স সম্পর্কে PreloadManager-কে জানানো গুরুত্বপূর্ণ যাতে এটি প্রি-লোডিংয়ের জন্য সর্বদা আপনার বর্তমান ইন্ডেক্সের সবচেয়ে কাছের আইটেমগুলিকে অগ্রাধিকার দিতে পারে।
preloadManager.setCurrentPlayingIndex(currentIndex) // Need to call invalidate() to update the priorities preloadManager.invalidate()
৪. কোনও আইটেম সরানো
ম্যানেজারকে আরও দক্ষ করে তুলতে, আপনাকে সেইসব আইটেম সরিয়ে দিতে হবে যেগুলি আর ট্র্যাক করার প্রয়োজন নেই, যেমন ব্যবহারকারীর বর্তমান লোকেশন থেকে অনেক দূরে থাকা আইটেম।
// When an item is too far from the current playing index preloadManager.remove(mediaItem)
আপনি যদি একসাথে সব আইটেম মুছে ফেলতে চান, তাহলে preloadManager.reset() নম্বরে কল করতে পারেন।
৫. ম্যানেজারকে রিলিজ করুন
PreloadManager-এর আর প্রয়োজন না হলে (যেমন, UI ধ্বংস হয়ে গেলে), এর রিসোর্স ফ্রি করতে আপনাকে এটি রিলিজ করতে হবে। আপনি যেখানে প্লেয়ারের রিসোর্স রিলিজ করছেন, এটি করার জন্য সেটিই ভাল জায়গা। প্লেয়ারের আগে ম্যানেজার রিলিজ করার সাজেশন দেওয়া হয়, কারণ আপনি আর প্রি-লোডিং করতে না চাইলে প্লেয়ার চালিয়ে যেতে পারেন।
// In your Activity's onDestroy() or Composable's onDispose preloadManager.release()
ডেমোর সময়
লাইভ অ্যাকশনে এটি চেক করে দেখুন 👍
নিচের ডেমোতে, আমরা ডানদিকে PreloadManager-এর প্রভাব দেখতে পাচ্ছি, যা দ্রুত লোড টাইম দেখায়, যেখানে বামদিকে বর্তমান অভিজ্ঞতা দেখানো হয়েছে। এছাড়াও, আপনি ডেমোর জন্য কোডের স্যাম্পেল দেখতে পারেন। (বোনাস: এটি প্রতিটি ভিডিওর জন্য স্টার্ট-আপ লেটেন্সিও দেখায়)
এরপর কী?
পার্ট ১ এখানেই শেষ হল! ডায়নামিক প্রি-লোডিং সিস্টেম তৈরি করার জন্য আপনার কাছে এখন টুল আছে। আপনি ExoPlayer-এ প্লেলিস্টের পরবর্তী আইটেম প্রি-লোড করতে PreloadConfiguration ব্যবহার করতে পারেন অথবা DefaultPreloadManager সেট-আপ করতে, ফ্লাইটে আইটেম যোগ করতে ও সরাতে, টার্গেট প্রি-লোড স্ট্যাটাস কনফিগার করতে এবং প্লেব্যাকের জন্য প্রি-লোড করা কন্টেন্ট সঠিকভাবে রিট্রিভ করতে পারেন।
পার্ট ২-এ, আমরা DefaultPreloadManager সম্পর্কে আরও জানব। আমরা কীভাবে প্রি-লোডিং ইভেন্ট শোনা যায় তা এক্সপ্লোর করব, মেমরি সংক্রান্ত সমস্যা এড়াতে স্লাইডিং উইন্ডো ব্যবহারের মতো সেরা পদ্ধতি নিয়ে আলোচনা করব এবং ExoPlayer ও DefaultPreloadManager-এর কাস্টম শেয়ার করা কম্পোনেন্টগুলি খুঁটিয়ে দেখব।
শেয়ার করার জন্য আপনার কোনও মতামত আছে? আপনার মতামত জানার জন্য আমরা উদগ্রীব।
সাথে থাকুন এবং আপনার অ্যাপ আরও দ্রুত করুন! 🚀
-
প্রোডাক্ট সম্পর্কিত খবরMedia3-এর মাধ্যমে মিডিয়া প্রি-লোডিং সংক্রান্ত আমাদের তিন-পার্টের সিরিজের দ্বিতীয় পর্বে স্বাগত। এই সিরিজটি আপনার Android অ্যাপে অত্যন্ত রেসপন্সিভ, কম লেটেন্সি সহ মিডিয়া অভিজ্ঞতা তৈরি করার প্রসেস সম্পর্কে আপনাকে গাইড করার জন্য ডিজাইন করা হয়েছে।
Mayuri Khinvasara Khabya • ৯ মিনিট রিডিং -
প্রোডাক্ট সম্পর্কিত খবরAndroid ডেভেলপার হিসেবে, অ্যাপ ডেভেলপমেন্টের জন্য আপনি যেসব এজেন্ট, LLM, টুল ও কমান্ড-লাইন ইন্টারফেস (CLI) ব্যবহার করেন, সেই ব্যাপারে আপনার কাছে অনেক বিকল্প আছে। আপনি যেভাবে তৈরি করতে চান না কেন, আমাদের লক্ষ্য হল আপনাকে সুন্দর, হাই-কোয়ালিটি Android অ্যাপ তৈরি করতে সাহায্য করা।
Simona Milanovic • ৪ মিনিট রিডিং টাইম -
প্রোডাক্ট সম্পর্কিত খবরGoogle Play-তে, আমরা ক্রমাগত আমাদের সাবস্ক্রিপশন প্ল্যাটফর্মের পরিধি বাড়াচ্ছি যাতে আপনি ব্যবসা বাড়াতে, নতুন বিজনেস মডেলের সাথে মানিয়ে নিতে এবং ব্যবহারকারীদের ঠিক যেখানে প্রয়োজন সেখানে তাদের চাহিদা পূরণ করতে পারেন।
Sheenam Mittal • ৪ মিনিট রিডিং টাইম
আপনার ইনবক্সে প্রতি সপ্তাহে Android ডেভেলপমেন্ট সংক্রান্ত লেটেস্ট ইনসাইট পান।