日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

iOS之性能优化·优化App的电池耗电量

發(fā)布時間:2024/5/21 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 iOS之性能优化·优化App的电池耗电量 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、前言

  • 在現(xiàn)如今的開發(fā)中,電量消耗是一個應(yīng)用運行效果的一個重要的衡量標準,尤其是直播和運動應(yīng)用等,設(shè)備中的每個硬件模塊都會消耗電量。
  • 電量的最大消費者是 CPU,但這只是系統(tǒng)的一個方面,一個編寫良好的應(yīng)用需要謹慎地使用電能,用戶往往會刪除耗電量大的應(yīng)用。除 CPU 外,耗電量高、值得關(guān)注的硬件模塊還包括網(wǎng)絡(luò)硬件、藍牙、GPS、麥克風、加速計、攝像頭、揚聲器和屏幕等。
  • 如何降低電量的消耗,是延長使用時間的關(guān)鍵,因此需要關(guān)注以下幾個方面:
    • 判斷電池的剩余電量及充電狀態(tài);
    • 如何分析電源;
    • 如何在 iOS 應(yīng)用中分析電源,CPU 和資源的使用。

二、CPU

  • 不論用戶是否正在直接使用,CPU 都是應(yīng)用所使用的主要硬件,在后臺操作和處理推送通知時,應(yīng)用仍然會消耗 CPU 資源。如下圖所示:

  • 應(yīng)用計算的越多,消耗的電量越多。在完成相同的基本操作時,老一代的設(shè)備會消耗更多的電量,計算量的消耗取決于不同的因素:
    • 對數(shù)據(jù)的處理;
    • 待處理的數(shù)據(jù)大小,更大的顯示屏允許軟件在單個視圖中展示更多的信息,但這也意味著要處理更多的數(shù)據(jù);
    • 處理數(shù)據(jù)的算法和數(shù)據(jù)結(jié)構(gòu);
    • 執(zhí)行更新的次數(shù),尤其是在數(shù)據(jù)更新后,觸發(fā)應(yīng)用的狀態(tài)或 UI 進行更新(應(yīng)用收到的推送通知也會導致數(shù)據(jù)更新,如果此用戶正在使用應(yīng)用,還需要更新 UI)。
  • 沒有單一原則可以減少設(shè)備中的執(zhí)行次數(shù),很多規(guī)則都取決于操作的本質(zhì),以下是一些可以在應(yīng)用中投入使用的最佳實踐:
    • 針對不同的情況選擇優(yōu)化的算法;
    • 如果應(yīng)用從服務(wù)器接受數(shù)據(jù),盡量減少需要在客戶端進行的處理;
    • 優(yōu)化靜態(tài)編譯(ahead-of-time,AOT)處理,動態(tài)編譯處理的缺點在于會強制用戶等待操作完成,但是激進的 AOT 處理則會導致計算資源的浪費,需要根據(jù)應(yīng)用和設(shè)備選擇精確定量的 AOT 處理。

三、網(wǎng)絡(luò)

  • 智能的網(wǎng)絡(luò)訪問管理可以讓應(yīng)用響應(yīng)的更快,并有助于延長電池壽命,在無法訪問網(wǎng)絡(luò)時,應(yīng)該推遲后續(xù)的網(wǎng)絡(luò)請求,直到網(wǎng)絡(luò)連接恢復為止。
  • 此外,應(yīng)避免在沒有連接 WiFi 的情況下進行高寬帶消耗的操作,比如視頻流,眾所周知,蜂窩無線系統(tǒng)(LTE,4G,3G 等)對電量的消耗遠遠大于 WiFi 信號,根源在于 LTE 設(shè)備基于多輸入、多輸出技術(shù),使用多個并發(fā)信號以維護兩端的 LTE 鏈接。
  • 類似的,所有的蜂窩數(shù)據(jù)鏈接都會定期掃描以尋找更強的信號,因此需要:
    • 在進行任何網(wǎng)絡(luò)操作之前,先檢查合適的網(wǎng)絡(luò)連接是否可用;
    • 持續(xù)監(jiān)視網(wǎng)絡(luò)的可用性,并在鏈接狀態(tài)發(fā)生變化時給與適當?shù)姆答仭?/li>
  • 官方提供了檢查和監(jiān)聽網(wǎng)絡(luò)狀態(tài)的變化的代碼,大多數(shù)人使用的網(wǎng)絡(luò)庫 AFNetWorking 也提供了類似的代碼,可以任選其一,亦或是自己編寫。

