zoukankan      html  css  js  c++  java
  • Android TimeoutExceptions及 wakelock

    本篇简单介绍调试机器人出现的TimeoutExceptions问题 Android 4.4

    问题描述

    机器人介绍:讲解机器人软件部分 分为双层结构。机器人胸口屏幕负责 UI 交互以及和服务器的通信。机器人底层Android v4.4 主板负责机器人运动控制。

    两层软件 通过网线进行通讯。在机器人的讲解过程中经常底层Android 主板上的App经常会出现TimeoutExceptions 问题崩溃。

    java.util.concurrent.TimeoutException: com.android.internal.os.BinderInternal$GcWatcher.finalize() timed out after 10 seconds

    解决方案

    GcWatcher.finalize, BinderProxy.finalizePlainSocketImpl.finalize 中的一类TimeoutExceptions。这个异常90%都是发生在4.34.4android系统上。

    这个问题的根源在于设备会Goes to Sleep一会儿,就是说操作系统会通过熄屏、降低cpu循环等方式降低电量消耗,进入休眠状态。它是通过在内核层暂停进程的方式来实现的。这可能发生在常规app运行的过程中, 但是会停在一次内核调用上,比如内核层的上下文切换。这就是Dalvik GC参与最初所说TimeoutExceptions问题的方式。

    Dalvik GC的基本工作方式就是,在GC循环中将收集到的一系列的对象去销毁。

    如果有一个后台运行的进程,在运行过程中,对象被创建、使用以及被收集(以释放内存)。一般的,应用不会使用Wakelock,因为会很耗电并且也没必要,这意味着应用会不时的执行GC动作。通常情况下,GC动作会正常的执行完成而不会被挂起。但是,有些时候(很稀少),操作系统会在GC动作的过程中进入休眠。如果你的应用运行时间足够长,它就有可能发生。现在,想一下GC循环中的有关时间戳的逻辑:有可能发生,设备开始进行GC,并且在处理系统对象销毁(native层的destroy())的过程中进入休眠, 然后被唤醒,恢复运行,记录现在的时间戳,也就是说这次GC动作花费的时间=销毁动作执行时长+休眠时长。如果休眠时间超过10s, 就会抛出concurrent.timeout异常。

    这个问题不能完全避免,只要你的应用在后台运行。我们可以通过调用wakelock减少设备休眠。

    wakelock

    对于系统来说,系统为了节省电量,cpu在没有任务很忙的时候会进入休眠状态。当有任务需要cpu高效执行的时候,就会给cpu加一个wakelock锁,我们给CPU加一个锁,系统就不会处于休眠状态。

    AndroidManifest.xml:

    
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.DEVICE_POWER"/>
    
    
    
    
        private boolean iswakeLock = true;// 是否常亮   
        private WakeLock wakeLock;  
    
    	@Override
    		protected void onResume() {
    			// TODO Auto-generated method stub
    			PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
    			wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
    					| PowerManager.ON_AFTER_RELEASE, "MyWakelockTag");
    
    			if (iswakeLock) {
    				wakeLock.acquire();
    			}
    			super.onResume();
    
    		}
    
        @Override
        protected void onPause() {
            // TODO Auto-generated method stub
            super.onPause();
            if (wakeLock != null) {
                wakeLock.release();
            }
        }
    
    
    

    onRusume方法中将获得到的锁使用acquire()方法来保持唤醒,在onPause方法中使用release()方法来释放掉该锁。

    锁类型:

    • PARTIAL_WAKE_LOCK:保持CPU 运转,屏幕和键盘灯有可能是关闭的

    • SCREEN_DIM_WAKE_LOCK:保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯

    • SCREEN_BRIGHT_WAKE_LOCK:保持CPU 运转,允许保持屏幕高亮显示,允许关闭键盘灯

    • FULL_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度

    • ACQUIRE_CAUSES_WAKEUP:正常唤醒锁实际上并不打开照明。相反,一旦打开他们会一直仍然保持。当获得wakelock,这个标志会使屏幕或/和键盘立即打开。一个典型的使用就是可以立即看到那些对用户重要的通知

    • ON_AFTER_RELEASE:设置了这个标志,当wakelock释放时用户activity计时器会被重置,导致照明持续一段时间。如果你在wacklock条件中循环,这个可以用来减少闪烁

    update 2018/04/06

    keep the screen on

    控制屏幕一直处于常亮状态

    1. Activity中使用 FLAG_KEEP_SCREEN_ON
    
    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);
      }
    
    
    1. 或是在xml 使用参数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>
    
    

    keep the CPU on

    控制cpu一直处于工作状态

    manifest file:

    
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    
    
    
    PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
    WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
            "MyWakelockTag");
    wakeLock.acquire();
    
    //  wakelock.release() /* release wakelock*/
    
    

    Using WakefulBroadcastReceiver

    WakefulBroadcastReceiver 是一种特殊的broadcast receiver为你的app提供WAKE_LOCK管理服务,确保在耗时任务完成之前设备不会熄屏。

    • 通过方法 startWakefulService(Context, Intent)来启动服务,启动后WakefulBroadcastReceiver 将自动创建一个wakelock ,并在Intent附上一个wakelock Id来区分 。

    • 最后必须调用 completeWakefulIntent(intent) 释放wakelock

    WakefulBroadcastReceiver,Demo

    AndroidManifest.xml

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

    启动 WakefulBroadcastReceiver

    
    public class MyWakefulReceiver extends WakefulBroadcastReceiver {            
        @Override    
        public void onReceive(Context context, Intent intent) {
            Intent service = new Intent(context, MyWakefulReceiver.class);      
            startWakefulService(context, service);    
        }
    }
    
    

    在耗时操作结束之后释放wakelock

    
    public class MyWakefulService extends IntentService {    
        public MyWakefulService() {        
            super("MyWakefulService");    
        } 
    
        @Override    
        protected void onHandleIntent(Intent intent) {        
            ...
            // 执行耗时任务
        
            // 任务结束释放唤醒锁
            MyWakefulReceiver.completeWakefulIntent(intent);    
        }
    }
    
    
  • 相关阅读:
    kafka
    yum-nginx
    expect
    ubuntu快捷方式
    10,zzlian爬取
    9-豆瓣电影
    8selenium
    7,pyquery获取数据
    6,BeautifulSoup-获取数据
    5-正则匹配获取数据
  • 原文地址:https://www.cnblogs.com/chenjy1225/p/9662283.html
Copyright © 2011-2022 走看看