SORU
28 EYLÜL 2012, Cuma


Daha fazla anlayış setRetainİnstance(true)

Netam olarakAra ne olur setRetainInstance(true) Fragment? Belgelere neredeyse-var olmayan ve bu çok önemli bir fonksiyonu gibi görünüyor. Özellikle gerçek olduğunu bilmek istiyorum.

  1. Kullanıcı cihazı döner.
  2. Parça Activity kopuk ve Fragment.onDetach() denir.
  3. ; Activity.onDestroy() yok aktivite olarak adlandırılır.
  4. Activity java nesne silinmiş (mümkün olduğunda, GC).
  5. Activity yeni java bir nesne oluşturulur; yapıcı, ve onCreate() denir.
  6. Activity.onCreate() biz de bir düzen parçasını içeren ayarlar setContentView(...) FragmentTransaction bir parça eklemek için kullanıyoruz.
  7. Bu konuda gerçekten emin değilim, ama android eski parça bulmak için yeterince akıllı olduğunu varsayıyorum, ve Fragment.onAttach() Activity yeni dikmek için arayın
  8. (Ya da önce?" kim bilir?) Activity.onResume() denir.

Yani bu doğru mu? Android eğer ben açıkça FragmentTransaction.add(new MyFragment(), ...) ilk kez kullanıyorsanız bile eski parça bulmak için yeterince akıllı mı? Ve eğer öyleyse, nasıl eklemekten kaçınınbaşka bironCreate() parçası? Bu gibi? bir şey yapmama gerek var mı

    if (getSupportFragmentManager().findFragmentByTag("foo") == null)
    {
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.add(new FooFragment(), "foo").commit();
    }

Neden belgelerinde bu değil mi? Ha-hayır, sadece şaka cevap verme!

CEVAP
28 EYLÜL 2012, Cuma


Tamam, belki bazı yararlı bilgiler var çünkü Android belgelere göre biraz fazla sert davrandım, ama ne yazık ki hiçbiri setRetainInstance() bağlantılı. the page about fragments

Not: Her parça sistemi benzersiz bir tanımlayıcı gerekir faaliyet başlatılır parça geri yüklemek için kullanın (ve hangi işlemleri gerçekleştirmek için parça yakalamak için kullanabilirsiniz kaldırın). Bir parça için: bir KİMLİK sağlamak için üç yolu vardır

  • Android kaynağı:kimliği benzersiz bir KİMLİK ile bağlıyor.
  • Android kaynağı:etiket benzersiz bir dize özniteliği.
  • Eğer önceki iki de sağlarsanız, sistem konteyner görünümün KİMLİĞİ kullanır.

Bu kuvvetle ima yaparsan setContentView(R.layout.whatever) Activity.onCreated() ve bu düzeni içeren bir parça ile setRetainInstance(true) ne zaman faaliyettir yeniden olacak aradı tekrar kullanmadan kendi kimlik ya da etiket.

İkinci olarak, UI-daha az parça, devletler

Bir kullanıcı arabirimi olmadan bir parça eklemek, etkinlikten parça eklemek Ekle(Parça, dizi) kullanarak benzersiz bir dize "" etiket temini parça yerine bir görünüm ID). Bu parça, ama, çünkü ekler aktivite düzeni içinde bir görünüm ile ilgili değil, değil onCreateView için bir çağrı(). Bu uygulamaya gerek yok yani yöntem.

