后臺服務(wù)以及電量監(jiān)控的最佳實(shí)踐

原文地址

創(chuàng)建一個后臺服務(wù):

IntentService類提供一個直接的結(jié)構(gòu)對于一個單獨(dú)后臺線程執(zhí)行操作。這就允許它處理長時間的操作而不影響用戶交互接口。并且,一個IntentService不被多數(shù)用戶接口循環(huán)事件影響,所以持續(xù)運(yùn)行的環(huán)境中應(yīng)該關(guān)掉AsyncTask。

一個IntentService有如下限制:
  • 不能直接和用戶接口交互。為了把它的結(jié)果交給UI,你應(yīng)該把它們發(fā)送給一個Activity。
  • 工作請求順序的執(zhí)行。如果一個操作在IntentService中執(zhí)行,并且你發(fā)送另一個請求,請求一直等待上一個操作執(zhí)行完。
  • 在IntentService中執(zhí)行的操作能夠被打斷。

然而,在大多數(shù)情況下,IntentService是首選的方式對于簡單的后臺操作。

這節(jié)課像你展示如何創(chuàng)建你自己的IntentService的子類。課程也像你展示了如何創(chuàng)建一個需要的回調(diào)方法onHandleIntent().最后,課程描述了如何在manifestfile定義IntentService。

創(chuàng)建一個IntentService

為了創(chuàng)建一個IntentService組件,定義一個繼承IntentService的類,并且重寫onHandleIntent()。如下:

public class RSSPullService extends IntentService {
    @Override
    protected void onHandleIntent(Intent workIntent) {
        // Gets data from the incoming Intent
        String dataString = workIntent.getDataString();
        ...
        // Do work here, based on the contents of dataString
        ...
    }
}

注意其他的常規(guī)Service組件的回調(diào)方法,例如onStartCommand()自動被IntentService調(diào)用,你應(yīng)該避免重寫這些回調(diào)。

在Manifest中定義IntentService

<application
        android:icon="@drawable/icon"
        android:label="@string/app_name">
        ...
        <!--
            Because android:exported is set to "false",
            the service is only available to this app.
        -->
        <service
            android:name=".RSSPullService"
            android:exported="false"/>
        ...
    <application/>

注意 <service> 元素不包含intent filter。Activity使用確切的Intent發(fā)送請求到service,所有不需要過濾器。這也意味著在同一應(yīng)用或者有相同用戶Id的應(yīng)用可以訪問這個服務(wù)。

發(fā)送工作請求到后臺服務(wù)

創(chuàng)建和發(fā)送一個工作請求到一個IntentService

為了創(chuàng)建一個工作請求并且發(fā)送它到一個IntentService,創(chuàng)建一個明確的Intent,并且為它添加請求數(shù)據(jù),并且通過調(diào)用startService()發(fā)送給IntentService。

  1. 創(chuàng)建一個新的、確切的Intent為IntentService調(diào)用RSSPullService
/*
 * Creates a new Intent to start the RSSPullService
 * IntentService. Passes a URI in the
 * Intent's "data" field.
 */
mServiceIntent = new Intent(getActivity(), RSSPullService.class);
mServiceIntent.setData(Uri.parse(dataUrl));
  1. 調(diào)用startService()
// Starts the IntentService
getActivity().startService(mServiceIntent);

注意你可以發(fā)送工作請求從任何地方,Activity、Fragment。例如,如果你需要先獲取用戶輸入,你可以發(fā)送請求從一個涉及到按鍵點(diǎn)擊或者簡單手勢的回調(diào)當(dāng)中。
一旦你調(diào)用了startService(),IntentService執(zhí)行onHandleIntent()方法定義的工作,接著停止它自己。

匯報(bào)工作狀態(tài):

從IntentService中匯報(bào)工作狀態(tài)

為了從IntentService中發(fā)送工作請求的狀態(tài)到其他組件,首先創(chuàng)建一個Intent。作為可選項(xiàng),你可以增加action和data Uri到這個Intent。
下一步,發(fā)送Intent通過調(diào)用 LocalBroadcastManager.sendBroadcast().這發(fā)送Intent到任何你應(yīng)用中注冊接收它的組件。調(diào)用getInstance()可以拿到本地廣播的實(shí)例。
例如:

public final class Constants {
    ...
    // Defines a custom Intent action
    public static final String BROADCAST_ACTION =
        "com.example.android.threadsample.BROADCAST";
    ...
    // Defines the key for the status "extra" in an Intent
    public static final String EXTENDED_DATA_STATUS =
        "com.example.android.threadsample.STATUS";
    ...
}
public class RSSPullService extends IntentService {
...
    /*
     * Creates a new Intent containing a Uri object
     * BROADCAST_ACTION is a custom Intent action
     */
    Intent localIntent =
            new Intent(Constants.BROADCAST_ACTION)
            // Puts the status into the Intent
            .putExtra(Constants.EXTENDED_DATA_STATUS, status);
    // Broadcasts the Intent to receivers in this app.
    LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
...
}

下一步是在組件中處理到來的廣播Intent對象。
接收狀態(tài)從一個IntentService
例如:

// Broadcast receiver for receiving status updates from the IntentService
private class DownloadStateReceiver extends BroadcastReceiver
{
    // Prevents instantiation
    private DownloadStateReceiver() {
    }
    // Called when the BroadcastReceiver gets an Intent it's registered to receive
    @Override
    public void onReceive(Context context, Intent intent) {
...
        /*
         * Handle Intents here.
         */
...
    }
}

一旦你已經(jīng)定義廣播接收器,你能夠定義為它定義過濾器去匹配特定的actions,categories和data。如下展示如何定義一個過濾器:

// Class that displays photos
public class DisplayActivity extends FragmentActivity {
    ...
    public void onCreate(Bundle stateBundle) {
        ...
        super.onCreate(stateBundle);
        ...
        // The filter's action is BROADCAST_ACTION
        IntentFilter statusIntentFilter = new IntentFilter(
                Constants.BROADCAST_ACTION);

        // Adds a data filter for the HTTP scheme
        statusIntentFilter.addDataScheme("http");
        ...

為了注冊廣播接收器和過濾器,拿到本地廣播的實(shí)例并且調(diào)用注冊接收器的方法。如下所示:

  // Instantiates a new DownloadStateReceiver
        DownloadStateReceiver mDownloadStateReceiver =
                new DownloadStateReceiver();
        // Registers the DownloadStateReceiver and its intent filters
        LocalBroadcastManager.getInstance(this).registerReceiver(
                mDownloadStateReceiver,
                statusIntentFilter);
        ...

一個單獨(dú)的廣播接收器能夠處理超過一種類型的廣播對象。如下:

  /*
         * Instantiates a new action filter.
         * No data filter is needed.
         */
        statusIntentFilter = new IntentFilter(Constants.ACTION_ZOOM_IMAGE);
        ...
        // Registers the receiver with the new filter
        LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
                mDownloadStateReceiver,
                statusIntentFilter);

發(fā)送一個廣播Intent不會start或者resume actvitiy。Activity的BroadcastReciver接收和處理Intent對象即使當(dāng)你的應(yīng)用在后臺,但是不強(qiáng)制你的應(yīng)用到前臺。如果你想通知用戶關(guān)于發(fā)生在后臺的事件當(dāng)你的應(yīng)用不可見的時候,使用Notification。永遠(yuǎn)不要start一個Activity去回應(yīng)到來的廣播Intent

管理設(shè)備的喚醒狀態(tài)

當(dāng)你的設(shè)備空閑的時候,它先變昏暗,接著關(guān)閉屏幕,最終關(guān)閉CPU。這防止電量被過早榨干。然而有時你的應(yīng)用可能需要一個不同的表現(xiàn)。
游戲應(yīng)用或者電影應(yīng)用可能需要保持屏幕亮著。
其他應(yīng)用可能不需要保持屏幕亮著,但是他們需要CPU持續(xù)運(yùn)行直到關(guān)鍵的操作完成。
這節(jié)描述如何保持一個設(shè)備喚醒當(dāng)需要的時候而不榨干它的電量

保持設(shè)備喚醒

某些應(yīng)用需要保持屏幕開啟,例如游戲或者電影應(yīng)用。最好的方式是使用 FLAG_KEEP_SCREEN_ON 在你的應(yīng)用當(dāng)中(只在activity當(dāng)中,不要在一個service或者其他應(yīng)用組件中)。例如:

public class MainActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
  }

