在現(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 和資源的使用
1. 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)用收到的推送通知也會導(dǎo)致數(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 處理則會導(dǎo)致計算資源的浪費, 需要根據(jù)應(yīng)用和設(shè)備選擇精確定量的 AOT 處理.
2. 網(wǎng)絡(luò)
智能的網(wǎng)絡(luò)訪問管理可以讓應(yīng)用響應(yīng)的更快,并有助于延長電池壽命.在無法訪問網(wǎng)絡(luò)時,應(yīng)該推遲后續(xù)的網(wǎng)絡(luò)請求, 直到網(wǎng)絡(luò)連接恢復(fù)為止。此外,應(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ù)姆答?/p>
官方提供了檢查和監(jiān)聽網(wǎng)絡(luò)狀態(tài)的變化的代碼,大多數(shù)人使用的網(wǎng)絡(luò)庫————AFNetWorking也提供了類似的代碼,我們可以任選其一,亦或是自己編寫(這段代碼并不復(fù)雜)
3. 定位管理器和 GPS
定位服務(wù)包括GPS(或GLONASS)和WIFI硬件以及蜂窩網(wǎng)絡(luò)
原文中只寫了前兩種,而我們知道iOS的定位是有三種的
衛(wèi)星定位
蜂窩基站定位
Wi-Fi定位(WIFI定位的故事和緣由很有的一講,在后面會說)
我們都知道定位服務(wù)是很耗電的,使用 GPS 計算坐標需要確定兩點信息:
時間鎖
每個 GPS 衛(wèi)星每毫秒廣播唯一一個1023位隨機數(shù), 因而數(shù)據(jù)傳播速率是1.024Mbit/s GPS 的接收芯片必須正確的與衛(wèi)星的時間鎖槽對齊
頻率鎖
GPS 接收器必須計算由接收器與衛(wèi)星的相對運動導(dǎo)致的多普勒偏移帶來的信號誤差
計算坐標會不斷的使用 CPU 和 GPS 的硬件資源,因此他們會迅速的消耗電池電量
先來看一下初始化CLLocationManager并高效接受地理位置更新的典型代碼
.h文件 @interfaceLLLocationViewController:UIViewController@property(nonatomic,strong)CLLocationManager*manager; @end .m文件 @implementationLLLocationViewController -(void)viewDidLoad{ [superviewDidLoad]; self.manager=[[CLLocationManageralloc]init]; self.manager.delegate=self; } -(void)enableLocationButtonClick:(UIButton*)sender{ self.manager.distanceFilter=kCLDistanceFilterNone; //按照最大精度初始化管理器 self.manager.desiredAccuracy=kCLLocationAccuracyBest; if(IS_IOS8){ [self.managerrequestWhenInUseAuthorization]; } [self.managerstartUpdatingLocation]; } -(void)locationManager:(CLLocationManager*)manager didUpdateLocations:(NSArray *)locations{ CLLocation*loc=[locationslastObject]; //使用定位信息 }
3.1 最佳的初始化
distanceFilter 只要設(shè)備的移動超過了最小的距離, 距離過濾器就會導(dǎo)致管理器對委托對象的 LocationManager事件通知發(fā)生變化,該距離單位是 M
desiredAccuracy 精度參數(shù)的使用直接影響了使用天線的個數(shù), 進而影響了對電池的消耗.精度級別的選取取決于應(yīng)用的具體用途,精度是一個枚舉 我們應(yīng)該依照不同的需求去恰當?shù)倪x取精度級別
距離過濾器只是軟件層面的過濾器,而精度級別會影響物理天線的使用.當委托方法 LocationManager被調(diào)用時,使用距離范圍更廣泛的過渡器只會影響間隔.另一方面,更高的精度級別意味著更多的活動天線,這會消耗更多的能量
3.2 關(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)閉位置跟蹤
3.3 只在必要時使用網(wǎng)絡(luò)
為了提高電量的使用效率, IOS 總是盡可能地保持無線網(wǎng)絡(luò)關(guān)閉.當應(yīng)用需要建立網(wǎng)絡(luò)連接時, IOS 會利用這個機會向后臺應(yīng)用分享網(wǎng)絡(luò)會話, 以便一些低優(yōu)先級能夠被處理, 如推送通知, 收取電子郵件等。關(guān)鍵在于每當用戶建立網(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)閉
3.4 后臺定位服務(wù)
這里iOS 10 之后變化比較大,參考即可
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.managerstopUpdatingLocation]; [self.managerstartMonitoringSignificantLocationChanges]; } -(void)applicationWillEnterForeground:(UIApplication*)application{ [self.managerstopMonitoringSignificantLocationChanges]; [self.managerstartUpdatingLocation]; }
3.5 在應(yīng)用關(guān)閉后重啟
當應(yīng)用位于后臺時,任何定時器或線程都會掛起。但如果你在應(yīng)用位于后臺狀態(tài)時申請了定位,那么應(yīng)用會在每次收到更新后被短暫的喚醒。在此期間,線程和計時器都會被喚醒。
3.6 在應(yīng)用關(guān)閉后重啟
在其他應(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*)applicationdidFinishLaunchingWithOptions:(NSDictionary*)launchOptions{ //因缺乏資源而關(guān)閉應(yīng)用后,監(jiān)測應(yīng)用是否因為位置變化而被重啟 if(launchOptions[UIApplicationLaunchOptionsLocationKey]){ //開啟監(jiān)測位置的變化 [self.managerstartMonitoringSignificantLocationChanges]; } }
4 屏幕
屏幕非常耗電, 屏幕越大就越耗電.當然,如果你的應(yīng)用在前臺運行且與用戶進行交互,則勢必會使用屏幕并消耗電量 這里仍然有一些方案可以優(yōu)化屏幕的使用
4.1 動畫
當應(yīng)用在前臺時, 使用動畫, 一旦應(yīng)用進入了后臺,則立即暫停動畫.通常來說,你可以通過監(jiān)聽 UIApplicationWillResignActiveNotification或UIApplicationDIdEnterBackgroundNotification的通知事件來暫?;蛲V箘赢?也可以通過監(jiān)聽UIApplicationDidBecomeActiveNotification的通知事件來恢復(fù)動畫
4.2 視頻播放
在視頻播放期間,最好保持屏幕常量.可以使用UIApplication對象的 idleTimerDisabled屬性來實現(xiàn)這個目的.一旦設(shè)置了 YES, 他會阻止屏幕休眠,從而實現(xiàn)常亮. 與動畫類似,你可以通過相應(yīng)應(yīng)用的通知來釋放和獲取鎖
4.3 多屏幕
使用屏幕比休眠鎖或暫停/恢復(fù)動畫要復(fù)雜得多
如果正在播放電影或運行動畫, 你可以將它們從設(shè)備的屏幕挪到外部屏幕,而只在設(shè)備的屏幕上保留最基本的設(shè)置,這樣可以減少設(shè)備上的屏幕更新,進而延長電池壽命
處理這一場景的典型代碼會涉及一下步驟
在啟動期間監(jiān)測屏幕的數(shù)量 如果屏幕數(shù)量大于1,則進行切換
監(jiān)聽屏幕在鏈接和斷開時的通知. 如果有新的屏幕加入, 則進行切換. 如果所有的外部屏幕都被移除,則恢復(fù)到默認顯示
@interface LLMultiScreenViewController () @property (nonatomic, strong)UIWindow *secondWindow; @end
@implementation LLMultiScreenViewController
}
}
}
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc addObserver:self selector:@selector(scrensChanged:) name:UIScreenDidConnectNotification object:nil];
}
}
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;
LLScreen2ViewController*svc=[[LLScreen2ViewControlleralloc]init]; svc.parent=self; self.secondWindow.rootViewController=svc; } self.secondWindow.hidden=NO;
}else{ [self disconnectFromScreen]; }
}
if (self.secondWindow != nil) { // 斷開連接并釋放內(nèi)存 self.secondWindow.rootViewController = nil; self.secondWindow.hidden = YES; self.secondWindow = nil; }
}
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
(void)dealloc{
(void)disconnectFromScreen{
(void)updateScreens{
(void)scrensChanged:(NSNotification *)nofi{ [self updateScreens];
(void)registerNotifications{
(void)viewDidLoad { [super viewDidLoad];
[self registerNotifications];
(void)viewDidDisappear:(BOOL)animated{ [super viewDidDisappear:animated]; [self disconnectFromScreen];
(void)viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; [self updateScreens];
5 其他硬件
當你的應(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è)備傳輸文件
6 電池電量與代碼感知
一個智能的應(yīng)用會考慮到電池的電量和自身的狀態(tài), 從而決定是否執(zhí)行資源密集消耗性的操作(比如掃二維碼時的手電).另外一個有價值的點是對充電的判斷,確定設(shè)備是否處于充電狀態(tài)
來看一下此處的代碼實施
-(BOOL)shouldProceedWithMinLevel:(NSUInteger)minLevel{ UIDevice*device=[UIDevicecurrentDevice]; //打開電池監(jiān)控 device.batteryMonitoringEnabled=YES; UIDeviceBatteryStatestate=device.batteryState; //在充電或電池已經(jīng)充滿的情況下,任何操作都可以執(zhí)行 if(state==UIDeviceBatteryStateCharging|| state==UIDeviceBatteryStateFull){ returnYES; } //UIdevice返回的batteryLevel的范圍在0.00~1.00 NSUIntegerbatteryLevel=(NSUInteger)(device.batteryLevel*100); if(batteryLevel>=minLevel){ returnYES; } returnNO; }
我們也可以得到應(yīng)用對 CPU 的利用率
//需要導(dǎo)入這兩個頭文件 #import#import -(float)appCPUUsage{ kern_return_tkr; task_info_data_tinfo; mach_msg_type_number_tinfoCount=TASK_INFO_MAX; kr=task_info(mach_task_self(),TASK_BASIC_INFO,info,&infoCount); if(kr!=KERN_SUCCESS){ return-1; } thread_array_tthread_list; mach_msg_type_number_tthread_count; thread_info_data_tthinfo; mach_msg_type_number_tthread_info_count; thread_basic_info_tbasic_info_th; kr=task_threads(mach_task_self(),&thread_list,&thread_count); if(kr!=KERN_SUCCESS){ return-1; } floattot_cpu=0; intj; for(j=0;jflags&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)); returntot_cpu; }
當剩余電量較低時,提醒用戶,并請求用戶授權(quán)執(zhí)行電源密集型的操作,---當然,只在 用戶同意的前提下執(zhí)行 總是用一個指示符(也就是進度條百分比)顯示長時間任務(wù)的進度, 包括設(shè)備上即將完成的計算或者只是下載一些內(nèi)容.向用戶提供完成進度的估算, 以幫助他們決定是否需要為設(shè)備充電
7 最佳實踐
以下的最佳實踐可以確保對電量的謹慎使用, 遵循以下要點,應(yīng)用可以實現(xiàn)對電量的高效使用.
最小化硬件使用. 換句話說,盡可能晚的與硬件打交道, 并且一旦完成任務(wù)立即結(jié)束使用
在進行密集型任務(wù)前, 檢查電池電量和充電狀態(tài)
在電量低時, 提示用戶是否確定要執(zhí)行任務(wù),并在用戶同意后再執(zhí)行
或提供設(shè)置的選項,允許用戶定義電量的閾值,以便在執(zhí)行秘籍型操作前提示用戶
下邊代碼展示了設(shè)置電量的閾值以提示用戶.
-(IBAction)onIntensiveOperationButtonClick:(id)sender{ NSUserDefaults*defaults=[NSUserDefaultsstandardUserDefaults]; BOOLprompt=[defaultsboolForKey:@"promptForBattery"]; intminLevel=[defaultsintegerForKey:@"minBatteryLevel"]; BOOLcanAutoProceed=[selfshouldProceeWithMinLevel:minLevel]; if(canAutoProceed){ [selfexecuteIntensiveOperation]; }else{ if(prompt){ UIAlertView*view=[[UIAlertViewalloc]initWithTitle:@"提示"message:@"電量低于最小值,是否繼續(xù)執(zhí)行"delegate:selfcancelButtonTitle:@"取消"otherButtonTitles:@"確定"]; [viewshow]; }else{ [selfqueueIntensiveOperation]; } } } -(void)alertView:(UIAlertView*)alertViewclickedButtonAtIndex:(NSInteger)buttonIndex{ if(buttonIndex==0){ [selfqueueIntensiveOperation]; }else{ [selfexecuteIntensiveOperation]; } }
設(shè)置由兩個條目組成:promptForBattery(應(yīng)用設(shè)置中的撥動開關(guān),表明是否要在低電量時給予提示)和miniBatteryLevel(區(qū)間為0~100的一個滑塊,表明了最低電量------在此示例中,用戶可以自行調(diào)整),在實際項目中應(yīng)用的開發(fā)人員通常根據(jù)操作的復(fù)雜性和密集性對閾值進行預(yù)設(shè).不同的密集型操作可能會有不同的最低電量需求
在實際執(zhí)行密集操作之前,檢查當前電量是否足夠, 或者手機是否正在充電.這就是我們判斷是否可以進行后續(xù)處理的邏輯,圖中你可以有自己的定制---最低電量和充電狀態(tài)
-
cpu
+關(guān)注
關(guān)注
68文章
10887瀏覽量
212339 -
gps
+關(guān)注
關(guān)注
22文章
2899瀏覽量
166393 -
藍牙
+關(guān)注
關(guān)注
114文章
5837瀏覽量
170756 -
iOS
+關(guān)注
關(guān)注
8文章
3395瀏覽量
150795 -
電池
+關(guān)注
關(guān)注
84文章
10643瀏覽量
130464
原文標題:7 最佳實踐
文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論