Ve dokümanlar çok iyi bir örnek için size kolaylık sağlamak için aşağıda yeniden var olan FragmentRetainInstance.java link. Soruma cevap (if (...findFragmentByTag() == null) { ...) olduğunu iddia tam olarak ne yapar.

Son olarak, işlevleri olarak tam olarak ne olduğunu görmek için kendi test etkinliği oluşturdu. Yatay, dikey ve dönme başlattığınızda bu çıkışları,. Kodu aşağıda.

(Bu daha kolay okunur hale getirmek için biraz düzenlenebilir.)

TestActivity@415a4a30: this()
TestActivity@415a4a30: onCreate()
TestActivity@415a4a30: Existing fragment not found.
TestFragment{41583008}: this() TestFragment{41583008}
TestFragment{41583008}: onAttach(TestActivity@415a4a30)
TestFragment{41583008}: onCreate()
TestFragment{41583008}: onCreateView()
TestFragment{41583008}: onActivityCreated()
TestActivity@415a4a30: onStart()
TestFragment{41583008}: onStart()
TestActivity@415a4a30: onResume()
TestFragment{41583008}: onResume()

<rotate device>

TestFragment{41583008}: onPause()
TestActivity@415a4a30: onPause()
TestFragment{41583008}: onStop()
TestActivity@415a4a30: onStop()
TestFragment{41583008}: onDestroyView()
TestFragment{41583008}: onDetach()
TestActivity@415a4a30: onDestroy()
TestActivity@415a3380: this()
TestFragment{41583008}: onAttach(TestActivity@415a3380)
TestActivity@415a3380: onCreate()
TestActivity@415a3380: Existing fragment found.
TestFragment{41583008}: onCreateView()
TestFragment{41583008}: onActivityCreated()
TestActivity@415a3380: onStart()
TestFragment{41583008}: onStart()
TestActivity@415a3380: onResume()
TestFragment{41583008}: onResume()

Android belgelerine yanlış not: UI-daha az parçayokonCreateView() çağrı alma ama null dönüş için ücretsiz.

TestActivity/TestFragment kaynak kodu

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.concentriclivers.ss.R;

// An activity for understanding Android lifecycle events.
public class TestActivity extends Activity
{
    private static final String TAG = TestActivity.class.getSimpleName();

    public TestActivity()
    {
        super();
        Log.d(TAG, this   ": this()");
    }

    protected void finalize() throws Throwable
    {
        super.finalize();
        Log.d(TAG, this   ": finalize()");
    }

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        Log.d(TAG, this   ": onCreate()");


        TextView tv = new TextView(this);
        tv.setText("Hello world");
        setContentView(tv);

        if (getFragmentManager().findFragmentByTag("test_fragment") == null)
        {
            Log.d(TAG, this   ": Existing fragment not found.");
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.add(new TestFragment(), "test_fragment").commit();
        }
        else
        {
            Log.d(TAG, this   ": Existing fragment found.");
        }
    }

    @Override
    public void onStart()
    {
        super.onStart();
        Log.d(TAG, this   ": onStart()");
    }

    @Override
    public void onResume()
    {
        super.onResume();
        Log.d(TAG, this   ": onResume()");
    }

    @Override
    public void onPause()
    {
        super.onPause();
        Log.d(TAG, this   ": onPause()");
    }

    @Override
    public void onStop()
    {
        super.onStop();
        Log.d(TAG, this   ": onStop()");
    }

    @Override
    public void onDestroy()
    {
        super.onDestroy();
        Log.d(TAG, this   ": onDestroy()");
    }




    public static class TestFragment extends Fragment
    {
        private static final String TAG = TestFragment.class.getSimpleName();

        public TestFragment()
        {
            super();
            Log.d(TAG,  this   ": this() "   this);
        }

        @Override
        public void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            Log.d(TAG, this   ": onCreate()");
            setRetainInstance(true);
        }

        @Override
        public void onAttach(final Activity activity)
        {
            super.onAttach(activity);
            Log.d(TAG, this   ": onAttach("   activity   ")");
        }

        @Override
        public void onActivityCreated(Bundle savedInstanceState)
        {
            super.onActivityCreated(savedInstanceState);
            Log.d(TAG, this   ": onActivityCreated()");
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
            Log.d(TAG, this   ": onCreateView()");
            return null;
        }

        @Override
        public void onViewCreated(View view, Bundle savedInstanceState)
        {
            super.onViewCreated(view, savedInstanceState);
            Log.d(TAG, this   ": onViewCreated()");
        }

        @Override
        public void onDestroyView()
        {
            super.onDestroyView();
            Log.d(TAG, this   ": onDestroyView()");
        }

        @Override
        public void onDetach()
        {
            super.onDetach();
            Log.d(TAG, this   ": onDetach()");
        }

        @Override
        public void onStart()
        {
            super.onStart();
            Log.d(TAG, this   ": onStart()");
        }

        @Override
        public void onResume()
        {
            super.onResume();
            Log.d(TAG, this   ": onResume()");
        }

        @Override
        public void onPause()
        {
            super.onPause();
            Log.d(TAG, this   ": onPause()");
        }

        @Override
        public void onStop()
        {
            super.onStop();
            Log.d(TAG, this   ": onStop()");
        }

        @Override
        public void onDestroy()
        {
            super.onDestroy();
            Log.d(TAG, this   ": onDestroy()");
        }
    }

}

FragmentRetainInstance.java kaynak kodu (API 16):

/*
 * 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.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 {
    @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.
            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.
            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();
            }
        }
    }
}

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • akalyne

    akalyne

    13 Mayıs 2009
  • audivila

    audivila

    5 HAZİRAN 2009
  • boburnham

    boburnham

    11 Temmuz 2006