這樣做的好處是不像wake locks(詳見Keep the CPU On),它不需要請求特殊的權(quán)限,平臺妥善的管理用戶在不同應(yīng)用之間的切換,而你的應(yīng)用不需要擔(dān)憂釋放不需要的資源。
另一種方式是在你應(yīng)用的layout XML文件中,通過使用 android:keepScreenOn屬性:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:keepScreenOn="true">
    ...
</RelativeLayout>

注意:你不需要清掉FlAG_KEEP_SCREEN_ON標(biāo)簽除非你不再希望屏幕保持亮在你運(yùn)行的應(yīng)用當(dāng)中(例如,如果你希望屏幕一段確切的時間不活動熄滅)。Window manager確保正確的事情發(fā)生當(dāng)應(yīng)用到后臺或者返回前臺。但是你想明確的清楚標(biāo)簽并且允許屏幕再次關(guān)閉,使用clearFlags():
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)

保持CPU工作:

如果你需要保持CPU工作為了完成某些任務(wù)在設(shè)備睡眠之前,你可以使用PowerManager系統(tǒng)服務(wù)調(diào)用wake locaks,Wake locks允許你的應(yīng)用控制設(shè)備的電池狀態(tài)。
創(chuàng)建并且持有wake locks會有劇烈的影響在設(shè)備電池的壽命上。因此你應(yīng)該使用wake locks僅當(dāng)嚴(yán)格需要并且保持盡可能短的時間。例如,你不應(yīng)該使用wake lock 在一個activity中。
一個合法的情況是使用wake lock 可能是后臺服務(wù)需要獲得wake lock讓cpu 持續(xù)工作當(dāng)屏幕關(guān)閉的時候,而且,這種實(shí)踐應(yīng)該最小化由于電池的壽命。
使用Wake lock,第一步添加wake lock的權(quán)限到你應(yīng)用的manifest文件中:

<uses-permission android:name="android.permission.WAKE_LOCK" />

如果你的應(yīng)用包含一個使用service做一些工作廣播接收器,你可以管理你的wake lock通過一個WakefulBroadcastReceiver.如 Using a WakefulBroadcastReceiver 描述的,這是首選的方式。如果你的應(yīng)用不跟從這個規(guī)則,你可以這樣直接使用:

PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
        "MyWakelockTag");
wakeLock.acquire();

調(diào)用wakelock.release()釋放wake lock。盡快釋放wake lock 是非常重要的,避免它榨干你的電量。

使用WakefulBroadcastReciver

使用broadcast reciver和service管理后臺任務(wù)的生命周期。
WakefulBroadcastReceiver是一種特殊類型的廣播接收器,為你的app關(guān)注創(chuàng)建和管理PARTIAL_WAKE_LOCK。WakefulBroadcastReceiver把工作傳到Service(典型的IntentService),當(dāng)確保設(shè)備不會在事務(wù)中入睡。如果你不持有一個wake lock當(dāng)過渡工作到一個服務(wù)中,你實(shí)際上是允許設(shè)備休眠在工作完成之前。應(yīng)用的網(wǎng)絡(luò)結(jié)果可能沒有完成工作直到未來一些任意的點(diǎn),這并不是你想要的。
使用WakefulBroadcastReceiver是添加它到你的manifest中,像其他廣播接收器那樣:

<receiver android:name=".MyWakefulReceiver"></receiver>

如下代碼start MyIntentService通過方法startWakefulService()。這個方法與startService()相等,WakefulBroadcastReceiver持有一個wake lock當(dāng)serivce開始的時候。startWakefulService()傳入的Intent中持有一個額外的wake lock標(biāo)識。

