Benedikt Bock
Benedikt Bock

Reputation: 1027

Android Fragments due onDestroy gets called twice, onViewStateRestored() don't work properly

I'm programming an tuner. The tuner is a fragment. My goal is to keep the tuner running when the phone switches between landscape and portrait mode. Therefore I save the actual status with onSaveInstanceState() and restore it with onViewStateRestored(). That actually works very fine. But I've one big problem: When the fragment is rebuilt onDestroy(), onCreateView() and onViewStateRestored() are executed a second time. That causes an crash. Any ideas how to fix it?

Below the code, please ask if you need more detailed code:

public class TunerFragment extends BasicFragment
{
    //View Elemente
        public boolean controlButtonUnclicked = true;
        private static final String LOG_TAG = "FFTTEST";
        private final Semaphore bufferZugriff = new Semaphore(1, true);


        //Objecte zur Aufnahme
        private int channel_config = AudioFormat.CHANNEL_IN_MONO;
        private int format = AudioFormat.ENCODING_PCM_16BIT;
        private int sampleRate = 44100;
        private int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channel_config, format)*8; // je größer der Buffer, desto genauer die FFT!!
        private AudioRecord audioInput = null; //new AudioRecord(AudioSource.MIC, sampleSize, channel_config, format, bufferSize);
        private short[] audioBuffer = new short[bufferSize];

        //Attribute zur Steuerung
        private Thread readingThread = null,writingThread=null;
        private boolean isRecording = false;




    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View view;

        view = inflater.inflate(R.layout.fragment_tuner, container, false);

        TextView tv = (TextView) view.findViewById(R.id.textview_referencenote);

        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this.getActivity());

        tv.setText(sharedPrefs.getString("value_a", "440"));

        Button mButton = (Button) view.findViewById(R.id.controlButton);
        mButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                onControlButton(v);
            }
        });
        return view;
    }

    @Override
    public void onDestroy() { 
        super.onDestroy();
        if(isRecording)
        {
            isRecording = false;
            while(this.readingThread.isAlive());

            try
            {
                audioInput.stop();
                audioInput.release();
            }
            catch (Exception e)
            {}
            while(this.writingThread.isAlive());

            audioInput= null;
            readingThread = null;
            writingThread = null;

        }
    }

    @Override
    public void onStop() {
        super.onStop();
        if(isRecording) 
        {
            isRecording = false;
            while(this.readingThread.isAlive());
            try
            {
                audioInput.stop();
                audioInput.release();
            }
            catch (Exception e)
            {}
            while(this.writingThread.isAlive());

            audioInput= null;
            readingThread = null;
            writingThread = null;

        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean("isRecording", isRecording); 
    }

    @Override
    public void onViewStateRestored (Bundle savedInstanceState) {
        super.onViewStateRestored (savedInstanceState);
        if(savedInstanceState!=null)    
        {
            if(savedInstanceState.getBoolean("isRecording"))
            {
                Button mPlayButton = (Button) getView().findViewById(R.id.controlButton);
                //Recorder starten
                controlButtonUnclicked = false;
                mPlayButton.setText("Stop");
                startRecording();
                isRecording = true;
            }
        }
    }

    public void onControlButton(View v)
    {
        //...


    }


    private void onPlay(boolean start) {
       //starts and stops the tuner, depending on the actual state

    }



    private void startRecording()
    {

        //prepares and starts the worker threads (Thread for reading the Mic.-buffer and Thread for processing the signal)
    }



    private int maxFrequenzToIndex (int MaxFreq)
    {
        return (MaxFreq * 1 * bufferSize) / (1 * sampleRate);
    }

    private void calculate()
    {
        while(isRecording)
        {
                //processing the signal ...



                //post result to main thread
                final String notennamef = notenname;
                final int differenzf=differenz;
                ((TextView) getView().findViewById(R.id.editNote)).post(new Runnable() {

                    @Override
                    public void run() {
                        try
                        {
                            TextView View = (TextView) getView().findViewById(R.id.editNote);

                            View.setText(""+notennamef); 

                            View = (TextView) getView().findViewById(R.id.editAbweichung);
                            View.setText(""+differenzf); 
                        }
                        catch (NullPointerException e)
                        {
                            System.out.println("Exception in calculate() -> run()");
                            System.out.println(e);
                        }
                    }
                });

            try
            {
                Thread.sleep(100); //Wie oft wird die Anzeige aktualisiert?
            }
            catch (InterruptedException e)
            {}
        }
        // restore neutral view
            ((TextView) getView().findViewById(R.id.editNote)).post(new Runnable() {

                @Override
                public void run() {
                    try
                     {
                            TextView View = (TextView) getView().findViewById(R.id.editNote);
                            View.setText("");



                            View = (TextView) getView().findViewById(R.id.editAbweichung);
                            View.setText("");
                     }
                     catch (NullPointerException e)
                     {
                         System.out.println("Exception in calculate() -> nach while");
                         System.out.println(e);
                     }
                }
            });
    }

    private int calculateCent(double referenz, double frequenz)
    {
        return (int) (1200*(Math.log(frequenz/referenz)/Math.log(2)));  // die Formel entspricht 1200*log2(frequenz/referenz)
    }

    private void readAudioToBuffer() 
    {
        while(isRecording)
        {

            try
            {
                bufferZugriff.acquire();
                audioInput.read(audioBuffer, 0,bufferSize);
                bufferZugriff.release();
            }
            catch (Exception e )
            {
                System.out.println("Fehler beim schreiben in den Audiobuffer");
            }

        }

     }


    private void stopRecording()
    {
        isRecording = false;
        try
        {
            audioInput.stop();
            audioInput.release();
        }
        catch (Exception e)
        {}
        audioInput= null;
        readingThread = null;
        writingThread = null;
        getView().findViewById(R.id.controlButton).setKeepScreenOn(false);
    }
}

Upvotes: 1

Views: 1797

Answers (1)

Karim Aly
Karim Aly

Reputation: 569

The problem is that when the phone switches between landscape and portrait mode the activity is recreated.

so you need to make sure on activity recreation that you don't create new fragment by overriding the activity's onCreate method like this :

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_layout);

    if (savedInstanceState == null) {
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();

        Fragment fragment = new TunerFragment();
        transaction.add(R.id.fragment_container, fragment);
        transaction.commit();
    }
}

Upvotes: 7

Related Questions