四、定位管理器和 GPS

① 定位服務(wù)
  • 定位服務(wù)包括 GPS(或 GLONASS)和 WiFi 硬件以及蜂窩網(wǎng)絡(luò)。因此,iOS 的定位有三種方式:
    • 衛(wèi)星定位;
    • 蜂窩基站定位;
    • Wi-Fi 定位。
  • 定位服務(wù)是很耗電的,使用 GPS 計算坐標需要確定兩點信息:
    • 時間鎖:每個 GPS 衛(wèi)星每毫秒廣播唯一一個 1023 位隨機數(shù),因而數(shù)據(jù)傳播速率是1.024Mbit/s,GPS 的接收芯片必須正確的與衛(wèi)星的時間鎖槽對齊。
    • 頻率鎖:GPS 接收器必須計算由接收器與衛(wèi)星的相對運動導致的多普勒偏移帶來的信號誤差。
  • 計算坐標會不斷的使用 CPU 和 GPS 的硬件資源,因此會迅速的消耗電池電量。
  • 初始化 CLLocationManager 并高效接受地理位置更新的示例代碼如下:
.h文件@interface YDWLocationViewController :UIViewController<CLLocationManagerDelegate>@property (nonatomic, strong)CLLocationManager *manager;@end.m文件@implementation YDWLocationViewController- (void)viewDidLoad {[super viewDidLoad];self.manager = [[CLLocationManager alloc]init];self.manager.delegate = self; }- (void)enableLocationButtonClick:(UIButton *)sender{self.manager.distanceFilter = kCLDistanceFilterNone;// 按照最大精度初始化管理器self.manager.desiredAccuracy = kCLLocationAccuracyBest;if (IS_IOS8) {[self.manager requestWhenInUseAuthorization];}[self.manager startUpdatingLocation];}- (void)locationManager:(CLLocationManager *)managerdidUpdateLocations:(NSArray<CLLocation *> *)locations {CLLocation *loc = [locations lastObject];// 使用定位信息}
② 最佳初始化
  • distanceFilter 只要設(shè)備的移動超過了最小的距離,距離過濾器就會導致管理器對委托對象的 LocationManager:didUpdateLocations: 事件通知發(fā)生變化,該距離單位是 M;
  • desiredAccuracy 精度參數(shù)的使用直接影響了使用天線的個數(shù),進而影響了對電池的消耗,精度級別的選取取決于應(yīng)用的具體用途。精度是一個枚舉,我們應(yīng)該依照不同的需求去恰當?shù)倪x取精度級別。
  • 距離過濾器只是軟件層面的過濾器,而精度級別會影響物理天線的使用。當委托方法 LocationManager:didUpdateLocations: 被調(diào)用時,使用距離范圍更廣泛的過渡器只會影響間隔,另一方面,更高的精度級別意味著更多的活動天線,這會消耗更多的能量。
③ 關(guān)閉無關(guān)緊要的特性
  • 判斷何時需要跟蹤位置的變化,在需要跟蹤的時候調(diào)用 startUpdatingLocation 方法, 無須跟蹤時調(diào)用 stopUpdatingLocation 方法。
  • 當應(yīng)用在后臺運行或用戶沒有與別人聊天時,也應(yīng)該關(guān)閉位置跟蹤,即瀏覽媒體庫,查看朋友列表或調(diào)整應(yīng)用設(shè)置時,都應(yīng)該關(guān)閉位置跟蹤。
