How to use PreferenceFragment?

10,981

I'm using a rather simple way of doing it, so here's basically a copy/paste from one of my projects - hopefully you can use it. You'll obviously need to replace some parts with your own stuff, i.e. the preferences, strings, namespace and such :-)

Show preference screen:

startActivity(new Intent(getApplicationContext(), Preferences.class));

Preferences class:

import java.util.List;

import android.os.Bundle;
import android.preference.PreferenceActivity;

public class Preferences extends PreferenceActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onBuildHeaders(List<Header> target) {       
        loadHeadersFromResource(R.xml.preference_headers, target);
    }

}

Prefs class:

import android.os.Bundle;
import android.preference.PreferenceFragment;

public class Prefs extends PreferenceFragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        int res=getActivity().getResources().getIdentifier(getArguments().getString("resource"), "xml", getActivity().getPackageName());
        addPreferencesFromResource(res);
    }

}

preference_headers.xml (in res/xml):

You'll need a header listing for each preference screen (fragment).

<preference-headers xmlns:android="http://schemas.android.com/apk/res/android" >

    <header
        android:fragment="com.miz.mizuu.Prefs"
        android:icon="@drawable/search"
        android:title="@string/prefsIdentificationAndSearch" >
        <extra
            android:name="resource"
            android:value="preferences" />
    </header>
    <header
        android:fragment="com.miz.mizuu.Prefs"
        android:icon="@drawable/apptheme"
        android:title="@string/prefsUI" >
        <extra
            android:name="resource"
            android:value="preferences2" />
    </header>

</preference-headers>

preferences.xml, preferences2.xml, etc. (in /res/xml):

You'll need separate preference xml files for each of the referenced "extras" in preference_headers.xml. This means that the code above relies on preferences.xml and preferences2.xml.

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >

    <PreferenceCategory android:title="@string/prefsIdentification" >
        <CheckBoxPreference
            android:defaultValue="false"
            android:icon="@drawable/localizedinfo"
            android:key="prefsUseLocalData"
            android:summary="@string/prefsUseLocalDataDescription"
            android:title="@string/prefsUseLocalDataTitle" >
        </CheckBoxPreference>
    </PreferenceCategory>

</PreferenceScreen>
Share:
10,981
Andres
Author by

Andres

Electronics engineer with a passion for web development and embedded systems. Experience in high-level and low-level programming and hardware design!

Updated on June 04, 2022

Comments

  • Andres
    Andres about 2 years

    i am trying to use PreferenceFragment calling it from an Activity when i click an icon from my ActionBar, I simply call the FragmentPreferences whit Intent:

    case R.id.settings:
        Intent prefs = new Intent(this, LogicAnalizerPrefs.class);
        startActivity(prefs);
        break;
    

    On this way when i click my icon the application simple stucks, i mean it doesnt crash and nothing strange on LogCat simple stucks and if i click again i get ANR. If i use instead:

    getFragmentManager().beginTransaction().replace(android.R.id.content, new LogicAnalizerPrefs()).commit();
    

    I can see the Fragment but the background is transparent, i have seen some user asking whit the same problem but the answer is calling the whit Intent but my application stucks. Here is my Fragment code:

    public class LogicAnalizerPrefs extends PreferenceFragment {
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.logicanalizerprefs);
        }
    
    }
    

    And my logicanalizerprefs.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
    
        <EditTextPreference
            android:defaultValue="128"
            android:key="buffer1"
            android:summary="Buffer canal 1"
            android:title="Buffer" />
        <EditTextPreference
            android:defaultValue="128"
            android:key="buffer2"
            android:summary="Buffer canal 2"
            android:title="Buffer" />
        <EditTextPreference
            android:defaultValue="128"
            android:key="buffer3"
            android:summary="Buffer canal 3"
            android:title="Buffer" />
        <EditTextPreference
            android:defaultValue="128"
            android:key="buffer4"
            android:summary="Buffer canal 4"
            android:title="Buffer" />
    
    </PreferenceScreen>
    

    Hope you can help me i dont have any idea what can it be :/

    --EDIT-- It is the Activity from which i am calling my Preference Activity/Fragment, it uses achartengine and implemments a Runnable Thread to refresh the chart on the Handler.

    public class LogicAnalizerView extends Activity implements Runnable{
    
        /** Debugging */
        private static final boolean DEBUG = false;     String TAG;
        /** Varios */
        static ActionBar actionBar;         // ActionBar
        static Thread myThread = null;      // Thread para el metodo run() de Runnable
        static boolean Running;             // Ejecuta o no el while dentro de run()
        static Random crazy = new Random(); // Clase Random para generar numeros aleatorios
        /** Tiempo en el eje X */
        static float time = (float) 0.0;    // Tiempo transcurrido (eje X del grafico)
        static final float TimeIncrement = (float) 0.4;     // Tiempo que transcurre por muestreo (duracion de un 1-0)
        static final int XMax = 10;         // Valor maximo de X inicial
        static final int XMin = 0;          // Valor minimo de X inicial
        static int Ticks = 0;               // Veces que el grafico se actualiza
        static final int maxTicks = (int) (XMax/TimeIncrement);     // Cantidad de '1' y '0' que entran en el intervalo [XMin,XMax]
        /** Buffers */
        static int BufferSize;              // Tamaño del buffer de recepcion
        static byte[] ReceptionBuffer;      // Buffer de recepcion
        static byte[] Channel1;             // Buffers para cada canal
        static byte[] Channel2;
        static byte[] Channel3;
        static byte[] Channel4;
    
        //Lineas en el grafico
        TimeSeries[] input = new TimeSeries[4]; // Cada TimeSeries representa una funcion en el grafico
        XYMultipleSeriesDataset dataset;        // Agrupa todas las TimeSeries en el grafico
        //Renderers
        XYSeriesRenderer renderer;              // Opciones de renderizado para cada TimeSeries
        XYSeriesRenderer renderer1;
        XYSeriesRenderer renderer2;
        XYSeriesRenderer renderer3;
        XYMultipleSeriesRenderer mRenderer;     // Agrupa todas las opciones de renderizado del grafico
        //GraphicalView
        GraphicalView mChartView;               // View del grafico (el grafico en si)
    
        /**
         * Creacion de la Activity
         */
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            /**
             * ActionBar
             */
            actionBar = getActionBar();                     // Obtengo el ActionBar
            actionBar.setDisplayHomeAsUpEnabled(true);      // El icono de la aplicacion funciona como boton HOME
    
            /**
             * Preferencias
             */
            SharedPreferences getPrefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
            Channel1 = new byte[Integer.decode(getPrefs.getString("buffer1", "128")) + 1];      // Tamaño de los buffers de cada canal basado en 
            Channel2 = new byte[Integer.decode(getPrefs.getString("buffer2", "128")) + 1];      // la configuracion +1 porque en el buffer[0] se coloca
            Channel3 = new byte[Integer.decode(getPrefs.getString("buffer3", "128")) + 1];      // el tipo de protocolo (I2C, SPI, UART, etc)
            Channel4 = new byte[Integer.decode(getPrefs.getString("buffer4", "128")) + 1];
            ReceptionBuffer = new byte[64];     // Buffer de recepcion general de 64 bytes
    
            /**
             * Configuro el grafico
             */
            //Crea una "Serie" que es una linea en el grafico llamado "Linea1"
            input[0] = new TimeSeries("Entrada 1");
            input[1] = new TimeSeries("Entrada 2");
            input[2] = new TimeSeries("Entrada 3");
            input[3] = new TimeSeries("Entrada 4");
    
            //XYMultipleSeriesDataset contiene todas las series, es decir todas las lineas del grafico en esta clase
            dataset = new XYMultipleSeriesDataset();
            dataset.addSeries(input[0]);    // Agregamos la serie que creamos a XYMultipleSeriesDataset que contiene todas las series
            dataset.addSeries(input[1]);
            dataset.addSeries(input[2]);
            dataset.addSeries(input[3]);
    
            //XYMultipleSeriesRenderer contiene todos los renderer de las diferentes series
            //XYSeriesRenderer le da las propiedades a las Series (lineas) como color y esas cosas
            mRenderer = new XYMultipleSeriesRenderer();
            renderer = new XYSeriesRenderer();
            renderer1 = new XYSeriesRenderer();
            renderer2 = new XYSeriesRenderer();
            renderer3 = new XYSeriesRenderer();
    
            //Renderers
            mRenderer.addSeriesRenderer(renderer);      // Agrego el XYSeriesRenderer al grupo XYMultipleSeriesRenderer
            mRenderer.addSeriesRenderer(renderer1);
            mRenderer.addSeriesRenderer(renderer2);
            mRenderer.addSeriesRenderer(renderer3);
            mRenderer.setShowGrid(true);                // Muestra una grilla en X e Y en el grafico
            mRenderer.setYTitle("Canales");             // Titulo del eje Y
            mRenderer.setYLabelsAlign(Align.CENTER);    // Alineacion del titulo
            mRenderer.setXTitle("Tiempo x100nS");       // Titulos del eje X
            mRenderer.setXLabelsAlign(Align.CENTER);    // Alineacion del titulo
            mRenderer.setZoomButtonsVisible(true);      // Botones de Zoom visibles
            mRenderer.setZoomEnabled(true, false);      // Zoom sobre el eje X solamente
            mRenderer.setAntialiasing(true);            // Usa antialising para dibujar
            mRenderer.setXAxisMin(XMin);                // Valor minimo del eje X
            mRenderer.setXAxisMax(XMax);                // Valor maximo del eje X
    
            //Colores de lineas
            renderer.setColor(Color.WHITE);     
            renderer1.setColor(Color.RED);
            renderer2.setColor(Color.GREEN);
            renderer3.setColor(Color.YELLOW);
    
            //Grosores de lineas
            renderer.setLineWidth(2);
            renderer1.setLineWidth(3);
            renderer2.setLineWidth(4);
            renderer3.setLineWidth(5);
    
            mChartView = ChartFactory.getLineChartView(this, dataset, mRenderer);
            setContentView(mChartView);
    
        }
    
        /**
         * Crea el ActionBar
         */
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            if(DEBUG) Log.i(TAG, "onCreateOptionsMenu() -> LogicAnalizerView");
            MenuInflater inflater = getMenuInflater();
            inflater.inflate(R.menu.actionbarmain, menu);
            return true;
        }
    
        /**
         * Listener de los iconos en el ActionBar
         */
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            if(DEBUG) Log.i(TAG, "onOptionsItemSelected() -> LogicAnalizerView - Item: " + item.getItemId());
    
            switch(item.getItemId()){
            case android.R.id.home:
                Intent intent = new Intent(this, MainMenu.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); //si la aplicacion ya esta abierta ir a ella no abrir otra nueva
                startActivity(intent);
            case R.id.settings:
                Intent a = new Intent(this, MainMenu.class);
                a.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startActivity(a);
                //Intent prefs = new Intent(getApplicationContext(), LogicAnalizerPrefs.class);
                //startActivity(prefs);
                break;
            case R.id.save:
                createDialog();
                break;
            }
            return true;
        }
    
        /**
         * Crea una ventana perguntando al usuario el nombre con el que desea guardar la imagen del grafico
         */
        private void createDialog() {
            Running = false;    //Detengo el Thread run()
            AlertDialog.Builder alert = new AlertDialog.Builder(this);
            alert.setTitle("Guardar");
            alert.setMessage("Nombre de archivo");
    
            // Creamos un EditView para que el usuario escriba
            final EditText input = new EditText(this);
            alert.setView(input);
    
            // Creamos el boton OK y su onClickListener
            alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                    Editable text = input.getText();        // Obtengo el texto que escribio el usuario
                    Bitmap bitmap = mChartView.toBitmap();  // Creo un nuevo BitMap
    
                    try {   //Creo un nuevo archivo con el nombre del usuario y extension .jpeg
                        File image = new File(Environment.getExternalStorageDirectory(), "Multi\\" + text.toString() + ".jpeg");
                        if(image.exists()){
                            createDialogConfirm();
                        }
                        FileOutputStream output = new FileOutputStream(image);
                        bitmap.compress(CompressFormat.JPEG, 100, output);
                    } catch (FileNotFoundException e) { e.printStackTrace(); }
                    Running = true;
                }
    
            });
    
            // Boton cancelar
            alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
              public void onClick(DialogInterface dialog, int whichButton) {
                  dialog.dismiss();
                  Running = true;         
              }
            });
            alert.show();
        }
    
        private boolean createDialogConfirm() {
            AlertDialog.Builder confirm = new AlertDialog.Builder(this);
            confirm.setTitle("Guardar");
            confirm.setMessage("El archivo existe, sobreescribir ?");
    
            // Boton cancelar
            confirm.setPositiveButton("Si", new DialogInterface.OnClickListener() {
              public void onClick(DialogInterface dialog, int whichButton) {      
              }
            });
    
            // Boton cancelar
            confirm.setNegativeButton("No", new DialogInterface.OnClickListener() {
              public void onClick(DialogInterface dialog, int whichButton) {
                  dialog.dismiss();   
              }
            });
    
            confirm.show();
            return true;
        }
    
        /**
         * Prueba de byte
         * @param a: byte para testear
         * @param bit: numero de bit a testear 0-7
         */
        public boolean bitTest (byte a, int bit) {
            return (a & (1 << bit)) != 0;
        }
    
        /**
         * @author Andres
         * Se llama al crear la Activity y al volver a ella si se ha salido, aqui creamos el Thread run() y lo iniciamos, a su vez seteamos
         * el item del DropDown menu del ActionBar a la aplicacion actual.
         * @see http://developer.android.com/reference/android/app/Activity.html
         */
        @Override
        protected void onResume() {
            super.onResume();
            //Creo el Thread y lo inicio
            Running = true;
            myThread = new Thread(this);
            myThread.start();
        }
    
        /**
         * @author Andres
         * Cuando se pausa la Activity se elimina el Thread run() para liberar recursos ya que no sera usado y se lo iguala a null para
         * no provocar un error si por accidente se intenta usarlo
         */
        @Override
        protected void onPause() {
            super.onPause();
            //destruyo el Thread
            Running = false;
            try {
                myThread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myThread = null;    //pongo el Thread como null para no provocar errores
        }
    
        /**
         * @author Andres
         * Lee cada aproximadamente 500mS los datos que se tienen del analizador logico y los muestra en el grafico llamando a un Handler
         * debido a que el grafico debe ser actualizado desde el Main Thread.
         * @see "private Handler uiCallback = new Handler ()" debajo.
         */
        @Override
        public void run() {
    
            while(true){
                while(Running){
    
                    if(DEBUG) Log.i(TAG, "run() -> LogicAnalizerView");
                    uiCallback.sendEmptyMessage(0);
                    if(DEBUG) Log.i(TAG, "run() -> LogicAnalizerView - Thread.sleep()");
    
                    try { Thread.sleep(500); }
                    catch (InterruptedException e) { e.printStackTrace(); }
                }
    
            try { Thread.sleep(500); }
            catch (InterruptedException e) { e.printStackTrace(); }
    
            }
    
        }
    
        /** 
         * @author Andres
         * Los Handlers ejecutan sus operaciones en el Thread de la UI haciendo posible la modificacion de la misma desde Threads no UI.
         * @see http://developer.android.com/guide/topics/fundamentals/processes-and-threads.html
         * @see http://developer.android.com/reference/android/os/Handler.html
         */
        private Handler uiCallback = new Handler () {
            public void handleMessage (Message msg) {
                Running = false;
                if(DEBUG) Log.i(TAG, "XAxisMax: " + mRenderer.getXAxisMax() + " Time: " + time + " Ticks: " + Ticks);
                if(DEBUG) Log.i(TAG, "XAxisMin: " + mRenderer.getXAxisMin());
                final int[] factor = {0, 2, 4, 6};  // Valores tomados como 0 logicos
    
                // Si hay datos listos
                if(USBMulti.isLogicAnalizerDataRdy()){
                    ReceptionBuffer = USBMulti.getLogicAnalizerData();      // Obtengo los datos desde el USB
                }
    
                // Si los bit son 1 le sumo 1 a los valores tomados como 0 logicos
                for(int n=0; n < ReceptionBuffer.length; ++n){              // Voy a traves de los bytes recibidos
                    for(int bit=0; bit < 4; ++bit){     // Voy a traves de los 4 bits de cada byte
                        if(bitTest(ReceptionBuffer[n],bit)){
                            input[bit].add(time, factor[bit]+1);    
                        }
                        else{
                            input[bit].add(time, factor[bit]);
                        }
                    }
                    time += TimeIncrement;              // Incremento el tiempo
                    ++Ticks;                            // Incremento ticks
                    //Si llego al maximo del cuadro (borde derecho) aumento el maximo y el minimo para dibujar un tiempo mas
                    //(desplazamiento del cuadro) de esta manera si deslizamos el cuadro horizontalmente tendremos los datos
                    if(Ticks >= maxTicks){
                        mRenderer.setXAxisMax(mRenderer.getXAxisMax()+TimeIncrement);
                        mRenderer.setXAxisMin(mRenderer.getXAxisMin()+TimeIncrement);
                    }
                }
    
                if(DEBUG) Log.i(TAG, "uiCallback -> LogicAnalizerView - mChartView.repaint()");
                if(mChartView != null) mChartView.repaint();    // Redibujo el grafico
                Running = true;
            }
        };
    
  • Andres
    Andres about 12 years
    It is the same whit PreferenceActivity it stucks :/ And i need to use Fragments because later i need to use something like this: developer.android.com/reference/android/preference/…
  • Andres
    Andres about 12 years
    Same issue my application stucks :/ Could it be Android Emulator ? :/ I have made preferences screen before in Android 2.3 and i was not having this problems
  • Michell Bak
    Michell Bak about 12 years
    Nope, the above code works just fine in an emulator as well. If you don't mind, please update your question with the exact code you're using. It's important that you have both a class that extends PreferenceActivity AND a fragment class that extends PreferenceFragment. Also, is it just stuck or does Logcat show anything?
  • Andres
    Andres about 12 years
    I am not using PreferenceActivity just Activity and LogCat does not show anything, but i have just seen something interesting, i cannot call ANY Intent from my Activity everything stuck it. I edited my question whit my Activity code. Thanks you :)
  • Michell Bak
    Michell Bak about 12 years
    Please try to add preferences.java and prefs.java from my answer to your project, modify them to your needs and don't forget to add them to your manifest file. It really is quite a simple example and it works just fine.
  • Andres
    Andres about 12 years
    Yes, but the problem is not your sample, it works ok :D The problem is i cannot call any other Intent from my Activity :)
  • Michell Bak
    Michell Bak about 12 years
    Last time I checked, the problem was regarding PreferenceFragments :-) Anyway, I'm not sure if you can implement Runnable like that in your main class. Maybe that's the root of your problems.
  • Andres
    Andres about 12 years
    Yes, sorry the problem was that but i recently discovered i cannot call any Intent not only whit preferences :) My main class is a ListActivity from which i select my differents Activities. You say my problem could be Runnable ?
  • Andres
    Andres about 12 years
    You are right, I have eliminated Runnable and it works perfectly and your example too. How should i implemment Runnable or what i can use instead ?
  • Michell Bak
    Michell Bak about 12 years
    You can use a Handler and a Runnable to achieve that, but don't let the class implement Runnable. Here's a good example: stackoverflow.com/questions/1921514/…
  • Andres
    Andres about 12 years
    Thank you very much i will try that :) which is the main difference between using a Thread whit run and implementing runnable ?
  • Michell Bak
    Michell Bak about 12 years
    There really isn't much of a difference. Not for your project anyway :-)
  • slinden77
    slinden77 almost 11 years
    you can actually load a specific Fragment from an Intent. stackoverflow.com/questions/13672487/…