简体   繁体   English

当屏幕关闭时,停止CPU的休眠

[英]Stop CPU from sleeping when screen is off

I have an app that runs a webview as a service so the audio can contiune to play while the screen is locked. 我有一个将Webview作为服务运行的应用程序,因此可以在屏幕锁定时继续播放音频。 The app works great with audio streams such as podcasts. 该应用程序非常适合音频流,例如播客。 But I also wanted it to work with flash video. 但是我也希望它能与Flash视频一起使用。 I am able to load the flash video stream in the webview and have it play smooth and steady but once the screen goes off or is locked the audio becomes choppy. 我能够将Flash视频流加载到Webview中,并使其流畅稳定地播放,但是一旦屏幕关闭或被锁定,音频就会变得断断续续。 The behavior is the same on 3g and WiFi. 3g和WiFi上的行为相同。 I tried to use this posts suggestion of using a wake lock with: 我试图将这篇文章的建议与唤醒锁一起使用:

PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Tag"); 
wl.acquire();
//do what you need to do
wl.release(); 

However this has no effect. 但是,这没有效果。 I'm not sure where exactly in my code to put it but I've placed it in the oncreate for the service, which had no effect, and I placed it in the oncreate for my main activity with the same results. 我不确定将其确切放置在代码中的哪个位置,但已将其放置在服务的oncreate中,这无效,并且我将其放置在主要活动的oncreate中,结果相同。

However later in the post the person asking the question said that WIFI_MODE_FULL_HIGH_PERF was able to fix the problem. 但是在帖子的后面,询问该问题的人说WIFI_MODE_FULL_HIGH_PERF可以解决此问题。 But as I said I tested it on 3g and the audio stuttered when the screen was turned off. 但是正如我说的那样,我在3g上对其进行了测试,并且在屏幕关闭时,音频卡顿了。

Any ideas how I can stop this behavior? 有什么想法可以阻止这种行为吗?

Also I know this is a CPU intensive and a battery hog app but I'm just developing it for personal use. 我也知道这是CPU密集型和电池消耗型应用程序,但我只是在为个人使用而开发它。

This is my full code for the service: 这是我对服务的完整代码:

public class MyService extends Service {
    private NotificationManager nm;
    private static boolean isRunning = false;

    ArrayList<Messenger> mClients = new ArrayList<Messenger>(); // Keeps track of all current registered clients.
    int mValue = 0; // Holds last value set by a client.
    static final int MSG_REGISTER_CLIENT = 1;
    static final int MSG_UNREGISTER_CLIENT = 2;
    static final int MSG_SET_INT_VALUE = 3;
    static final int MSG_SET_STRING_VALUE = 4;
    PowerManager.WakeLock wl;


    @Override
    public IBinder onBind(Intent intent) {
        wl.acquire();
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("MyService", "Service Started.");
        showNotification();
        isRunning = true;
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 
        wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Tag");
    }
    private void showNotification() {
        nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
        // In this sample, we'll use the same text for the ticker and the expanded notification
        CharSequence text = getText(R.string.service_started);
        // Set the icon, scrolling text and timestamp
        Notification notification = new Notification(R.drawable.ic_launcher, text, System.currentTimeMillis());
        notification.flags = Notification.FLAG_ONGOING_EVENT;
        // The PendingIntent to launch our activity if the user selects this notification
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);
        // Set the info for the views that show in the notification panel.
        notification.setLatestEventInfo(this, getText(R.string.service_label), text, contentIntent);
        // Send the notification.
        // We use a layout id because it is a unique number.  We use it later to cancel.
        nm.notify(R.string.service_started, notification);
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("MyService", "Received start id " + startId + ": " + intent);
        return START_STICKY; // run until explicitly stopped.
    }

    public static boolean isRunning()
    {
        return isRunning;
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        nm.cancelAll();
        wl.release();
        nm.cancel(R.string.service_started); // Cancel the persistent notification.
        Log.i("MyService", "Service Stopped.");
        isRunning = false;
    }
}

My main code: 我的主要代码:

public class MainActivity extends Activity {
    Button btnStart, btnStop, btnBind, btnUnbind, btnUpby1, btnUpby10;
    Messenger mService = null;
    boolean mIsBound;
    WebView mWebView;

    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            mService = new Messenger(service);
            try {
                Message msg = Message.obtain(null, MyService.MSG_REGISTER_CLIENT);
                     mService.send(msg);
            } catch (RemoteException e) {
                // In this case the service has crashed before we could even do anything with it
            }
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been unexpectedly disconnected - process crashed.
            mService = null;
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btnStart = (Button)findViewById(R.id.btnStart);
        btnStop = (Button)findViewById(R.id.btnStop);
        btnBind = (Button)findViewById(R.id.btnBind);
        btnUnbind = (Button)findViewById(R.id.btnUnbind);

