নিয়মিত আপডেটের প্রভাব কমিয়ে দিন

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

নিয়মিত আপডেটের তিনটি সাধারণ প্রকার রয়েছে:

  • ব্যবহারকারীর সূচনা. কিছু ব্যবহারকারীর আচরণের উপর ভিত্তি করে একটি আপডেট করা, যেমন একটি পুল-টু-রিফ্রেশ অঙ্গভঙ্গি।
  • অ্যাপ-প্রবর্তিত। একটি পুনরাবৃত্ত ভিত্তিতে একটি আপডেট সঞ্চালন.
  • সার্ভার-সূচনা. একটি সার্ভার থেকে একটি বিজ্ঞপ্তির প্রতিক্রিয়া হিসাবে একটি আপডেট সম্পাদন করা।

এই বিষয়গুলি এইগুলির প্রতিটির দিকে নজর দেয় এবং ব্যাটারি ড্রেন কমাতে অপ্টিমাইজ করা যেতে পারে এমন অতিরিক্ত উপায়গুলি নিয়ে আলোচনা করে৷

ব্যবহারকারীর সূচনা অনুরোধ অপ্টিমাইজ করুন

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

থ্রোটল ব্যবহারকারীর অনুরোধ

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

একটি ক্যাশে ব্যবহার করুন

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

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

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

কম ঘন ঘন আরও ডেটা ডাউনলোড করতে বেশি ব্যান্ডউইথ ব্যবহার করুন

ওয়্যারলেস রেডিওর মাধ্যমে সংযুক্ত করা হলে, উচ্চ ব্যান্ডউইথ সাধারণত উচ্চ ব্যাটারি খরচের মূল্যে আসে, যার অর্থ হল 5G সাধারণত LTE থেকে বেশি শক্তি খরচ করে, যা 3G-এর থেকেও বেশি ব্যয়বহুল।

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

একই সময়ে, উচ্চ ব্যান্ডউইথ মানে আপনি একই সময়ে আরও ডেটা ডাউনলোড করে আরও আক্রমণাত্মকভাবে প্রিফেচ করতে পারেন। সম্ভবত কম স্বজ্ঞাতভাবে, কারণ টেল-টাইম ব্যাটারির খরচ তুলনামূলকভাবে বেশি, আপডেটের ফ্রিকোয়েন্সি কমাতে প্রতিটি স্থানান্তর সেশনের সময় রেডিওটিকে দীর্ঘ সময়ের জন্য সক্রিয় রাখাও আরও কার্যকর।

উদাহরণস্বরূপ, যদি একটি LTE রেডিওর ব্যান্ডউইথ দ্বিগুণ হয় এবং 3G-এর শক্তি খরচ দ্বিগুণ হয়, তাহলে প্রতিটি সেশনে আপনার চারগুণ বেশি ডেটা ডাউনলোড করা উচিত—অথবা সম্ভাব্য 10MB-এর মতো। এত বেশি ডেটা ডাউনলোড করার সময়, উপলব্ধ স্থানীয় সঞ্চয়স্থানে আপনার প্রিফেচিংয়ের প্রভাব বিবেচনা করা এবং আপনার প্রিফেচ ক্যাশে নিয়মিতভাবে ফ্লাশ করা গুরুত্বপূর্ণ।

আপনি ডিফল্ট নেটওয়ার্কের জন্য একজন শ্রোতা নিবন্ধন করতে ConnectivityManager ব্যবহার করতে পারেন এবং বর্তমান ডিভাইস সংযোগের ধরন নির্ধারণ করতে একটি PhoneStateListener নিবন্ধন করতে TelephonyManager ব্যবহার করতে পারেন। সংযোগের ধরন জানা হয়ে গেলে, আপনি সেই অনুযায়ী আপনার প্রিফেচিং রুটিনগুলি সংশোধন করতে পারেন:

কোটলিন

val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val tm = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager

private var hasWifi = false
private var hasCellular = false
private var cellModifier: Float = 1f

private val networkCallback = object : ConnectivityManager.NetworkCallback() {
    // Network capabilities have changed for the network
    override fun onCapabilitiesChanged(
            network: Network,
            networkCapabilities: NetworkCapabilities
    ) {
        super.onCapabilitiesChanged(network, networkCapabilities)
        hasCellular = networkCapabilities
    .hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
        hasWifi = networkCapabilities
    .hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
    }
}

