即使在最小化应用程序并在浏览片段时重新启动后,声音也会继续播放 [英] Sounds keep playing even after minimizing the app and restarts when navigating through fragments

查看:30
本文介绍了即使在最小化应用程序并在浏览片段时重新启动后,声音也会继续播放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的天气应用程序上成功实现声音后,搜索城市时播放效果非常好.但问题是,即使我最小化应用程序,它仍然一直重复播放声音,直到我关闭/退出应用程序.我愿意当我最小化应用程序时暂停,然后从它停止的地方继续播放回来的那一刻.

After successfully implementing sounds on my weather app, it plays quite OK when a city is searched. But the problem is that even when I minimize the app, it still keeps playing the sounds on repeat until I close/exit the app. I would like it to pause when I minimize the app, then continue playing from exactly where it stopped the moment I enter back.

所以我尝试添加此代码:

So I tried adding this code:

@Override
    public void onStop() {
        super.onStop();
        mMediaPlayer.pause();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mMediaPlayer.pause();
    }

它只是在最小化后完全停止声音,并且在返回时不会恢复.它也是降低了应用搜索城市的速度.

It only entirely stops the sound after minimizing and doesn't resume when entering back. It also slows the app from searching a city.

此外,该应用程序包含我导航的 3 个片段(今天、每小时和每日标签)通过单击底部导航.如果我在第一个选项卡上并且声音是播放然后我切换到第二/第三个标签然后移回第一个标签,声音自动重新启动播放的任何声音.我也想解决这个问题.

Also, the app contains 3 fragments(today, hourly and daily tabs) which I navigate through by clicking on the bottom navs. If I'm on the first tab and the sound is playing then I switch to the 2nd/3rd tab then move back to the first tab, the sound automatically restarts whichever sound it is playing. I would like to resolve the issue also.

这是片段的代码:

public class FirstFragment extends Fragment {

    private WeatherDataViewModel viewModel;

    private MediaPlayer mMediaPlayer; // Single MediaPlayer object

