如何在 Android 中服务 onDestroy 后保持对象变量处于活动状态?

Posted

技术标签:

【中文标题】如何在 Android 中服务 onDestroy 后保持对象变量处于活动状态?【英文标题】:How to keep object variable alive after service onDestroy in Android? 【发布时间】:2017-03-18 04:37:20 【问题描述】:

我的IntentService 班级中有一个MediaRecorder

我想要

    运行IntentService 开始录制音频 运行IntentService 以停止录制音频

我使用IntentService 是因为我希望即使我的手机屏幕关闭也能运行录音。服务在后台运行,所以这是一个好方法,对吧?

无论如何,我在第 1 步在我的IntentService 中启动我的MediaRecorder。 在第 2 步,我实例化的 MediaRecorder 为 NULL。看来IntentService里面的所有变量值都被重置了,因为服务结束并调用onDestroy

我该怎么办?如何保留对我的 MediaRecorder 的引用?

更新:粘贴我的 IntentService

package com.dan190.enregistreur.BackgroundService;

import android.app.IntentService;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;

import com.dan190.enregistreur.RecordedFilesActivity;
import com.dan190.enregistreur.Util.RecordingStatus;

import java.io.IOException;
import java.util.Calendar;

/**
 * Created by Dan on 17/03/2017.
 */
public class RecorderService extends IntentService 
    private static final String TAG = RecorderService.class.getName();

    private MediaRecorder mMediaRecorder;

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public RecorderService(String name) 
        super(name);
    

    public RecorderService() 
        super("RecorderService");
    
    /**
     * Handles intent.
     * Unwraps intent to find out if we need to start, pause, or stop
     * @param intent
     */
    @Override
    protected void onHandleIntent(@Nullable Intent intent) 
        Log.d(TAG, "onHandleIntent");

        Bundle bundle = intent.getExtras();
        int status = bundle.getInt(RecordingStatus.RECORDING_STATUS_KEY);
        switch (status) 
        case RecordingStatus.STANDBY:
            //do nothing
            break;
        case RecordingStatus.RECORDING:
            //if mediaPlayer is null, initiate
            //set datasource
            //prepare
            //record
            Log.d(TAG, "start recording");
            startRecording();
            break;
        case RecordingStatus.PAUSED:
            //pause
            Log.d(TAG, "pause recording");
            break;
        case RecordingStatus.STOPPED:
            //stop
            Log.d(TAG, "stop recording");
            stopRecording();
            Intent newIntent = new Intent(this, RecordedFilesActivity.class);
            startActivity(newIntent);
            break;
        case RecordingStatus.OPENDIR:
            //open recorded files
            Log.d(TAG, "open directory");
            getFileName();
            Intent newIntent2 = new Intent(this, RecordedFilesActivity.class);
            startActivity(newIntent2);
            break;
        default:
            break;
        

    

    /**
     * File stuff
     */
    private static String pathName,
    fileName;

    public static String getPath() 
        return pathName;
    

    public static String getFilePath() 
        return fileName;
    

    private String getFileName() 
        Calendar calendar = Calendar.getInstance();

        PackageManager m = getPackageManager();
        pathName = getPackageName();
        PackageInfo p = null;
        try 
            p = m.getPackageInfo(pathName, 0);
         catch(PackageManager.NameNotFoundException e) 
            e.printStackTrace();
        
        pathName = p.applicationInfo.dataDir;

        //        fileName = Environment.getExternalStorageDirectory() + "/" + Environment.DIRECTORY_DCIM + "/Recordings";
        fileName = pathName;
        fileName += String.format("/%d_%d_%d_%d_%d_%d.3gp", calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1, calendar.get(Calendar.DAY_OF_MONTH), calendar.get(Calendar.HOUR_OF_DAY) + 1, calendar.get(Calendar.MINUTE), calendar.get(Calendar.SECOND));

        return fileName;

    

    /**
     * Recorder stuff
     */
    private void startRecording() 
        String fileName = getFileName();
        Log.d(TAG, String.format("file name is %s", fileName));

        if (mMediaRecorder == null) mMediaRecorder = new MediaRecorder();

        //NOTE that mediaRecorder cannot pause for API < 24, which is Android 7.0
        mMediaRecorder.setAudiosource(MediaRecorder.AudioSource.MIC);
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        mMediaRecorder.setOutputFile(getFileName());
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

        try 
            mMediaRecorder.prepare();
         catch(IOException e) 
            Log.e(TAG, "prepare() failed");
            e.printStackTrace();
        

        try 
            mMediaRecorder.start();
         catch(IllegalStateException e) 
            Log.e(TAG, e.getStackTrace().toString());
        
    

    private void stopRecording() 
        try 
            mMediaRecorder.stop();
            mMediaRecorder.reset();
         catch(RuntimeException e) 
            e.printStackTrace();
        
        releaseMediaRecorder();
    

    private void releaseMediaRecorder() 
        if (mMediaRecorder != null) 
            mMediaRecorder.release();
            mMediaRecorder = null;
         else 
            Log.w(TAG, "mediaRecroder is already Null");
        

    

    /**
     * Lifecycle stuff
     */
    @Override
    public void onCreate() 
        super.onCreate();
        Log.i(TAG, "onCreate");
    

    @Override
    public void onDestroy() 
        super.onDestroy();
        Log.i(TAG, "onDestroy");
    


【问题讨论】:

在此处粘贴 IntentService 类 完成@ZeeshanShabbir 【参考方案1】:

通过使用服务而不是意图服务来修复它。

这篇文章很有帮助。 Service.onDestroy() is called directly after creation, anyway the Service does its work

基本上,IntentService 的设计目的是在 onHandleIntent 中的代码完成后立即停止所有服务。因此,我永远无法让我的 MediaRecorder 保持活力。

使用普通服务,我可以更好地控制服务的生命周期。我可以在需要时启动和停止它。使用 IntentService,这是不可能的。

【讨论】:

以上是关于如何在 Android 中服务 onDestroy 后保持对象变量处于活动状态?的主要内容,如果未能解决你的问题,请参考以下文章

如何防止 onPause() 之后调用 onDestroy()?

Android:在活动中 onStart()、onStop()、onDestroy() 的开头或结尾调用 super()?

Android:如何知道高级任务杀手杀死的活动/服务?

onDestroy() onTaskRemoved 两者都不能在 Redmi MI 设备上运行

在android中无限运行服务

在 Android 1.5 服务中使用唤醒锁