private val phoneStateListener = object : PhoneStateListener() {
override fun onPreciseDataConnectionStateChanged(
    dataConnectionState: PreciseDataConnectionState
) {
  cellModifier = when (dataConnectionState.networkType) {
      TelephonyManager.NETWORK_TYPE_LTE or TelephonyManager.NETWORK_TYPE_HSPAP -> 4f
      TelephonyManager.NETWORK_TYPE_EDGE or TelephonyManager.NETWORK_TYPE_GPRS -> 1/2f
      else -> 1f

  }
}

private class NetworkState {
    private var defaultNetwork: Network? = null
    private var defaultCapabilities: NetworkCapabilities? = null
    fun setDefaultNetwork(network: Network?, caps: NetworkCapabilities?) = synchronized(this) {
        defaultNetwork = network
        defaultCapabilities = caps
    }
    val isDefaultNetworkWifi
        get() = synchronized(this) {
            defaultCapabilities?.hasTransport(TRANSPORT_WIFI) ?: false
        }
    val isDefaultNetworkCellular
        get() = synchronized(this) {
            defaultCapabilities?.hasTransport(TRANSPORT_CELLULAR) ?: false
        }
    val isDefaultNetworkUnmetered
        get() = synchronized(this) {
            defaultCapabilities?.hasCapability(NET_CAPABILITY_NOT_METERED) ?: false
        }
    var cellNetworkType: Int = TelephonyManager.NETWORK_TYPE_UNKNOWN
        get() = synchronized(this) { field }
        set(t) = synchronized(this) { field = t }
    private val cellModifier: Float
        get() = synchronized(this) {
            when (cellNetworkType) {
                TelephonyManager.NETWORK_TYPE_LTE or TelephonyManager.NETWORK_TYPE_HSPAP -> 4f
                TelephonyManager.NETWORK_TYPE_EDGE or TelephonyManager.NETWORK_TYPE_GPRS -> 1 / 2f
                else -> 1f
            }
        }
    val prefetchCacheSize: Int
        get() = when {
            isDefaultNetworkWifi -> MAX_PREFETCH_CACHE
            isDefaultNetworkCellular -> (DEFAULT_PREFETCH_CACHE * cellModifier).toInt()
            else -> DEFAULT_PREFETCH_CACHE
        }
}
private val networkState = NetworkState()
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
    // Network capabilities have changed for the network
    override fun onCapabilitiesChanged(
            network: Network,
            networkCapabilities: NetworkCapabilities
    ) {
        networkState.setDefaultNetwork(network, networkCapabilities)
    }

    override fun onLost(network: Network?) {
        networkState.setDefaultNetwork(null, null)
    }
}

private val telephonyCallback = object : TelephonyCallback(), TelephonyCallback.PreciseDataConnectionStateListener {
    override fun onPreciseDataConnectionStateChanged(dataConnectionState: PreciseDataConnectionState) {
        networkState.cellNetworkType = dataConnectionState.networkType
    }
}

connectivityManager.registerDefaultNetworkCallback(networkCallback)
telephonyManager.registerTelephonyCallback(telephonyCallback)


private val prefetchCacheSize: Int
get() {
    return when {
        hasWifi -> MAX_PREFETCH_CACHE
        hasCellular -> (DEFAULT_PREFETCH_CACHE * cellModifier).toInt()
        else -> DEFAULT_PREFETCH_CACHE
    }
}

}

জাভা

ConnectivityManager cm =
 (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
TelephonyManager tm =
  (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

private boolean hasWifi = false;
private boolean hasCellular = false;
private float cellModifier = 1f;

private ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
@Override
public void onCapabilitiesChanged(
    @NonNull Network network,
    @NonNull NetworkCapabilities networkCapabilities
) {
        super.onCapabilitiesChanged(network, networkCapabilities);
        hasCellular = networkCapabilities
    .hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
        hasWifi = networkCapabilities
    .hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
}
};

private PhoneStateListener phoneStateListener = new PhoneStateListener() {
@Override
public void onPreciseDataConnectionStateChanged(
    @NonNull PreciseDataConnectionState dataConnectionState
    ) {
    switch (dataConnectionState.getNetworkType()) {
        case (TelephonyManager.NETWORK_TYPE_LTE |
            TelephonyManager.NETWORK_TYPE_HSPAP):
            cellModifier = 4;
            Break;
        case (TelephonyManager.NETWORK_TYPE_EDGE |
            TelephonyManager.NETWORK_TYPE_GPRS):
            cellModifier = 1/2.0f;
            Break;
        default:
            cellModifier = 1;
            Break;
    }
}
};

cm.registerDefaultNetworkCallback(networkCallback);
tm.listen(
phoneStateListener,
PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE
);

public int getPrefetchCacheSize() {
if (hasWifi) {
    return MAX_PREFETCH_SIZE;
}
if (hasCellular) {
    return (int) (DEFAULT_PREFETCH_SIZE * cellModifier);
    }
return DEFAULT_PREFETCH_SIZE;
}

অ্যাপ-সূচিত অনুরোধগুলি অপ্টিমাইজ করুন

অ্যাপ-শুরু করা অনুরোধগুলি সাধারণত একটি সময়সূচীতে ঘটে, যেমন একটি অ্যাপ যা একটি ব্যাকএন্ড পরিষেবাতে লগ বা বিশ্লেষণ পাঠায়। অ্যাপ-ইনিশিয়েট করা অনুরোধগুলির সাথে কাজ করার সময়, সেই অনুরোধগুলির অগ্রাধিকার বিবেচনা করুন, সেগুলি একসাথে ব্যাচ করা যায় কিনা এবং ডিভাইসটি চার্জ না হওয়া পর্যন্ত বা মিটারবিহীন নেটওয়ার্কের সাথে সংযুক্ত না হওয়া পর্যন্ত সেগুলি পিছিয়ে দেওয়া যেতে পারে কিনা৷ এই অনুরোধগুলি সাবধানে সময়সূচীর সাথে এবং WorkManager- এর মতো লাইব্রেরি ব্যবহার করে অপ্টিমাইজ করা যেতে পারে।

ব্যাচ নেটওয়ার্ক অনুরোধ

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

WorkManager ব্যবহার করুন

আপনি একটি দক্ষ সময়সূচীতে কাজ সম্পাদন করতে WorkManager লাইব্রেরি ব্যবহার করতে পারেন যা বিবেচনা করে যে নির্দিষ্ট শর্তগুলি পূরণ করা হয়েছে কিনা, যেমন নেটওয়ার্ক উপলব্ধতা এবং পাওয়ার স্থিতি। উদাহরণস্বরূপ, ধরুন আপনার কাছে DownloadHeadlinesWorker নামে একটি Worker সাবক্লাস রয়েছে যা সর্বশেষ সংবাদ শিরোনামগুলি পুনরুদ্ধার করে৷ এই কর্মীকে প্রতি ঘন্টায় চালানোর জন্য নির্ধারিত করা যেতে পারে, যদি ডিভাইসটি একটি মিটারবিহীন নেটওয়ার্কের সাথে সংযুক্ত থাকে এবং ডিভাইসের ব্যাটারি কম না হয়, যদি ডেটা পুনরুদ্ধার করতে কোনো সমস্যা হয় তবে একটি কাস্টম পুনরায় চেষ্টা করার কৌশল সহ, নীচে দেখানো হয়েছে:

কোটলিন

val constraints = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.UNMETERED)
    .setRequiresBatteryNotLow(true)
    .build()
val request =
    PeriodicWorkRequestBuilder<DownloadHeadlinesWorker>(1, TimeUnit.HOURS)
        .setConstraints(constraints)
        .setBackoffCriteria(BackoffPolicy.LINEAR, 1L, TimeUnit.MINUTES)
        .build()
WorkManager.getInstance(context).enqueue(request)

জাভা

Constraints constraints = new Constraints.Builder()
        .setRequiredNetworkType(NetworkType.UNMETERED)
        .setRequiresBatteryNotLow(true)
        .build();
WorkRequest request = new PeriodicWorkRequest.Builder(DownloadHeadlinesWorker.class, 1, TimeUnit.HOURS)
        .setBackoffCriteria(BackoffPolicy.LINEAR, 1L, TimeUnit.MINUTES)
        .build();
WorkManager.getInstance(this).enqueue(request);

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

সার্ভার দ্বারা শুরু করা অনুরোধগুলি অপ্টিমাইজ করুন

সার্ভার-প্রবর্তিত অনুরোধগুলি সাধারণত একটি সার্ভার থেকে একটি বিজ্ঞপ্তির প্রতিক্রিয়া হিসাবে ঘটে। উদাহরণস্বরূপ, সাম্প্রতিক সংবাদ নিবন্ধগুলি পড়ার জন্য ব্যবহৃত একটি অ্যাপ ব্যবহারকারীর ব্যক্তিগতকরণ পছন্দগুলির সাথে মানানসই নিবন্ধগুলির একটি নতুন ব্যাচ সম্পর্কে একটি বিজ্ঞপ্তি পেতে পারে, যা এটি ডাউনলোড করে।

Firebase ক্লাউড মেসেজিং এর মাধ্যমে সার্ভার আপডেট পাঠান

ফায়ারবেস ক্লাউড মেসেজিং (FCM) হল একটি লাইটওয়েট মেকানিজম যা সার্ভার থেকে একটি নির্দিষ্ট অ্যাপ ইনস্ট্যান্সে ডেটা প্রেরণ করতে ব্যবহৃত হয়। FCM ব্যবহার করে, আপনার সার্ভার একটি নির্দিষ্ট ডিভাইসে চলমান আপনার অ্যাপকে বিজ্ঞপ্তি দিতে পারে যে এটির জন্য নতুন ডেটা উপলব্ধ রয়েছে।

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

FCM একটি স্থায়ী TCP/IP সংযোগ ব্যবহার করে প্রয়োগ করা হয়। এটি ক্রমাগত সংযোগের সংখ্যা কমিয়ে দেয় এবং প্ল্যাটফর্মটিকে ব্যান্ডউইথ অপ্টিমাইজ করতে এবং ব্যাটারি লাইফের সাথে সম্পর্কিত প্রভাব কমিয়ে আনতে দেয়।