    public FirstFragment() {
// Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View rootView = inflater.inflate(R.layout.fragment_first, container, false);
        // For displaying weather data
        final TextView current_temp = rootView.findViewById(R.id.textView10);
        final TextView current_output = rootView.findViewById(R.id.textView11);
        final TextView rise_time = rootView.findViewById(R.id.textView25);
        final TextView set_time = rootView.findViewById(R.id.textView26);
        final TextView temp_out = rootView.findViewById(R.id.textView28);
        final TextView Press_out = rootView.findViewById(R.id.textView29);
        final TextView Humid_out = rootView.findViewById(R.id.textView30);
        final TextView Ws_out = rootView.findViewById(R.id.textView33);
        final TextView Visi_out = rootView.findViewById(R.id.textView34);
        final TextView Cloud_out = rootView.findViewById(R.id.textView35);
        final ImageView current_icon = rootView.findViewById(R.id.imageView6);
        final SwipeRefreshLayout realSwipe = rootView.findViewById(R.id.real_swipe);

        // Get our ViewModel instance
        viewModel = new ViewModelProvider(this).get(WeatherDataViewModel.class);

        // And whenever the data changes, refresh the UI
        viewModel.getWeatherDataLiveData().observe(getViewLifecycleOwner(), data -> {

            realSwipe.setOnRefreshListener(() -> {
                // perform you action here for ex. add refresh screen code here
                new Handler().postDelayed(() -> {
                    // this code is for stop refreshing icon, After 1000 ms automatically refresh icon will stop
                    realSwipe.setRefreshing(false);
                }, 1000);
            });

            int drawableResource = -1; // here define default icon for example R.drawable.default_weather_icon

            int soundResource = -1; // Default sound is nothing

            if (data != null) {
                current_temp.setVisibility(View.VISIBLE);
                current_temp.setText(data.getMain().getTemp() + " ℃"); // for that you can use strings resource and templates more in https://developer.android.com/guide/topics/resources/string-resource.html#formatting-strings
                current_output.setVisibility(View.VISIBLE);
                current_output.setText(data.getWeather().get(0).getDescription());
                rise_time.setVisibility(View.VISIBLE);
                rise_time.setText(data.getSys().getSunrise() + " ");
                set_time.setVisibility(View.VISIBLE);
                set_time.setText(data.getSys().getSunset() + " ");
                temp_out.setVisibility(View.VISIBLE);
                temp_out.setText(data.getMain().getTemp() + " ℃");
                Press_out.setVisibility(View.VISIBLE);
                Press_out.setText(data.getMain().getPressure() + " hpa");
                Humid_out.setVisibility(View.VISIBLE);
                Humid_out.setText(data.getMain().getHumidity() + " %");
                Ws_out.setVisibility(View.VISIBLE);
                Ws_out.setText(data.getWind().getSpeed() + " Km/h");
                Visi_out.setVisibility(View.VISIBLE);
                Visi_out.setText(data.getVisibility() + " m");
                Cloud_out.setVisibility(View.VISIBLE);
                Cloud_out.setText(data.getClouds().getAll() + " %");

// get actual weather.

                String icon = data.getWeather().get(0).getIcon();

                switch (icon) {
                    case "01d":
                    case "01n":
                        drawableResource = R.drawable.sun;
                        soundResource = R.raw.clear_sky_sound;
                        break;

                    case "02d":
                    case "021n":
                        drawableResource = R.drawable.few_clouds;
                        soundResource = R.raw.clouds_sound;
                        break;

                    case "03d":
                    case "03n":
                        drawableResource = R.drawable.scattered_clouds;
                        soundResource = R.raw.clouds_sound;
                        break;

                    case "04d":
                    case "04n":
                        drawableResource = R.drawable.broken_clouds;
                        soundResource = R.raw.clouds_sound;
                        break;

                    case "09d":
                    case "09n":
                        drawableResource = R.drawable.shower_rain;
                        soundResource = R.raw.shower_rain_sound;
                        break;

                    case "10d":
                    case "10n":
                        drawableResource = R.drawable.small_rain;
                        soundResource = R.raw.shower_rain_sound;
                        break;

                    case "11d":
                    case "11n":
                        drawableResource = R.drawable.thunderstorm;
                        soundResource = R.raw.thunderstorm_sound;
                        break;

                    case "13d":
                    case "13n":
                        drawableResource = R.drawable.snow;
                        soundResource = R.raw.snow_sound;
                        break;

                    case "50d":
                    case "50n":
                        drawableResource = R.drawable.mist;
                        soundResource = R.raw.mist_sound;
                        break;
                }

                if (drawableResource != -1)
                    current_icon.setImageResource(drawableResource);


                if (soundResource != -1) {

                    if (mMediaPlayer != null) {

                        // stop the playing
                        if (mMediaPlayer.isPlaying()) {
                            mMediaPlayer.stop();
                        }

                        // release mMediaPlayer resoruces
                        mMediaPlayer.release();
                        mMediaPlayer = null;
                    }

                    // Play the new resource
                    prepareMediaPlayer(soundResource);
                }

            } else {
                Log.e("TAG", "No City found");
                current_temp.setVisibility(View.GONE);
                current_output.setVisibility(View.GONE);
                rise_time.setVisibility(View.GONE);
                set_time.setVisibility(View.GONE);
                temp_out.setVisibility(View.GONE);
                Press_out.setVisibility(View.GONE);
                Humid_out.setVisibility(View.GONE);
                Ws_out.setVisibility(View.GONE);
                Visi_out.setVisibility(View.GONE);
                Cloud_out.setVisibility(View.GONE);
                Toast.makeText(requireActivity(), "No City found", Toast.LENGTH_SHORT).show();
            }
        });

        return rootView;
    }

    public void getWeatherData(String name) {
// The ViewModel controls loading the data, so we just
// tell it what the new name is - this kicks off loading
// the data, which will automatically call through to
// our observe() call when the data load completes
        viewModel.setCityName(name);
    }


    private void prepareMediaPlayer(int resource) {
        // add track file
        mMediaPlayer = MediaPlayer.create(requireActivity(), resource);

        // listening to when the media file finishes playing so that we can release the resources
        mMediaPlayer.setLooping(true);
        mMediaPlayer.start();

    }

}

天气数据视图模型:

public class WeatherDataViewModel extends ViewModel {
    // This will save the city name
    private SavedStateHandle state;

    // This is where we'll store our result from the server
    private MutableLiveData<Example> mutableWeatherData = new MutableLiveData<>();

    public WeatherDataViewModel(SavedStateHandle savedStateHandle) {
        state = savedStateHandle;
        String savedCityName = state.get("name");
        if (savedCityName != null) {
            // We already had a previously saved name, so we'll
            // start loading right away
            loadData();
        }
    }

    // This is what our Fragment will use to get the latest weather data
    public LiveData<Example> getWeatherDataLiveData() {
        return mutableWeatherData;
    }

    // When you get a new city name, we'll save that in our
    // state, then load the new data from the server
    public void setCityName(String name) {
        state.set("name", name);
        loadData();
    }

    private void loadData() {
        // Get the last name that was set
        String name = state.get("name");

        // Now kick off a load from the server
        ApiInterface apiInterface = ApiClient.getClient().create(ApiInterface.class);

        Call<Example> call = apiInterface.getWeatherData(name);

        call.enqueue(new Callback<Example>() {
            @Override
            public void onResponse(@NonNull Call<Example> call, @NonNull Response<Example> response) {
                // Save the response we've gotten
                // This will automatically update our UI
                mutableWeatherData.setValue(response.body());
            }

            @Override
            public void onFailure(@NotNull Call<Example> call, @NotNull Throwable t) {
                t.printStackTrace();
            }
        });
    }
}

推荐答案

当我最小化应用程序时,它仍然重复播放声音直到我关闭/退出应用程序.我希望它在最小化时暂停应用程序,然后从它停止的地方继续播放我回车的那一刻.

when I minimize the app, it still keeps playing the sounds on repeat until I close/exit the app. I would like it to pause when I minimize the app, then continue playing from exactly where it stopped the moment I enter back.

当片段未显示在屏幕上时,即在 onPause() 回调中,您可以暂停 mediPlayer,并在 onResume() 中恢复它.

You can pause the mediPlayer when the fragment is not shown on the screen i.e in onPause() callback, and resume it in onResume().

但是要小心,因为 mediaPlayer 不会在 onCreate() 中立即启动,因为它会等到从天气 API 获取数据;所以你需要做空能力检查:

But be careful as the mediaPlayer doesn't start immediately in onCreate() because it waits until the data is grabbed from the weather API; so you need to do null-ability check:

public void onResume() {
    super.onResume();
    if (mMediaPlayer != null)
        mMediaPlayer.start();
}

@Override
public void onPause() {
    super.onPause();
    if (mMediaPlayer != null)
        mMediaPlayer.pause();
}

附注:为了避免在进行片段事务时潜在的内存/电池泄漏,如果应用程序被破坏,应该释放 mediaPlayer 资源:

Side note: In order to avoid potential memory/battery leaks whenever you do fragment transaction, The mediaPlayer resource should be released if the application is destroyed:

@Override
public void onDestroy() {
    super.onDestroy();
    // release mMediaPlayer resoruces
    mMediaPlayer.release();
    mMediaPlayer = null;
}

但我建议将 mMediaPlayer 对象添加到 ViewModel 中,以便在手机方向等配置更改期间保存其状态.

But I would suggest to add the mMediaPlayer object into the ViewModel, in order to save its state during configuration changes like phone orientation.

这篇关于即使在最小化应用程序并在浏览片段时重新启动后,声音也会继续播放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