0

画面がロックされている間もオーディオを再生し続けることができるように、サービスとして webview を実行するアプリがあります。このアプリは、ポッドキャストなどのオーディオ ストリームに最適です。しかし、Flash ビデオでも動作するようにしたかったのです。Flash ビデオ ストリームを webview にロードして、スムーズかつ安定して再生することはできますが、画面が消えたりロックされたりすると、音声が途切れ途切れになります。動作は 3g と WiFi で同じです。私はウェイクロックを使用するというこの投稿の提案を使用しようとしました:

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(); 

ただし、これは効果がありません。コードのどこに配置すればよいか正確にはわかりませんが、サービスの oncreate に配置しましたが、これは効果がなく、メイン アクティビティの oncreate に配置しても同じ結果が得られました。

ただし、投稿の後半で、質問者WIFI_MODE_FULL_HIGH_PERFは問題を解決できたと述べました。しかし、私が言ったように、3Gでテストしたところ、画面がオフになっていると音声が途切れました。

この動作を止める方法はありますか?

また、これが CPU を集中的に使用し、バッテリーを大量に消費するアプリであることはわかっていますが、個人的な使用のために開発しているだけです。

これは、サービスの完全なコードです。

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;
    }
}

私の主なコード:

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();

     }
}
4

1 に答える 1

3

あなたの説明から、WakeLock のリリースが早すぎるように思えます。そのコード ブロックを Service の onCreate に入れるだけの場合、ストリーミング コードの実行中に WakeLock を取得することはできません。バックグラウンド作業の間、ロックを取得する必要があります。

このようなサービスに使用したパターンは次のとおりです。

  1. onCreate で WakeLock を作成する (取得はしない)
  2. onDestroy で WakeLock が保持されている場合は解放します。(主に安全のため)
  3. onBind または onStartCommand のいずれかで、実際のバックグラウンド作業を開始するときに、ロックを取得します。
  4. バックグラウンド作業が完了したら、wake lock を解放します。

問題は、特に WebView の動作方法にある可能性があります。とはいえ、これは製品コードではないため、リリースを削除してウェイクロックを単に「リーク」してみて、それが役立つかどうかを確認できます。アクティビティの開始時にロックを作成して取得するだけで、サービスを気にする必要はありません。

サービスは実際にはあまり提供していません。コードが現在構造化されている方法では、まだ問題が発生します。サービスがある場合でも、バックグラウンドでアクティビティを削除できます。単にサービスを持っているだけではこれは停止しません。さらに、WebView はビューであるため、実際にはアクティビティとビューの階層が必要です。

于 2012-03-30T23:12:13.357 に答える