public class MyWakefulReceiver extends WakefulBroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        // Start the service, keeping the device awake while the service is
        // launching. This is the Intent to deliver to the service.
        Intent service = new Intent(context, MyIntentService.class);
        startWakefulService(context, service);
    }
}

當(dāng)Service完成后,它調(diào)用 MyWakefulReceiver.completeWakefulIntent()去釋放wake lock。completeWakefulIntent()方法有像它參數(shù)一樣的從 WakefulBroadcastReceiver被傳入的intent

public class MyIntentService extends IntentService {
    public static final int NOTIFICATION_ID = 1;
    private NotificationManager mNotificationManager;
    NotificationCompat.Builder builder;
    public MyIntentService() {
        super("MyIntentService");
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        Bundle extras = intent.getExtras();
        // Do the work that requires your app to keep the CPU running.
        // ...
        // Release the wake lock provided by the WakefulBroadcastReceiver.
        MyWakefulReceiver.completeWakefulIntent(intent);
    }

監(jiān)控電池電量和充電狀態(tài)

如果您要通過改變后臺更新的頻率來減少這些更新對電池壽命的影響,最好先從檢查當(dāng)前電池電量和充電狀態(tài)入手。
執(zhí)行中的應(yīng)用更新對電池壽命的影響取決于設(shè)備的電池電量和充電狀態(tài)。 設(shè)備通過交流電源充電時執(zhí)行更新的影響可以忽略不計(jì),因此在大多數(shù)情況下,只要設(shè)備連接了壁式充電器,您就可以將更新頻率提高到最高水平。 相反,如果設(shè)備正在放電,降低更新頻率有助于延長電池壽命。
同理,您也可以檢查電池充電電量,并在電池電量近乎耗盡時降低更新頻率,甚至停止更新
確定當(dāng)前充電狀態(tài)
首先,確定當(dāng)前充電狀態(tài)。BatteryManager 在一個包含充電狀態(tài)的粘性 Intent 中廣播所有電池和充電詳情。
由于它是一種粘性 Intent,因此您并不需要如下一代碼段中所示的那樣通過簡單地調(diào)用 registerReceiver傳入 null 作為接收器來注冊BroadcastReceiver,便可返回當(dāng)前電池狀態(tài) Intent。您可以在此處傳入實(shí)際 BroadcastReceiver 對象,但由于稍后我們將會處理更新,因此并不需要這樣做。

IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = context.registerReceiver(null, ifilter);

您可以提取當(dāng)前充電狀態(tài),并且如果設(shè)備正在充電,則還可以提取設(shè)備是通過 USB 還是交流充電器進(jìn)行充電。

// Are we charging / charged?
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
                     status == BatteryManager.BATTERY_STATUS_FULL;

// How are we charging?
int chargePlug = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
boolean usbCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
boolean acCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_AC;

通常,如果設(shè)備連接了交流充電器,您應(yīng)該最大限度提高后臺更新的頻率;而如果設(shè)備是通過 USB 充電,則應(yīng)降低更新頻率,如果電池正在放電,則應(yīng)進(jìn)一步降低更新頻率。
監(jiān)控充電狀態(tài)變化
就像設(shè)備可以輕松地插入電源,充電狀態(tài)也很容易發(fā)生變化,因此必須監(jiān)控充電狀態(tài)的變化并相應(yīng)地改變更新頻率。
每當(dāng)設(shè)備連接或斷開電源時,BatteryManager 都會廣播一個操作。 必須接收這些事件,即便您的應(yīng)用并未運(yùn)行 — 尤其要考慮到這些事件可能會影響您啟用應(yīng)用以便發(fā)起后臺更新的頻率 — 因此您應(yīng)該在清單文件中注冊一個 BroadcastReceiver,通過在一個 Intent 過濾器內(nèi)定義ACTION_POWER_CONNECTED 和 ACTION_POWER_DISCONNECTED 來同時偵聽這兩種事件。

<receiver android:name=".PowerConnectionReceiver">
  <intent-filter>
    <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
    <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
  </intent-filter>
</receiver>

在關(guān)聯(lián)的 BroadcastReceiver 實(shí)現(xiàn)內(nèi),您可以按上一步所述提取當(dāng)前充電狀態(tài)和方法。

public class PowerConnectionReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
        boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
                            status == BatteryManager.BATTERY_STATUS_FULL;

