ApiDemo/FragmentRetainInstance parsing, androidapidemo

Source: Internet
Author: User

ApiDemo/FragmentRetainInstance parsing, androidapidemo

/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.example.android.apis.app;import com.example.android.apis.R;import android.app.Activity;import android.app.Fragment;import android.app.FragmentManager;import android.os.Bundle;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.ProgressBar;/** * This example shows how you can use a Fragment to easily propagate state * (such as threads) across activity instances when an activity needs to be * restarted due to, for example, a configuration change.  This is a lot * easier than using the raw Activity.onRetainNonConfiguratinInstance() API. */public class FragmentRetainInstance extends Activity {private static String TAG="FragmentRetainInstance";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);                // First time init, create the UI.        if (savedInstanceState == null) {            getFragmentManager().beginTransaction().add(android.R.id.content,                    new UiFragment()).commit();        }    }    /**     * This is a fragment showing UI that will be updated from work done     * in the retained fragment.     */    public static class UiFragment extends Fragment {        RetainedFragment mWorkFragment;        @Override        public View onCreateView(LayoutInflater inflater, ViewGroup container,                Bundle savedInstanceState) {            View v = inflater.inflate(R.layout.fragment_retain_instance, container, false);            // Watch for button clicks.            Button button = (Button)v.findViewById(R.id.restart);            button.setOnClickListener(new OnClickListener() {                public void onClick(View v) {                    mWorkFragment.restart();                }            });            return v;        }        @Override        public void onActivityCreated(Bundle savedInstanceState) {            super.onActivityCreated(savedInstanceState);            FragmentManager fm = getFragmentManager();            // Check to see if we have retained the worker fragment.            mWorkFragment = (RetainedFragment)fm.findFragmentByTag("work");            // If not retained (or first time running), we need to create it.            if (mWorkFragment == null) {                mWorkFragment = new RetainedFragment();                // Tell it who it is working with.                mWorkFragment.setTargetFragment(this, 0);                fm.beginTransaction().add(mWorkFragment, "work").commit();            }        }    }    /**     * This is the Fragment implementation that will be retained across     * activity instances.  It represents some ongoing work, here a thread     * we have that sits around incrementing a progress indicator.     */    public static class RetainedFragment extends Fragment {        ProgressBar mProgressBar;        int mPosition;        boolean mReady = false;        boolean mQuiting = false;        /**         * This is the thread that will do our work.  It sits in a loop running         * the progress up until it has reached the top, then stops and waits.         */        final Thread mThread = new Thread() {            @Override            public void run() {                // We'll figure the real value out later.                int max = 10000;                // This thread runs almost forever.                while (true) {                    // Update our shared state with the UI.                    synchronized (this) {                        // Our thread is stopped if the UI is not ready                        // or it has completed its work.                        while (!mReady || mPosition >= max) {                            if (mQuiting) {                                return;                            }                            try {                                wait();                            } catch (InterruptedException e) {                            }                        }                        // Now update the progress.  Note it is important that                        // we touch the progress bar with the lock held, so it                        // doesn't disappear on us.                        mPosition++;                        max = mProgressBar.getMax();                        mProgressBar.setProgress(mPosition);                    }                    // Normally we would be doing some work, but put a kludge                    // here to pretend like we are.                    synchronized (this) {                        try {                            wait(50);                        } catch (InterruptedException e) {                        }                    }                }            }        };        /**         * Fragment initialization.  We way we want to be retained and         * start our thread.         */        @Override        public void onCreate(Bundle savedInstanceState) {            super.onCreate(savedInstanceState);                        // Tell the framework to try to keep this fragment around            // during a configuration change.            setRetainInstance(true);                        // Start up the worker thread.            mThread.start();        }        /**         * This is called when the Fragment's Activity is ready to go, after         * its content view has been installed; it is called both after         * the initial fragment creation and after the fragment is re-attached         * to a new activity.         */        @Override        public void onActivityCreated(Bundle savedInstanceState) {            super.onActivityCreated(savedInstanceState);                        // Retrieve the progress bar from the target's view hierarchy.            mProgressBar = (ProgressBar)getTargetFragment().getView().findViewById(                    R.id.progress_horizontal);                        // We are ready for our thread to go.            synchronized (mThread) {                mReady = true;                mThread.notify();            }        }        /**         * This is called when the fragment is going away.  It is NOT called         * when the fragment is being propagated between activity instances.         */        @Override        public void onDestroy() {            // Make the thread go away.        Log.d(TAG, "onDestroy");            synchronized (mThread) {                mReady = false;                mQuiting = true;                mThread.notify();            }                        super.onDestroy();        }        /**         * This is called right before the fragment is detached from its         * current activity instance.         */        @Override        public void onDetach() {            // This fragment is being detached from its activity.  We need            // to make sure its thread is not going to touch any activity            // state after returning from this function.        Log.d(TAG, "onDetach");            synchronized (mThread) {                mProgressBar = null;                mReady = false;                mThread.notify();            }            super.onDetach();        }        /**         * API for our UI to restart the progress thread.         */        public void restart() {            synchronized (mThread) {                mPosition = 0;                mThread.notify();            }        }    }}
 

This small example has two key points:

1. Save the status through Fragment. The Fragment associated with the Activity is also destroyed when the Activity is destroyed. Related Fragment is automatically created when the Activity is rebuilt. Therefore, the onCreate function of the Activity often determines whether the savedInstanceState is null (when the Activity has an associated Fragment, the savedInstanceState is not empty when the Activity is rebuilt) to avoid repeated Fragment creation. The reconstructed Fragment and the previous Fragment are two different objects. However, if setRetainInstance (true) is called for Fragment, the Fragment will be retainment (onDetach will be called) when the Activity is destroyed (the activity is destroyed due to changes in settings, such as horizontal and vertical screen switching, onDestroy will not be called), and the Fragment will continue to be associated during Activity reconstruction. That is, the Fragment obtained through FragmentManager is still the previous Fragment. This property of Fragment can be used to save the Activity status. Compared with the onSaveInstance or onRetainNonConfiguratinInstance () method, it is convenient to save the status through Fragment. Especially for large objects such as Bitmap or objects that are not easily serialized (such as thread objects in this example ). The Fragment used to save the status generally does not have a view (onCreateView returns null), but TargetFragment can be set to obtain TargetFragment and update the UI of TargetFragment.
2. How to Avoid background threads updating the UI during Activity destruction.
In this example, the thread is still executing during activity destruction, and the progress bar may be changed during the thread execution. However, the UI has been destroyed.
In this example, set mReady to false in onDetach to avoid updating the progress bar.
At the same time, the mutex lock is obtained when the progress bar is updated to prevent UI resources from being recycled when the progress bar is updated.
 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.