How to use PreferenceFragment?
android, android-fragments, preferences
Solution
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>
Problem
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; } }; ```