在后台运行的服务?

5

我正在构建的应用程序有一个记录功能。我通过在服务中启动一个MediaRecorder对象来实现这个功能:

Intent intent = new Intent(v.getContext(), RecordService.class);
Messenger messenger = new Messenger(handler);
intent.putExtra("COUNT", basic);
intent.putExtra("MESSENGER", messenger);

v.getContext().startService(intent);

//service

//...
mRecorder = new MediaRecorder();
//...

现在我添加了一个通知,用于让用户了解录制本身的状态,因为如果你回到主页或点击返回按钮,它必须继续录制。因此,如果你点击通知,你会回到应用程序

这就是我遇到困难的地方,如果我点击通知,我回到应用程序,但所有内容都被设置为初始状态(计时器回到00:00:00,我可以再次点击录制按钮而不是暂停按钮)。我应该实现的当然是保持录制并且我可以看到正在进行的计时器+停止按钮。注意:计时器现在不是一个服务。有什么想法吗?我应该如何处理这个问题?

编辑

假设我关闭了应用程序,服务仍在运行。重新打开应用程序(因此是最初调用服务的活动)我们可以使用:

private boolean isMyServiceRunning() {
        ActivityManager manager = (ActivityManager) myContext.getSystemService(Context.ACTIVITY_SERVICE);
        for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (MyService.class.getName().equals(service.service.getClassName())) {
                return true;
            }
        }
        return false;
    }

我在某种程度上已经解决了这个问题,但是从该服务传递到该活动的变量现在已经丢失。看起来我的活动中的处理程序在重新打开该活动后没有接收到它们?

private Handler handler = new Handler() {
        public void handleMessage(Message message) {

            //..
            Bundle bundle = message.getData();
            fileName = bundle.getString("FILENAME");
            tvFileName.setText(fileName);


            Log.e("Filename", "transfered: " + fileName);

        };
    };

//编辑

片段:

public class LayoutOne extends Fragment implements OnClickListener {

    //vars
    @Override
    public void onPause() {
        super.onPause();
        if (mRecorder != null) {
            mRecorder.release();
            mRecorder = null;
        }

        if (mPlayer != null) {
            mPlayer.release();
            mPlayer = null;
        }
    }

    private Handler handler = new Handler() {
        public void handleMessage(Message message) {

            int i = message.arg1;
            Bundle bundle = message.getData();
            fileName = bundle.getString("FILENAME");
            tvFileName.setText(fileName);

            Log.e("Handler", "Succesfully transfered: " + (Integer.toString(i)));
            Log.e("Filename", "Succesfully transfered: " + fileName);
        };
    };

    @Override
    public void onClick(View v) {

        switch (v.getId()) {
        case R.id.bRecord:

            if (mStartRecording) {
                mStartRecording = false;
                Intent intent = new Intent(v.getContext(), RecordService.class);

                Messenger messenger = new Messenger(handler);
                intent.putExtra("MESSENGER", messenger);
                v.getContext().startService(intent);


            } else {
                mRecordButton.setText("Record");
                Intent stopIntent = new Intent(v.getContext(),
                        RecordService.class);

                try {
                    v.getContext().stopService(stopIntent);
                } catch (Exception e) {
                    e.printStackTrace();

                }
                mStartRecording = true;
            }

            break;

        case R.id.bStop:
            Intent stopIntent = new Intent(v.getContext(), RecordService.class);
            v.getContext().stopService(stopIntent);
            break;

        }
    }

    public static Fragment newInstance(Context context) {
        LayoutOne f = new LayoutOne();
        return f;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
        root = (ViewGroup) inflater.inflate(R.layout.layout_one, null);
        myContext = container.getContext();

        //buttons

        mgr = (NotificationManager) myContext.getSystemService(Context.NOTIFICATION_SERVICE);
        return root;
    }



    public void notifyMe(View v) {
        Notification note = new Notification(R.drawable.ic_launcher,
                getString(R.string.notificationbar), System.currentTimeMillis());
        PendingIntent i = PendingIntent.getActivity(myContext, 0, new Intent(
                myContext, ViewPagerStyle1Activity.class), 0);

        note.setLatestEventInfo(myContext, getString(R.string.app_name),
                getString(R.string.notification), i);
        note.number = ++count;
        note.vibrate = new long[] { 500L, 200L, 200L, 500L };
        note.flags |= Notification.FLAG_AUTO_CANCEL;

        mgr.notify(NOTIFY_ME_ID, note);
    }

    public void clearNotification(View v) {
        mgr.cancel(NOTIFY_ME_ID);
    }

    // /SHARED PREFERENCES SETTINGS///
//…

    private void initiatePopupWindow() {
        //..
    }



    @Override
    public void onResume() {
        super.onResume();
        Intent intent = new Intent(myContext, RecordService.class);
        myContext.startService(intent);
        myContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // TODO Auto-generated method stub
             LocalBinder binder = (LocalBinder) service;
                myService = binder.getService();
                //myService.setBound(true);
                initializeUI();

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub

        }
    };

    protected void initializeUI() {
        //..

        }

    }

    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        myContext.unbindService(mServiceConnection);
    }

    @Override
    public void onStop() {
        // TODO Auto-generated method stub
        myContext.unbindService(mServiceConnection);
    }



}