        int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
        boolean usbCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
        boolean acCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_AC;
    }
}

確定當(dāng)前電池電量

在某些情況下,確定當(dāng)前電池電量也很有用處。您可以選擇在電池電量低于某一水平時降低后臺更新的頻率。
您可以如以下所示,通過從電池狀態(tài) Intent 提取當(dāng)前電池電量和刻度來了解當(dāng)前電池電量:

int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);

float batteryPct = level / (float)scale;

監(jiān)控顯著的電池電量變化

您無法輕松地持續(xù)監(jiān)控電池狀態(tài),您也不必如此。
一般而言,持續(xù)監(jiān)控電池電量對電池的影響大于對應(yīng)用正常行為的影響,因此最好只監(jiān)控顯著的電池電量變化—特別是在設(shè)備進(jìn)入或退出電量不足狀態(tài)時。
以下清單文件代碼段摘自某個廣播接收器內(nèi)的 Intent 過濾器元素。 通過偵聽 ACTION_BATTERY_LOW 和 ACTION_BATTERY_OKAY,每當(dāng)設(shè)備電池電量不足或退出不足狀態(tài)時,便會觸發(fā)該接收器。

<receiver android:name=".BatteryLevelReceiver">
<intent-filter>
  <action android:name="android.intent.action.ACTION_BATTERY_LOW"/>
  <action android:name="android.intent.action.ACTION_BATTERY_OKAY"/>
  </intent-filter>
</receiver>

一般而言,最好在電池電量極低時停用所有后臺更新。 如果手機(jī)在您利用數(shù)據(jù)前就已自行關(guān)機(jī),數(shù)據(jù)的新鮮度則無關(guān)緊要。
在許多情況下,為設(shè)備充電與將設(shè)備插入基座是同一操作。下一節(jié)課為您介紹如何確定當(dāng)前基座狀態(tài)以及如何監(jiān)控設(shè)備插接狀態(tài)的變化。
確定和監(jiān)控插接狀態(tài)和基座類型
Android 設(shè)備可插接到幾個不同種類的基座,其中包括汽車或家用基座以及數(shù)字和模擬基座。 插接狀態(tài)通常與充電狀態(tài)聯(lián)系密切,因?yàn)樵S多基座都為插接的設(shè)備供電。
手機(jī)插接狀態(tài)對更新頻率的影響取決于您的應(yīng)用。您可以選擇在手機(jī)插入桌面基座時提高體育中心應(yīng)用的更新頻率,或者在設(shè)備插入車載手機(jī)座時完全停用更新。 相反,如果您的后臺服務(wù)正在更新交通狀況,則您可以選擇在已插接車載基座的情況下最大限度提高更新頻率。
插接狀態(tài)也以粘性 Intent 形式廣播,以便您查詢設(shè)備是否已插接以及已插接情況下的插接類型。

確定當(dāng)前插接狀態(tài)

插接狀態(tài)詳情以 extra 形式包含在 ACTION_DOCK_EVENT 操作的粘性廣播中。由于它是粘性廣播,因此您無需注冊 BroadcastReceiver。如下一段代碼中所示,您只需調(diào)用 registerReceiver(),將 null 作為廣播接收器傳入。

IntentFilter ifilter = new IntentFilter(Intent.ACTION_DOCK_EVENT);
Intent dockStatus = context.registerReceiver(null, ifilter);
您可以從 EXTRA_DOCK_STATE extra 中提取當(dāng)前插接狀態(tài):
int dockState = battery.getIntExtra(EXTRA_DOCK_STATE, -1);
boolean isDocked = dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;

確定當(dāng)前基座類型


如果設(shè)備已插接,其插接的基座可能為以下四種不同類型之一:
? 車載基座
? 桌面基座
? 低端(模擬)桌面基座
? 高端(數(shù)字)桌面基座
請注意,后兩種類型從 Android 的 API 級別 11 才開始引入,因此如果您只關(guān)注基座類型而不關(guān)心其具體為數(shù)字還是模擬形式,則最好檢查所有三種類型:

boolean isCar = dockState == EXTRA_DOCK_STATE_CAR;
boolean isDesk = dockState == EXTRA_DOCK_STATE_DESK ||
                 dockState == EXTRA_DOCK_STATE_LE_DESK ||
                 dockState == EXTRA_DOCK_STATE_HE_DESK;

監(jiān)控插接狀態(tài)或基座類型變化


每當(dāng)設(shè)備插入或拔出基座時,都會廣播 ACTION_DOCK_EVENT 操作。如需監(jiān)控設(shè)備的插接狀態(tài)變化,只需如下面的代碼段所示,在您的應(yīng)用清單文件中注冊一個廣播接收器:
<action android:name="android.intent.action.ACTION_DOCK_EVENT"/>
您可以使用上一步中介紹的相同技巧提取接收器實(shí)現(xiàn)內(nèi)的基座類型和插接狀態(tài)。
確定和監(jiān)控連接狀態(tài)
重復(fù)鬧鈴和后臺服務(wù)的一些最常見用途是安排定期從互聯(lián)網(wǎng)資源、緩存數(shù)據(jù)更新應(yīng)用數(shù)據(jù),或者執(zhí)行長時間下載。但如果您未連入互聯(lián)網(wǎng),或者因連接速度過慢而無法完成下載,何苦要喚醒設(shè)備來安排更新呢?
您可以利用 ConnectivityManager 來檢查是否已實(shí)際連入互聯(lián)網(wǎng)以及已連入情況下的連接類型。
確定您是否連入了互聯(lián)網(wǎng)


如果您未連入互聯(lián)網(wǎng),則無需安排基于互聯(lián)網(wǎng)資源的更新。 下面這段代碼展示了如何利用 ConnectivityManager 查詢活動網(wǎng)絡(luò)并確定其是否連入了互聯(lián)網(wǎng)。

ConnectivityManager cm =
        (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);

NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null &&
                      activeNetwork.isConnectedOrConnecting();

確定您的互聯(lián)網(wǎng)連接類型


還可以確定當(dāng)前可用的互聯(lián)網(wǎng)連接類型。
設(shè)備連接可由移動數(shù)據(jù)、WiMAX、Wi-Fi 和以太網(wǎng)連接提供。如下所示,您可以通過查詢活動網(wǎng)絡(luò)的類型,根據(jù)可用帶寬改變更新頻率。

boolean isWiFi = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI;

移動數(shù)據(jù)成本往往遠(yuǎn)高于 Wi-Fi,因此在大多數(shù)情況下,使用移動連接時應(yīng)降低您的應(yīng)用的更新頻率。 同理,您應(yīng)在接入 Wi-Fi 后再進(jìn)行大數(shù)據(jù)量下載。
停用更新后,您必須偵聽連接變化,以便在建立互聯(lián)網(wǎng)連接后立即恢復(fù)更新。
監(jiān)控連接變化


每當(dāng)連接詳情發(fā)生變化時,ConnectivityManager 便會廣播 CONNECTIVITY_ACTION ("android.net.conn.CONNECTIVITY_CHANGE") 操作。您可以在清單文件中注冊一個廣播接收器,以便偵聽這些變化和相應(yīng)地恢復(fù)(或暫停)后臺更新。

<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>

設(shè)備的連接變化可能非常頻繁—您每次在移動數(shù)據(jù)與 Wi-Fi 之間切換時都會觸發(fā)該廣播。 因此,最好只在您之前暫停過更新或下載時監(jiān)控該廣播,以便恢復(fù)這些更新或下載。通常,只要在開始更新前檢查互聯(lián)網(wǎng)連接即已足夠,如果沒有任何連接,則再暫停其他更新直至連接恢復(fù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容