        btnStart.setOnClickListener(btnStartListener);
        btnStop.setOnClickListener(btnStopListener);
        btnBind.setOnClickListener(btnBindListener);
        CheckIfServiceIsRunning();



        //webview
        mWebView = (WebView) findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);

        mWebView.getSettings().setPluginsEnabled(true);
        mWebView.loadUrl(url);
        mWebView.setWebViewClient(new HelloWebViewClient());


    }


    private void CheckIfServiceIsRunning() {
        //If the service is running when the activity starts, we want to automatically bind to it.
        if (MyService.isRunning()) {
            doBindService();
        }
    }

    private OnClickListener btnStartListener = new OnClickListener() {
        public void onClick(View v){
            startService(new Intent(MainActivity.this, MyService.class));
        }
    };
    private OnClickListener btnStopListener = new OnClickListener() {
        public void onClick(View v){
            doUnbindService();
            stopService(new Intent(MainActivity.this, MyService.class));
        }
    };
    private OnClickListener btnBindListener = new OnClickListener() {
        public void onClick(View v){

            doBindService();
        }
    };
    private OnClickListener btnUnbindListener = new OnClickListener() {
        public void onClick(View v){

            doUnbindService();
        }
    };

    void doBindService() {
        bindService(new Intent(this, MyService.class), mConnection, Context.BIND_AUTO_CREATE);
        mIsBound = true;
    }
    void doUnbindService() {
        if (mIsBound) {
            // If we have received the service, and hence registered with it, then now is the time to unregister.
            if (mService != null) {
                try {
                    Message msg = Message.obtain(null, MyService.MSG_UNREGISTER_CLIENT);
                    mService.send(msg);
                } catch (RemoteException e) {
                    // There is nothing special we need to do if the service has crashed.
                }
            }
            // Detach our existing connection.
            unbindService(mConnection);
            mIsBound = false;
        }
    }

    private class HelloWebViewClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
            mWebView.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        try {
            doUnbindService();
        } catch (Throwable t) {
            Log.e("MainActivity", "Failed to unbind from the service", t);
        }
    }


     @Override
        protected void onResume() { 
            super.onResume();

     }
}

From your description it sounds like you are releasing the WakeLock too soon. 根据您的描述,听起来您太早释放了WakeLock。 If you are just putting that block of code in the onCreate for the Service then you really aren't getting a WakeLock while your streaming code is running. 如果您只是将该代码块放入服务的onCreate中,那么在运行流式代码时,实际上并没有得到WakeLock。 You must have the lock acquired for the duration of the background work. 在后台工作期间,您必须获取锁。

The pattern I've used for a service like this is: 我用于这样的服务的模式是:

  1. Create the WakeLock in onCreate (but do not acquire it) 在onCreate中创建WakeLock(但不获取它)
  2. In onDestroy if the WakeLock is held release it. 如果按住WakeLock,则在onDestroy中释放它。 (mostly for safety) (主要是为了安全)
  3. When starting the actual background work, either in onBind or onStartCommand, acquire the lock. 在onBind或onStartCommand中启动实际的后台工作时,获取锁。
  4. When done with the background work, release the wake lock. 完成后台工作后,释放唤醒锁。

The problem may be specifically with the way a WebView works. 问题可能与WebView的工作方式有关。 That said since this isn't production code, you could try simply 'leaking' the wake lock by removing the release just to see if that helps. 也就是说,由于这不是生产代码,因此您可以尝试通过删除发行版来“释放”唤醒锁,以查看是否有帮助。 Just create and acquire the lock at the start of your activity and not bother with the Service. 只需在活动开始时创建并获取锁,而不必理会服务。

The Service isn't really giving you much. 该服务并没有真正给您带来太多好处。 The way your code is currently structured you are still going to have problems. 当前代码的结构方式仍然会遇到问题。 Your Activity can be still deleted when in the background even if you have a Service, simply having a service won't stop this. 即使您有服务,在后台仍然可以删除您的活动,只是拥有服务并不能阻止它。 Further because the WebView is a View it really requires an Activity and view hierarchy. 此外,由于WebView是视图,因此它确实需要活动和视图层次结构。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM