You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android开发:如何将mFilePath从RecordingService传递到RecordingFragment?

如何从RecordingService传递mFilePath到RecordingFragment

首先先整理你提供的代码:

你的RecordingService.java代码

public class RecordingService extends Service { 
    private static final String LOG_TAG = "RecordingService"; 
    private String mFileName = null; 
    private String mFilePath = null; 
    private MediaRecorder mRecorder = null; 
    private DBHelper mDatabase; 
    private long mStartingTimeMillis = 0; 
    private long mElapsedMillis = 0; 
    private int mElapsedSeconds = 0; 
    private OnTimerChangedListener onTimerChangedListener = null; 
    private static final SimpleDateFormat mTimerFormat = new SimpleDateFormat("mm:ss", Locale.getDefault()); 
    private Timer mTimer = null; 
    private TimerTask mIncrementTimerTask = null; 

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

    public interface OnTimerChangedListener { 
        void onTimerChanged(int seconds); 
    } 

    @Override 
    public void onCreate() { 
        super.onCreate(); 
        mDatabase = new DBHelper(getApplicationContext()); 
    } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
        startRecording(); 
        return START_STICKY; 
    } 

    @Override 
    public void onDestroy() { 
        if (mRecorder != null) { 
            stopRecording(); 
        } 
        super.onDestroy(); 
    } 

    public void startRecording() { 
        setFileNameAndPath(); 
        mRecorder = new MediaRecorder(); 
        mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 
        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); 
        mRecorder.setOutputFile(mFilePath); 
        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); 
        mRecorder.setAudioChannels(1); 

        if (MySharedPreferences.getPrefHighQuality(this)) { 
            mRecorder.setAudioSamplingRate(44100); 
            mRecorder.setAudioEncodingBitRate(192000); 
        } 

        try { 
            mRecorder.prepare(); 
            mRecorder.start(); 
            mStartingTimeMillis = System.currentTimeMillis(); 
            //startTimer(); 
            //startForeground(1, createNotification()); 
        } catch (IOException e) { 
            Log.e(LOG_TAG, "prepare() failed"); 
        } 
    } 

    public void setFileNameAndPath(){ 
        int count = 0; 
        File f; 
        do{ 
            count++; 
            mFileName = getString(R.string.default_file_name) + "_" + (mDatabase.getCount() + count) + ".mp4"; 
            mFilePath = Environment.getExternalStorageDirectory().getAbsolutePath(); 
            mFilePath += "/SoundRecorder/" + mFileName; 
            f = new File(mFilePath); 
        }while (f.exists() && !f.isDirectory()); 
    } 

    public String getFileNameAndPath(){ 
        return mFilePath; 
    } 

    public void stopRecording() { 
        mRecorder.stop(); 
        mElapsedMillis = (System.currentTimeMillis() - mStartingTimeMillis); 
        mRecorder.release(); 
        Toast.makeText(this, getString(R.string.toast_recording_finish) + " " + mFilePath, Toast.LENGTH_LONG).show(); 

        //remove notification 
        if (mIncrementTimerTask != null) { 
            mIncrementTimerTask.cancel(); 
            mIncrementTimerTask = null; 
        } 

        mRecorder = null; 

        try { 
            mDatabase.addRecording(mFileName, mFilePath, mElapsedMillis); 
            Log.v("RecordingService", mFilePath); 
            Bundle bundle = new Bundle(); 
            RecordFragment recordFragment = new RecordFragment(); 
            bundle.putString("filepath", mFilePath); 
            recordFragment.setArguments(bundle); 
        } catch (Exception e){ 
            Log.e(LOG_TAG, "exception", e); 
        } 
    } 

    private void startTimer() { 
        mTimer = new Timer(); 
        mIncrementTimerTask = new TimerTask() { 
            @Override 
            public void run() { 
                mElapsedSeconds++; 
                if (onTimerChangedListener != null) 
                    onTimerChangedListener.onTimerChanged(mElapsedSeconds); 
                NotificationManager mgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 
                mgr.notify(1, createNotification()); 
            } 
        }; 
        mTimer.scheduleAtFixedRate(mIncrementTimerTask, 1000, 1000); 
    } 

    //TODO: 
    private Notification createNotification() { 
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getApplicationContext()) 
                .setSmallIcon(R.drawable.ic_mic_white_36dp) 
                .setContentTitle(getString(R.string.notification_recording)) 
                .setContentText(mTimerFormat.format(mElapsedSeconds * 1000)) 
                .setOngoing(true); 

        mBuilder.setContentIntent(PendingIntent.getActivities(getApplicationContext(), 0, new Intent[]{new Intent(getApplicationContext(), MainActivity.class)}, 0)); 

        return mBuilder.build(); 
    } 
}

你的RecordingFragment.java代码

public class RecordFragment extends Fragment { 
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER 
    private static final String ARG_POSITION = "position"; 
    private static final String LOG_TAG = RecordFragment.class.getSimpleName(); 
    private int position; 

    //Recording controls 
    private FloatingActionButton mRecordButton = null; 
    // evaluation button 
    private FloatingActionButton mEvalButton = null; 
    private Button mPauseButton = null; 
    private TextView mRecordingPrompt; 
    private int mRecordPromptCount = 0; 
    private boolean mStartRecording = true; 
    private boolean mPauseRecording = true; 
    private Chronometer mChronometer = null; 
    long timeWhenPaused = 0; //stores time when user clicks pause button 
    String filePath; 

    /** 
     * Use this factory method to create a new instance of 
     * this fragment using the provided parameters. 
     * 
     * @return A new instance of fragment Record_Fragment. 
     */ 
    public static

你当前代码的问题

在stopRecording()方法里,你新建了一个RecordFragment实例并设置Bundle参数,但这个新实例和界面上正在显示的Fragment完全不是同一个对象,所以参数根本传不到你想要的那个Fragment里。

下面给你几种可行的解决方案:

方案一:使用LocalBroadcastManager发送广播(简单易实现)

这是组件间通信的常用方式,适合Service向Fragment传递数据。

步骤1:在RecordingService中发送广播

修改stopRecording()方法,替换掉原来创建Fragment的代码:

public void stopRecording() {
    // ... 其他代码保持不变 ...

    try {
        mDatabase.addRecording(mFileName, mFilePath, mElapsedMillis);
        Log.v("RecordingService", mFilePath);
        
        // 发送广播传递mFilePath
        Intent intent = new Intent("RECORDING_FINISHED_ACTION");
        intent.putExtra("filepath", mFilePath);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
        
    } catch (Exception e){
        Log.e(LOG_TAG, "exception", e);
    }
}

步骤2:在RecordingFragment中注册广播接收器

在Fragment的生命周期方法中注册/注销接收器:

private BroadcastReceiver mRecordingFinishedReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        // 获取传递的文件路径
        filePath = intent.getStringExtra("filepath");
        // 这里可以做你需要的操作,比如更新UI
        Log.d(LOG_TAG, "Received file path: " + filePath);
    }
};

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    // 注册广播接收器
    IntentFilter filter = new IntentFilter("RECORDING_FINISHED_ACTION");
    LocalBroadcastManager.getInstance(requireContext()).registerReceiver(mRecordingFinishedReceiver, filter);
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    // 注销接收器,避免内存泄漏
    LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(mRecordingFinishedReceiver);
}

方案二:使用ViewModel(推荐,适合Jetpack架构)

如果你的项目使用Jetpack,可以用ViewModel来共享数据,这样Service和Fragment可以访问同一个ViewModel实例。

步骤1:创建共享的ViewModel

import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

public class RecordingViewModel extends ViewModel {
    private final MutableLiveData<String> recordingFilePath = new MutableLiveData<>();

    public void setRecordingFilePath(String path) {
        recordingFilePath.setValue(path);
    }

    public MutableLiveData<String> getRecordingFilePath() {
        return recordingFilePath;
    }
}

步骤2:在RecordingService中更新ViewModel

public void stopRecording() {
    // ... 其他代码保持不变 ...

    try {
        mDatabase.addRecording(mFileName, mFilePath, mElapsedMillis);
        Log.v("RecordingService", mFilePath);
        
        // 更新ViewModel中的数据
        RecordingViewModel viewModel = new ViewModelProvider(
                new ViewModelStoreOwner() {
                    @NonNull
                    @Override
                    public ViewModelStore getViewModelStore() {
                        return getApplication().getViewModelStore();
                    }
                },
                ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication())
        ).get(RecordingViewModel.class);
        viewModel.setRecordingFilePath(mFilePath);
        
    } catch (Exception e){
        Log.e(LOG_TAG, "exception", e);
    }
}

步骤3:在RecordingFragment中观察ViewModel数据

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    
    RecordingViewModel viewModel = new ViewModelProvider(requireActivity()).get(RecordingViewModel.class);
    viewModel.getRecordingFilePath().observe(getViewLifecycleOwner(), newPath -> {
        filePath = newPath;
        // 数据更新时执行操作,比如更新UI
        Log.d(LOG_TAG, "Received file path from ViewModel: " + filePath);
    });
}

方案三:绑定Service并使用回调接口

如果你的Service是可绑定的,可以通过绑定Service,让Fragment和Service建立连接,然后通过回调传递数据。

步骤1:修改RecordingService为可绑定

public class RecordingService extends Service { 
    // ... 其他成员变量 ...

    private final IBinder mBinder = new LocalBinder();
    private OnRecordingFinishedListener mFinishedListener;

    // 定义回调接口
    public interface OnRecordingFinishedListener {
        void onRecordingFinished(String filePath);
    }

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

    @Override 
    public IBinder onBind(Intent intent) { 
        return mBinder; 
    }

    // 设置回调监听
    public void setOnRecordingFinishedListener(OnRecordingFinishedListener listener) {
        mFinishedListener = listener;
    }

    // 修改stopRecording方法,调用回调
    public void stopRecording() {
        // ... 其他代码保持不变 ...

        try {
            mDatabase.addRecording(mFileName, mFilePath, mElapsedMillis);
            Log.v("RecordingService", mFilePath);
            
            // 通过回调传递数据
            if (mFinishedListener != null) {
                mFinishedListener.onRecordingFinished(mFilePath);
            }
            
        } catch (Exception e){
            Log.e(LOG_TAG, "exception", e);
        }
    }

    // ... 其他方法 ...
}

步骤2:在RecordingFragment中绑定Service并设置回调

private RecordingService mRecordingService;
private boolean mBound = false;

private ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName className, IBinder service) {
        RecordingService.LocalBinder binder = (RecordingService.LocalBinder) service;
        mRecordingService = binder.getService();
        mBound = true;
        // 设置回调监听
        mRecordingService.setOnRecordingFinishedListener(new RecordingService.OnRecordingFinishedListener() {
            @Override
            public void onRecordingFinished(String filePath) {
                RecordFragment.this.filePath = filePath;
                // 执行操作
                Log.d(LOG_TAG, "Received file path via callback: " + filePath);
            }
        });
    }

    @Override
    public void onServiceDisconnected(ComponentName arg0) {
        mBound = false;
    }
};

@Override
public void onStart() {
    super.onStart();
    // 绑定Service
    Intent intent = new Intent(requireContext(), RecordingService.class);
    requireContext().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}

@Override
public void onStop() {
    super.onStop();
    // 解绑Service
    if (mBound) {
        requireContext().unbindService(mConnection);
        mBound = false;
    }
}

以上三种方案都能解决你的问题,其中**方案一(LocalBroadcast)**最容易快速实现,**方案二(ViewModel)**更符合现代Android架构的最佳实践,推荐在使用Jetpack的项目中使用。

内容的提问来源于stack exchange,提问作者Mohamad Handy Nugraha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:36:02