④ 只在必要時使用網(wǎng)絡(luò)
  • 為了提高電量的使用效率,iOS 總是盡可能地保持無線網(wǎng)絡(luò)關(guān)閉,當應(yīng)用需要建立網(wǎng)絡(luò)連接時,iOS 會利用這個機會向后臺應(yīng)用分享網(wǎng)絡(luò)會話,以便一些低優(yōu)先級能夠被處理,如推送通知、收取電子郵件等。
  • 每當用戶建立網(wǎng)絡(luò)連接時,網(wǎng)絡(luò)硬件都會在連接完成后多維持幾秒的活動時間,每次集中的網(wǎng)絡(luò)通信都會消耗大量的電量。要想減輕這個問題帶來的危害,軟件需要有所保留的的使用網(wǎng)絡(luò),應(yīng)該定期集中短暫的使用網(wǎng)絡(luò),而不是持續(xù)的保持著活動的數(shù)據(jù)流,只有這樣網(wǎng)絡(luò)硬件才有機會關(guān)閉。
⑤ 后臺定位服務(wù)
  • CLLocationManager 提供了一個替代的方法來監(jiān)聽位置的更新,[self.manager startMonitoringSignificantLocationChanges] 可以在更遠的距離跟蹤運動,精確的值由內(nèi)部決定,且與 distanceFilter 無關(guān)。
  • 使用這一模式可以在應(yīng)用進入后臺后繼續(xù)跟蹤運動,典型的做法是在應(yīng)用進入后臺時執(zhí)行 startMonitoringSignificantLocationChanges 方法,而當應(yīng)用回到前臺時執(zhí)行 startUpdatingLocation,代碼如下:
- (void)applicationDidEnterBackground:(UIApplication *)application {[self.manager stopUpdatingLocation];[self.manager startMonitoringSignificantLocationChanges];}- (void)applicationWillEnterForeground:(UIApplication *)application { [self.manager stopMonitoringSignificantLocationChanges];[self.manager startUpdatingLocation]; }
⑥ 在應(yīng)用關(guān)閉后重啟
  • 當應(yīng)用位于后臺時,任何定時器或線程都會掛起。如果在應(yīng)用位于后臺狀態(tài)時申請了定位,那么應(yīng)用會在每次收到更新后被短暫的喚醒,在此期間,線程和計時器都會被喚醒。
  • 在其他應(yīng)用需要更多資源時,后臺的應(yīng)用可能會被關(guān)閉。在這種情況下,一旦發(fā)生位置變化,應(yīng)用會被重啟,因而需要重新初始化監(jiān)聽過程,若出現(xiàn)這種情況 application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 方法會受到鍵值為 UIApplicationLaunchOptionsLocationKey 的條目,在應(yīng)用關(guān)閉后重新初始化監(jiān)聽,如下所示:
- (void)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {// 因缺乏資源而關(guān)閉應(yīng)用后, 監(jiān)測應(yīng)用是否因為位置變化而被重啟if (launchOptions[UIApplicationLaunchOptionsLocationKey]) {// 開啟監(jiān)測位置的變化[self.manager startMonitoringSignificantLocationChanges];}}

五、屏幕

  • 屏幕非常耗電,屏幕越大就越耗電。當然,如果應(yīng)用在前臺運行且與用戶進行交互,則勢必會使用屏幕并消耗電量。但是仍然有一些方案可以優(yōu)化屏幕的使用,來減少電池的電量消耗。
① 動畫
  • 當應(yīng)用在前臺時,使用動畫,一旦應(yīng)用進入了后臺,則立即暫停動畫。
  • 通常來說,可以通過監(jiān)聽 UIApplicationWillResignActiveNotification 或UIApplicationDIdEnterBackgroundNotification 的通知事件來暫停或停止動畫,也可以通過監(jiān)聽 UIApplicationDidBecomeActiveNotification 的通知事件來恢復動畫。
② 視頻播放
  • 在視頻播放期間,最好保持屏幕常亮,可以使用 UIApplication 對象的 idleTimerDisabled 屬性來實現(xiàn)這個目的,一旦設(shè)置了 YES,就會阻止屏幕休眠,從而實現(xiàn)常亮。
  • 與動畫類似,可以通過相應(yīng)應(yīng)用的通知來釋放和獲取鎖。
③ 多屏幕
  • 使用屏幕比休眠鎖或暫停/恢復動畫要復雜得多。如果正在播放電影或運行動畫,你可以將它們從設(shè)備的屏幕挪到外部屏幕,而只在設(shè)備的屏幕上保留最基本的設(shè)置,這樣可以減少設(shè)備上的屏幕更新,進而延長電池壽命。
  • 處理這一場景,會涉及以下步驟:
    • 在啟動期間監(jiān)測屏幕的數(shù)量,如果屏幕數(shù)量大于1,則進行切換;
    • 監(jiān)聽屏幕在鏈接和斷開時的通知,如果有新的屏幕加入,則進行切換。如果所有的外部屏幕都被移除,則恢復到默認顯示。
@interface YDWMultiScreenViewController ()@property (nonatomic, strong) UIWindow *secondWindow;@end@implementation YDWMultiScreenViewController- (void)viewDidAppear:(BOOL)animated {[super viewDidAppear:animated];[self updateScreens];}- (void)viewDidDisappear:(BOOL)animated{[super viewDidDisappear:animated];[self disconnectFromScreen];}- (void)viewDidLoad {[super viewDidLoad];[self registerNotifications];}- (void)registerNotifications {[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(scrensChanged:)name:UIScreenDidConnectNotificationobject:nil];}- (void)scrensChanged:(NSNotification *)nofi {[self updateScreens];}- (void)updateScreens {NSArray *screens = [UIScreen screens];if (screens.count > 1) {UIScreen *secondScreen = [screens objectAtIndex:1];CGRect rect = secondScreen.bounds;if (self.secondWindow == nil) {self.secondWindow = [[UIWindow alloc]initWithFrame:rect];self.secondWindow.screen = secondScreen;YDWScreenViewController *svc = [[YDWScreenViewController alloc]init];svc.parent = self;self.secondWindow.rootViewController = svc;}self.secondWindow.hidden = NO;} else {[self disconnectFromScreen];}}- (void)disconnectFromScreen{if (self.secondWindow != nil) {// 斷開連接并釋放內(nèi)存self.secondWindow.rootViewController = nil;self.secondWindow.hidden = YES;self.secondWindow = nil;}}- (void)dealloc {[[NSNotificationCenter defaultCenter] removeObserver:self];}@end

六、其他硬件

  • 當應(yīng)用進入后臺的時候, 應(yīng)該釋放對這些硬件的鎖定:藍牙、相機、揚聲器(除非應(yīng)用是音樂類的)、麥克風等,基本規(guī)則: 只有當應(yīng)用處于前臺時才與這些硬件進行交互,,應(yīng)用處于后臺時應(yīng)停止交互。
  • 不過揚聲器和無線藍牙可能例外,如果你正在開發(fā)音樂,收音機或其他的音頻類應(yīng)用,則需要在應(yīng)用進入后臺后繼續(xù)使用揚聲器,不要讓屏幕僅僅為音頻播放的目的而保持常亮。
  • 類似的,若應(yīng)用還有未完成的數(shù)據(jù)傳輸,則需要在應(yīng)用進入后臺后持續(xù)使用無線藍牙,如:與其他設(shè)備傳輸文件。

七、電池電量與代碼感知

  • 一個智能的應(yīng)用會考慮到電池的電量和自身的狀態(tài),從而決定是否執(zhí)行資源密集消耗性的操作(比如掃二維碼時的手電),另外一個有價值的點是對充電的判斷,確定設(shè)備是否處于充電狀態(tài)。
  • 代碼實施如下:
- (BOOL)shouldProceedWithMinLevel:(NSUInteger)minLevel {UIDevice *device = [UIDevice currentDevice];// 打開電池監(jiān)控device.batteryMonitoringEnabled = YES;UIDeviceBatteryState state = device.batteryState;// 在充電或電池已經(jīng)充滿的情況下,任何操作都可以執(zhí)行if (state == UIDeviceBatteryStateCharging ||state == UIDeviceBatteryStateFull) {return YES;} // UIdevice 返回的 batteryLevel 的范圍在0.00 ~ 1.00NSUInteger batteryLevel = (NSUInteger)(device.batteryLevel * 100);if (batteryLevel >= minLevel) {return YES;}return NO;}
  • 應(yīng)用對 CPU 的利用率:
// 需要導入這兩個頭文件#import <mach/mach.h>#import <assert.h>- (float)appCPUUsage{kern_return_t kr;task_info_data_t info;mach_msg_type_number_t infoCount = TASK_INFO_MAX; kr = task_info(mach_task_self(), TASK_BASIC_INFO, info, &infoCount); if (kr != KERN_SUCCESS) {return -1;} thread_array_t thread_list;mach_msg_type_number_t thread_count;thread_info_data_t thinfo;mach_msg_type_number_t thread_info_count;thread_basic_info_t basic_info_th;kr = task_threads(mach_task_self(), &thread_list, &thread_count);if (kr != KERN_SUCCESS) {return -1;}float tot_cpu = 0;int j;for (j = 0; j < thread_count; j++) {thread_info_count = THREAD_INFO_MAX;kr = thread_info(thread_list[j], THREAD_BASIC_INFO, thinfo, &thread_info_count);if (kr != KERN_SUCCESS) {return -1;} basic_info_th = (thread_basic_info_t)thinfo;if (!(basic_info_th -> flags & TH_FLAGS_IDLE)) {tot_cpu += basic_info_th -> cpu_usage / TH_USAGE_SCALE * 100.0;}}vm_deallocate(mach_task_self(), (vm_offset_t)thread_list, thread_count * sizeof(thread_t));return tot_cpu;}
  • 當剩余電量較低時,提醒用戶并請求用戶授權(quán)執(zhí)行電源密集型的操作。當然,只有在用戶同意的前提下執(zhí)行,總是用一個指示符(也就是進度條百分比)顯示長時間任務(wù)的進度,包括設(shè)備上即將完成的計算或者只是下載一些內(nèi)容,向用戶提供完成進度的估算,以幫助他們決定是否需要為設(shè)備充電。

八、最佳實踐

  • 以下的最佳實踐可以確保對電量的謹慎使用,遵循以下要點,應(yīng)用可以實現(xiàn)對電量的高效使用:
    • 最小化硬件使用,換句話說,盡可能晚的與硬件打交道,并且一旦完成任務(wù)立即結(jié)束使用;
    • 在進行密集型任務(wù)前,檢查電池電量和充電狀態(tài);
    • 在電量低時,提示用戶是否確定要執(zhí)行任務(wù),并在用戶同意后再執(zhí)行;
    • 或提供設(shè)置的選項,允許用戶定義電量的閾值,以便在執(zhí)行密集型操作前提示用戶。
  • 設(shè)置電量的閾值以提示用戶如下:
- (IBAction)onIntensiveOperationButtonClick:(id)sender {NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];BOOL prompt = [defaults boolForKey:@"promptForBattery"];int minLevel = [defaults integerForKey:@"minBatteryLevel"];BOOL canAutoProceed = [self shouldProceeWithMinLevel:minLevel];if (canAutoProceed) {[self executeIntensiveOperation];} else {if (prompt) {UIAlertView *view = [[UIAlertView alloc]initWithTitle:@"提示" message:@"電量低于最小值,是否繼續(xù)執(zhí)行" delegate: self cancelButtonTitle:@"取消" otherButtonTitles:@"確定"];[view show];} else {[self queueIntensiveOperation];}}}- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {if (buttonIndex == 0) {[self queueIntensiveOperation];} else {[self executeIntensiveOperation];}}
  • 設(shè)置由兩個條目組成 promptForBattery(應(yīng)用設(shè)置中的撥動開關(guān),表明是否要在低電量時給予提示)和 miniBatteryLevel(區(qū)間為0~100的一個滑塊,表明最低電量),在實際項目中應(yīng)用的開發(fā)人員通常根據(jù)操作的復雜性和密集性對閾值進行預設(shè),不同的密集型操作可能會有不同的最低電量需求。
  • 在實際執(zhí)行密集操作之前,檢查當前電量是否足夠,或者手機是否正在充電,這就是我們判斷是否可以進行后續(xù)處理的邏輯。

總結(jié)

以上是生活随笔為你收集整理的iOS之性能优化·优化App的电池耗电量的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。