//SERVICE

public class RecordService extends Service {

    //vars

     public class LocalBinder extends Binder {
            RecordService getService() {
                return RecordService.this;
            }
        }

    @Override
    public void onCreate() {
        Log.i("Oncreate", "Service onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Bundle extras = intent.getExtras();
        if (extras != null) {

            messenger = (Messenger) extras.get("MESSENGER");
            count = Integer.toString(extras.getInt("COUNT"));
            try {
                Message message = new Message();
                int arg = 0;
                message.arg1 = arg;

                mFileNamePass=”test”;
                Bundle bundle = new Bundle();
                bundle.putString("FILENAME", mFileNamePass);
                message.setData(bundle);
                messenger.send(message);
            } catch (android.os.RemoteException e1) {
                Log.w(getClass().getName(), "Exception sending message", e1);
            }
        }
        else {
            Log.i("Extras","Didn't find extras");
        }

        Runnable r = new Runnable() {

            @Override
            public void run() {
                checkIfFolderExists();
                String dateFull = calculateDate();
                mFileName = Environment.getExternalStorageDirectory()
                        .getAbsolutePath();
                mFileName += "test.3gp";

                mRecorder = new MediaRecorder();
                mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                mRecorder.setOutputFile(mFileName);
                mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

                try {
                    mRecorder.prepare();
                } catch (IOException e) {
                    Log.e(LOG_TAG, "prepare() failed");
                }

                mRecorder.start();
                Log.i("Service", "Service running");

            }
        };

        Thread t = new Thread(r);
        t.start();
        return RecordService.START_STICKY;
    }

    @Override
    public void onDestroy() {

        Runnable stopRecord = new Runnable() {

            @Override
            public void run() {
                mRecorder.stop();
                mRecorder.release();
                mRecorder = null;

            }

        };
        Thread stopRecordThread = new Thread(stopRecord);
        stopRecordThread.start();
        Log.i("Service", "Service stopped");
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }



}

更新了我的问题,得到了一个解决方案,但是从服务传递的变量在重新打开活动后是否被接收到。 - Matthias Vanb
1
"一切都已设置为初始状态",你的onPause和onResume中有什么? - StarPinkER
我正在使用一个片段进行初始化,其中的命令来自于该活动,并且在该片段中,我只有一个onPause方法:@Override public void onPause() { super.onPause(); if (mRecorder != null) { mRecorder.release(); mRecorder = null; } - Matthias Vanb
当用户从您的组件返回主页时,将调用onPause方法,因此我认为在onPause方法中释放录音机是不合适的。 - StarPinkER
1个回答

1

首先,您不需要通过某些ActivityManager方法来检查您的Service是否正在运行。 如果在onResume()中调用startService() && bindService(),Android足够智能,如果服务已经在运行,则仅绑定到该服务,如果没有,则按照其正确的记录生命周期创建Service,然后绑定到它。

您可以在此处执行以下操作:

@Override
public void onResume() {
    super.onResume();
    Intent intent = new Intent(this, YourService.class);
    startService(intent);
    bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}

现在,假设您的服务已经运行,并且您想获取其正确的值。在您的ServiceConnection()onServiceConnected()方法中,当绑定完成时,您可以调用一个类似于initializeUI()的方法:
private ServiceConnection mServiceConnection = new ServiceConnection() {
    public void onServiceConnected(ComponentName className, IBinder service) {
        LocalBinder binder = (LocalBinder) service;
        myService = binder.getService();
        myService.setBound(true);
        initializeUI();
    }

    public void onServiceDisconnected(ComponentName className) {
    }
};

现在,您有一个指向您的Service对象的myService变量,您可以调用其中的getter方法,例如myService.getTimer()和myService.isRecording()。请注意保留html标签。
public void initializeUI() {
    timerTextview.setText( myService.getTime() );
    someOtherUiElement.setText( myService.getSomething() );
    if( myService.isRecording() )
        recordButton.setImageResource( R.drawable.pause );
} //etc...

顺便说一下,我不知道你是否也在努力让你的服务在退出应用后保持运行 如果是的话,使用startService(intent)将使你的Service在Android有足够的内存时保持运行。你必须有一段代码可以调用myService.stopService(),否则,服务将会长时间运行。


谢谢@tolgap!我今晚会深入研究它,并会回复你! - Matthias Vanb
我试过用这种方式实现,但为什么在Eclipse中myService.startRecording()会给我编译错误,而binder.getService().startRecording()却没有?@tolgap? - Matthias Vanb
你能打开一个 Tinychat 房间或 Stack Overflow 聊天室,这样我就可以帮助你更多了。 - tolgap
我会在这里和你交流:@tolgap(http://chat.stackoverflow.com/rooms/26930/http-stackoverflow-com-questions-15494917-service-run-in-background) - Matthias Vanb
@tolgap 我相信服务,即使在远程进程上运行,也与主UI线程共享同一个线程。我使用远程服务中的睡眠方法进行了测试,它会挂起整个应用程序。 - woojoo666
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接