Usuario:ManuelRomero/Android2/Interfaz
Contenido
- 1 Descripción general de la aplicación y programa principal
- 1.1 Qué es un ListActivity
- 1.2 1.2      Combinando con más componentes View
- 1.3 1.3Â Â Â Â Primera actividad : Ciclo de vida
- 1.4 1.4Â Â Â Â Segunda actividad : SingleTouch
- 1.5 1.5Â Tercera actividad : MultiTouch
- 1.6 1.6Â Cuarta actividad: el Teclado
- 1.7 1.7 Quinta actividad Acelerómetro
- 1.8 1.8Â Sexta actividad: Assets
- 1.9 1.9      Septima actividad  AlmacenamientoExterno
- 1.10 1.10Â Â Â Â Â Â Â Â Â Â Â Â Â "Sonido"
- 1.11 1.11Â Â Â Â Â Â Â Â Â Â Â Â Â "Video",
- 1.12 1.12Â Â Â Â Â Â Â Â Â Â Â Â Â "Ventana Completa",
- 1.13 1.13Â Â Â Â Â Â Â Â Â Â Â Â Â "RenderView",
- 1.14 1.14Â Â Â Â Â Â Â Â Â Â Â Â Â "image",
- 1.15 1.15Â Â Â Â Â Â Â Â Â Â Â Â Â "Bitmap",
- 1.16 1.16Â Â Â Â Â Â Â Â Â Â Â Â Â "Fuente"
- 1.17 1.17Â "SurfaceView"
Descripción general de la aplicación y programa principal
Realizaremos una pequeña api en android para ver diferentes funcionalidades.
Para ello la actividad principal nos visualizará las diferentes funcionalidades en una lista y se encargará de invocar a cada una de ellas cuando la seleccionemos
A continuación una lista a priori de las funcionalidades que queremos realizar
- "CicloVida",
- "SingleTouch",
- "MultiTouch",
- "Teclas",
- "Acelerómetro",
- "Asset",
- "AlmacenamientoExterno",
- "Sonido",
- "Video",
- "Ventana Completa",
- "RenderView",
- "image",
- "Bitmap",
- "Fuente"
- "SurfaceView"
En el programa principal usaremos un ListActivity.
Qué es un ListActivity
Es una clase que extiende de Activity y está especializada en trabajar con listas.
Es una actividad que muestra una lista de elementos cuyos valores se toman de algún origen de datos como una matriz o un cursor, y nos ofrece los controles de eventos cuando el usuario selecciona un elemento.
La propia clase implementa un layout contenedor que contiene un ListView, por lo que no necesitamos declararlo, ni asociar la actividad con ningún layout.
Esto implica que dentro de la activdad principal ListActivity, no necesitamos usar el callback SetContentView(..)
ListView
Un ListView es una clase que pertenece al grupo de ViewGroup (view contenedores) que tienen alguna funcionalidad añadida que le permite al usuario interactuar con ella.
Otras clases de este tipo (Gallery, GridView, ImageSwitcher, ScrollView, TabHost) .
Muestra una serie de View como una lista, otorgando al usuario la capacidad de navegar entre ellos utilizando la caracterÃstica de desplazamiento vertical.
Para obtener los datos del array o cursor y asociarlos al ListView necesitamos un la clase Adapter
Debemos definir un Adapter(ArrayAdapter, CursorAdapter o SimpleCursorAdapter), para asignar al ListView de la ListActivity los valores que queramos visualizar. Para ello debemos usar el método setAdapter() de la clase ListView o como en el caso de nos ocupa usar el método setListAdapter de la clase ListAdapter
ArrayAdapter adaptadorValores;
adaptadorValores=newArrayAdapter<String>( this,
android.R.layout.simple_list_item_1,
aplicaciones
)
Vemos tres parámetros al construir el ArrayAdapter
ü this è Es el context de la actividad, es decir la propia actividad
ü android.R.layout.simple_list_item_1 è Es un layout predefinido que incorpora un ListView con el id android:list para incorporar en una lista de valores
ü aplicaciones è Es la lista de valores
Para asignar al ListView del ListActivity los valores que queremos visualizar, en este caso el contenido de la variable aplicaciones, invocamos al método setListAdapter y le pasamos el adapter previamente definido
setListAdapter(adaptadorValores);
1.1.2    Gestionando eventos de selección
La clase ListActivity tiene un método protegido onListItemClick() el cual es invocado al seleccionar un elemento.
@Override
protected void onListItemClick(ListView valores, View vista, int pos, long id){
super.onListItemClick(valores, vista, pos, id);
. . .
. . .
}
Este método recibe 4 parámetros
Ø valores è Es el contenedor ListView que contiene la lista de view donde ha ocurrido el evento
Ø vista è es el view del listView que ha sido cliqueado
Ø pos è es la posición en el vector del elemento del ListView seleccionado
Ø id è el id de la fila que ha sido seleccionada
Lo primero que debemos hacer es invocar al método del la clase ListActivity
Y ahora lo que queremos es que se invoque a la clase que realice la acción seleccionada
Para ello usaremos un Intent, como ya sabemos. El nombre de la clase será el contenido del texto del elemento seleccionado. El código que habla por sà sólo quedará como sigue:
. . .
String app = aplicaciones[pos];
try{
Class accion = Class.forName("com.example.api_juegos."+app);
Intent i =new Intent(this,clase);
startActivity(i);
}catch(ClassNotFoundException e){
e.printStackTrace();
}
1.2      Combinando con más componentes View
Si queremos más controles View entonces sà que nos creamos un layout para ello; En este caso debemos definir también un ListView con el identificador android:id=â€@android:listâ€
Podemos usar un TextView identificado @android:id/empty y si la lista está vacÃa se mostrará el contenido de este TextView.
package com.example.api_juegos;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class Api extends ListActivity {
String aplicaciones []={
"CicloVida",
"SingleTouch",
"MultiTouch",
"Key",
"Acelerómetro",
"Asset",
"Almacenamiento Externo",
"Sonido",
"Video",
"Ventana Completa",
"RenderView",
"Shape",
"Bitmap",
"Fuente",
"SurfaceView"};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("DEBUGANDI","Antes de setListAdapter");
setListAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,aplicaciones));
}
@Override
protected void onListItemClick(ListView valores, View vista, int pos, long id){
super.onListItemClick(valores, vista, pos, id);
String app = aplicaciones[pos];
try{
Class clase = Class.forName("com.example.api_juegos."+app);
Intent i =new Intent(this,clase);
startActivity(i);
}catch(ClassNotFoundException e){
e.printStackTrace();
}
}
Concepto de Listas ListView Adaptar (ArrayAdapter) y método Adapter.setAdaptaer
ListView vistaLista = (ListView)findViewById(R.id.listaActividades);
Log.i("DEBUGANDO", "he llamado al super de oncreate");
Log.i("DEBUGANDO", "definido vistaLista");
ArrayAdapter <String> listaAdaptada = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,aplicaciones);
Log.i("DEBUGANDO", "Hecho arrayAdapter");
vistaLista.setAdapter(listaAdaptada);
Log.i("DEBUGANDO", "adaptada lista");
ListView è es un View que muestra cada control View como un elemento de una lista otorgando al usuario la capacidad de navegar entre ellos utilizando la caracterÃstica de desplazamiento vertical.
Adapter è es un objeto que va a leer datos de alguna fuente y va a genera datos para un control ListView,. Las clases Adapter más comunes son
ArrayAdapter è Los datos los cojo de un array
CursorAdapterè Los datos los cojo de una base de datos como resultado de una consulta
AdapterViewè Un conjunto de controles View que muestran datos de alguna fuente
O usar directamente una subclase ListActivity que ya está preparada para visualizar con un ListView como en el ejemplo
1.3Â Â Â Â Primera actividad : Ciclo de vida
Nuestra primera actividad de nuestro api es mostrar un ciclo de vida de una actividad.
En el wiki tenemos una pequeña explicación de los estados en los que se puede encontrar una actividad, y los métodos que se ejecutan al pasar de un estado a otro
Esta imagen está en la página de developer de android. La siguiente muestra los estados de las actividades
Se pretende que me muestre el estado en el que se encuentra la actividad y el instante en el que se ha producido.
La actividad debe mostrar el estado en el que se encuentra y el instante en el que se pasó a esa actividad.
Una posible idea es tener un método información al que le pasamos el nombre del estado y nos visualizará dicho string junto con el instante de tal acción
package com.example.api_juegos;
import java.text.SimpleDateFormat;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class CicloVida extends Activity{
StringBuilder builder = new StringBuilder();
TextView texto;
long fecha;
SimpleDateFormat df;
private void informacion (String text){
fecha = System.currentTimeMillis();
df = new SimpleDateFormat("h-m-s");
String curTime = df.format(fecha);
Log.d("CicloVida ",text);
builder.append(curTime+"-"+text);
builder.append('\n');
texto.setText(texto.getText()+builder.toString());
}
public void onCreate(Bundle estado){
super.onCreate(estado);
texto = new TextView (this);
texto.setText(builder.toString());
setContentView(texto);
informacion("ejecución");
}
protected void onResume(){
super.onResume();
log("detenido");
}
protected void onPause(){
super.onPause();
log("pausado");
if(isFinishing()){
log("terminado");
}
}
}
1.4Â Â Â Â Segunda actividad : SingleTouch
Ahora pasamos a la segunda actividad
El evento singleTouch es un evento que se genera cuando se recibe un toque en la pantalla. La pantalla al ser táctil al pulsar o tocar en ella se genera este evento
Implementa la interfaz OnTouchListener
Esta interfaz sólo tiene un método abstracto que habrá que implementar
public abstract boolean onTouch(View vista, MotionEvent evento);
Para asociar el Listener a un objeto de tipo view y recoger los eventos de toque en dicho objeto se usa el método
View.setOnTouchListener()
La clase MotionEvent tiene tres métodos importantes
float getX() è Coordenada x
float getY() è Coordenada y
getAction() ètipo de evento táctil. Tenemos los siguientes posibles eventos
MotionEvent.ACTION_DOWN
MotionEvent.ACTION_MOVE
MotionEvent.ACTION_CANCEL
MotionEvent.ACTION_UP
Hacer el programa para que cuando toque con el dedo ponga el tipo de evento y la posición en la que se ha producido
public class SingleTouch extends Activity implements OnTouchListener{
StringBuilder texto = new StringBuilder();
TextView cajaTexto;
public void onCreate(Bundle instancia){
super.onCreate(instancia);
cajaTexto = new TextView(this);
cajaTexto.setText("Multiple toque en pantalla");
cajaTexto.setOnTouchListener(this);
setContentView(cajaTexto);
}
@Override
public boolean onTouch(View v, MotionEvent evento) {
texto.setLength(0);//Borramos lo que habÃa en el texto
switch (evento.getAction()){
//Presionamos un dedo
case MotionEvent.ACTION_DOWN:
texto.append("Down, ");
break;
case MotionEvent.ACTION_UP:
texto.append("Up, ");
break;
case MotionEvent.ACTION_CANCEL:
texto.append("Cancel, ");
break;
case MotionEvent.ACTION_MOVE:
texto.append("Move, ");
break;
}
texto.append(", ");
texto.append(evento.getX());
texto.append(", ");
texto.append(evento.getY());
texto.append("\n");
cajaTexto.setText(texto.toString());
return true;
}
}
1.5Â Tercera actividad : MultiTouch
El evento que se produce, la interfaz y el método abstracto son iguales que en el caso anterior, pero a diferencia de él, éste incorpora más eventos, ya que puedo presionar hasta con 10 dedos, dependiendo de lo que implemente el dispositivo. Normalmente dispositivos móviles no suele tener mucho sentido que implementen más de 5 toques
Aquà aparecen además de los eventos anteriores dos más con lo que en total tendremos
MotionEvent.ACTION_POINTER_DOWN
MotionEvent.ACTION_POINTER_UP
Ahora un único MotionEvent puede tener datos para varios eventos. De hecho los eventos anteriores ocurren cuando presionamos o levantamos un toque que no sea el primero.
Para saber cuántos eventos está gestionando un MotionEvent tenemos el método
MotionEvent.getPointerCount();
En el propio evento MotionEvent.getAction() nos viene codificado el tipo de evento y el Ãndice de qué toque es el que en un momento dado está produciendo el evento si no es el primero
Para quedarnos sólo con el tipo de evento invocamos al método MotionEvent.getActionMasked()
Respecto con el resto de toques que no sean el primero se gestionan en un vector.
Podemos acceder al Ãndice y al identificador
int MotionEvent.getActionIndex()
int MotionEvent.getPointerIdentified()
1.5.1Â Â Â Â Identificador e Indice
int indice = MotionEvent.getActionIndex()
int identificardor = MotionEvent.getPointerIdentified(inidice)
Ãndice es un valor que corresponde a un Ãndice de los arrays internos de MotionEvent, por lo que no corresponde con el toque después de primer 0,1,2,…
identificador es un entero que retorna el identificador del puntero del dedo, en este caso sà que corresponde al toque 0,1,2,…
package com.example.api_juegos;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.TextView;
public class MultiTouch extends Activity implements OnTouchListener{
StringBuilder texto = new StringBuilder();
TextView cajaTexto;
float[]x = new float[10];
float[]y = new float[10];
boolean[]tocado = new boolean[10];
public void onCreate(Bundle instancia){
super.onCreate(instancia);
cajaTexto = new TextView(this);
cajaTexto.setText("Multiple toque en pantalla");
cajaTexto.setOnTouchListener(this);
setContentView(cajaTexto);
}
private void actualizaCajaTexto(){
texto.setLength(0);//Borramos lo que habÃa en el texto
for (int i = 0; i<10; i++){
texto.append(tocado[i]);
texto.append(", ");
texto.append(x[i]);
texto.append(", ");
texto.append(y[i]);
texto.append("\n");
}
cajaTexto.setText(texto.toString());
}
@Override
public boolean onTouch(View v, MotionEvent evento) {
//Primero obtenemos el tipo de evento
int accion = evento.getActionMasked();
int indiceToque = evento.getActionIndex();
int idToque = evento.getPointerId(indiceToque);
switch (accion){
//Presionamos un dedo
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
tocado[idToque]=true;
x[idToque]=(int)evento.getX(indiceToque);
y[idToque]=(int)evento.getY(indiceToque);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL:
tocado[idToque]=false;
x[idToque]=(int)evento.getX(indiceToque);
y[idToque]=(int)evento.getY(indiceToque);
break;
case MotionEvent.ACTION_MOVE:
int contadorToque=evento.getPointerCount();
for(int i=0;i<contadorToque;i++){
indiceToque=i;
idToque=evento.getPointerId(indiceToque);
x[idToque]=(int)evento.getX(indiceToque);
y[idToque]=(int)evento.getY(indiceToque);
}
break;
}
actualizaCajaTexto();
return true;
}
}
1.6Â Cuarta actividad: el Teclado
Estos eventos se generan cuando la aplicación detecta acciones sobre el teclado. Estos eventos pueden ser del teclado, de la pantalla (soft ), teclado hard, si el dispositivo lo tiene o entradas del sistema.
Interfaz OnKeyListener con un único método onKey().
public boolean onKey (View vista, int keyCode, KeyEvent evento)
Los parámetros
· vista es la vista sobre que recibe el evento del teclado
· keyCode es el código de la tecla que he presionado; este código corresponde a una constante de la clase KeyEvent (Por ejemplo la tecla Z corresponde a la constante KeyCode.KEYCOD_Z
· evento es el propio evento que se ha generado.
1.6.1Â Â Â Â Eventos de la clase
La clase KeyEvento tiene dos métodos
KeyEvent.getAction
KeyEvent.getUnicodeChar()
En el primer caso nos devuelve el tipo de evento generado, pudiendo ser uno de los siguientes
KeyEvent.ACTION_DOWN
KeyEvent.ACTION_UP
KeyEvent.ACTION_MULTIPLE
El Segundo método nos retorna el código Unicode de la tecla presionada para poder, por ejemplo escribirla.
1.6.2Â Â Â Â Trabajar con eventos del teclado sobre la vista
View.setFocusableInTouchMode(true);
View.requestFocus();
A continuación el código para conseguir este funcionamiento
Para poder ver el funcionamiento, debemos tener visible el teclado
Para ello vamos a ver el siguiente código
InputMethodManager teclado =
(InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
teclado.toggleSoftInput(InputMethodManager.SHOW_FORCED,
InputMethodManager.HIDE_IMPLICIT_ONLY);
Obtenemos una referencia de la clase que administra los métodos de entrada y la instanciamos a partir del servicio del sistema que nos informa de cual es el servicio del sistema para insertar datos por el teclado
Posteriormente llamamos al método toggleSoftInput que lo que hace es cambiar el método de entrada (teclado ) que se visualiza por la pantalla
void toggleSoftInput( int showFlags, int hideFlags)
Le pasamos dos flag tiene el siguiente valor que nos indica cuando cambiar de modo de visualizar a modo oculto
· InputMethodManager.SHOW_FORCED è Se ha forzado que aparezca el teclado y no desaparecerá hasta que explÃcitamente se indique
· InputMethodManager.HIDE_IMPLICIT_ONLY è El teclado solo debe de estar oculto si el usuario lo indica de forma explÃcita
1.7 Quinta actividad Acelerómetro
Es una funcionalidad que está muy de moda y es un reclamo muy interesante para el mundo de los juegos, y muchas aplicaciones interesantes.
El acelerómetro es un sensor que nos facilita la ubicación espacial del dispositivo respecto a un eje de tres coordenadas
El acelerómetro utiliza la interfaz SensorEventListener
Esta interfaz tiene dos métodos
public void onSensorChage(SensorEvent evento)
public void onAccurrencyChanged(Sensor sensor, int accurrency)
El primer método se invoca cuando se cambia la posición del móvil respecto a la última que tenÃa
Entre otros métodos y datos del SensorEvent tenemos la nueva posición que nos la da un vector
evento.values[0 ]
evento.values[1 ]
evento.values[2 ]
El segundo cuando cambian el número de sensores de acelerómetro que tiene el dispositivo.
A la hora de hacer la aplicación, primero debemos verificar que el dispositivo tenga acelerómetro, y en caso de que exista asociar el listener de este evento al Adminstrador del sistema de sensores
//Verificamos que el dispositivo tenga acelerómetros
SensorManager sm =(SensorManager) getSystemService (SENSOR_SERVICE);
List<Sensor>listaAcelerometros = sm.getSensorList(Sensor.TYPE_ACCELEROMETER);
if (listaAcelerometros.size()>0)
//Registramos el acelerómetro para recoger los eventos
sm.registerListener(this,listaAcelerometros.get(0),SensorManager.SENSOR
_DELAY_GAME);
Una vez que hemos hecho esto ya solo queda juntar todo y nos quedará el siguiente código
package com.example.api_juegos;
import java.util.List;
import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.TextView;
public class Acelerometro extends Activity implements SensorEventListener{
StringBuffer texto = new StringBuffer();
TextView cajaTexto;
public void onCreate(Bundle estado){
super.onCreate(estado);
cajaTexto = new TextView (this);
cajaTexto.setText("Controlando el acelerómetro");
//Verificamos que el dispositivo tenga acelerómetros
SensorManager sm =(SensorManager) getSystemService (SENSOR_SERVICE);
List<Sensor> listaAcelerometros = sm.getSensorList(Sensor.TYPE_ACCELEROMETER);
if (listaAcelerometros.size()>0)
//Registramos el acelerómetro para recoger los eventos
sm.registerListener(this,listaAcelerometros.get(0),SensorManager.SENSOR_DELAY_GAME);
setContentView(cajaTexto);
}
@Override
public void onSensorChanged(SensorEvent evento) {
// TODO Auto-generated method stub
texto.setLength(0);
texto.append("X=");
texto.append(evento.values[0]);
texto.append("Y=");
texto.append(evento.values[1]);
texto.append("Z=");
texto.append(evento.values[2]);
String t = texto.toString();
Log.d("KeyText",t);
cajaTexto.setText(t);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
}
1.8Â Sexta actividad: Assets
Queremos acceder a ficheros ubicados en un almacenamiento externo, generalmente una tarjeta SD
En android los ficheros que incorporamos a nuestra aplicación y que con ella los queremos distribuir pueden estar ubicados en res/ o en assets/
Los ficheros ubiados en res/ deben cumplir ciertas restricciones, no siendo asà en los ubicados en assets/
Queremos trabajar con ficheros que vamos a ubicar en assets/
Necesitmos un objeto de la clase AssetManager
Para instanciar obtenemos una referencia del método getAssets() la interfaz Context
AssetManager fileAdmin = context.getAssets();
Con este objeto podemos acceder a los ficheros. Para abrir los ficheros
InputStream file = fileAdmin.open(“datos.txtâ€);
La ubicación del fichero estará dentro del directorio assets.
Una vez que hemos abierto el fichero de manera tan sencilla ahora tenemos que leerlo. Si trabajamos con ficheros que ubicamos en nuestra aplicación hemos de saber que sólo se pueden abrir en modo de lectura, y no de escritura
Ahora nos queda leer los datos del fichero
Para ello trabajaremos con la clase ByteArrayOutputStream, y usaremos el método read() de la clase InputStream
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
byte[] bytes = new byte[4096];
int len = 0;
while((len = fa.read(bytes))>0){
byteStream.write(bytes,0,len);
String texto = byteStream.toByteArray();
En nuestro api haremos que se visualice el contenido de un fichero llamado datos.txt que estará dentro de la capeta assets/datos.txt
A continuación el código
package com.example.api_juegos;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import android.app.Activity;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class Asset extends Activity {
StringBuffer texto = new StringBuffer();
TextView cajaTexto;
public void onCreate(Bundle estado){
super.onCreate(estado);
cajaTexto = new TextView (this);
InputStream file=null;
AssetManager adminAsset = getAssets();
setContentView(cajaTexto);
Log.i("ASSETS","Antes de abrirlo el fichero");
try{
file = adminAsset.open("datos.txt");
Log.i("ASSETS","Fichero abierto");
String texto = leeFichero(file);
cajaTexto.setText(texto);
}catch(IOException e){
cajaTexto.setText("No puedo cargar el ficheroâ€);
}finally{
if (file!=null)
try{
file.close();
}catch(IOException e){
cajaTexto.setText("No puedo cerrar el fichero");
}
}
}
private String leeFichero(InputStream fa) throws IOException{
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
byte[] bytes = new byte[4096];
int len = 0;
while((len = fa.read(bytes))>0)
byteStream.write(bytes,0,len);
Log.i("ASSET","justo antes de retornar");
return new String(byteStream.toByteArray());
}
}
1.9      Septima actividad  AlmacenamientoExterno
En este caso queremos almacenar la información en la tarjeta SD en lugar de almacenarlo junto a la aplicación y distribuirlo.
En este caso ya sà que podemos realizar operaciones de lectura y escritura
Para acceder a este dispositivo debemos tener permiso para acceder a este dispositivo de almacenamiento externo <uses-permission>. Para el acceso a la tarjeta SD
<user-permission android.name= â€android.permission.WRITE_EXTERNAL_STORAGE†>
Posteriormente debemos comprobar que existe o tenemos disponible dicho dispositivo
String estado = Enviroment.getExternalStorageState()
La clase Enviroment define entre otras cosas la constante Enviroment.MEDIA_MOUNTED Si el método anterior nos retorna dicho valor, implica que tendremos acceso en lectura y escritura a dicho dispositivo
Ahora nos queda obtener la ubicación de este dispositivo, es decir el directorio donde esté montado
File directorioSD= Enviroment.getExternalStorageDirectory()
En estos momentos podemos disponernos a abrir el fichero
File fichero = new File(directorioSD.getAbsolutePath()+File.separator+ "texto.txt");
Ahora a usar las clases de java de I/O para leer y escribir en ficheros.
El código de esta actividad completa se muestra a continuación
package com.example.api_juegos;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.widget.TextView;
public class AlamcenamientoExterno extends Activity {
StringBuffer texto = new StringBuffer();
TextView cajaTexto ;
public void onCreate(Bundle estado){
super.onCreate(estado);
cajaTexto = new TextView (this);
setContentView(cajaTexto);
String estadoSD = Environment.getExternalStorageState();
if (!estadoSD.equals(Environment.MEDIA_MOUNTED)){
cajaTexto.setText("No está disponible la tarjeta SD");
}else{
File directorioSD= Environment.getExternalStorageDirectory();
File fichero = new File(directorioSD.getAbsolutePath() +
File.separator + "texto.txt");
try{
escribeTexto(fichero,"Esto es una lÃnea que quiero escribier
en mi fichero");
String t = leeTexto(fichero);
cajaTexto.setText(t);
}catch(IOException e){
cajaTexto.setText("Error accediendo "+e.getMessage());
}
}
}
private String leeTexto(File fichero) throws IOException {
// TODO Auto-generated method stub
BufferedReader r = new BufferedReader( new FileReader(fichero));
StringBuilder texto = new StringBuilder();
String linea;
while ((linea=r.readLine())!=null){
texto.append(linea);
texto.append('\n');
}
r.close();
return r.toString();
}
private void escribeTexto(File fichero, String texto) throws
IOException {
BufferedWriter w = new BufferedWriter( new FileWriter(fichero));
w.write(texto);
w.close();
}
}
1.10Â Â Â Â Â Â Â Â Â Â Â Â Â "Sonido"
1.11Â Â Â Â Â Â Â Â Â Â Â Â Â "Video",
1.12Â Â Â Â Â Â Â Â Â Â Â Â Â "Ventana Completa",
1.13Â Â Â Â Â Â Â Â Â Â Â Â Â "RenderView",
1.13.1Programación básico de gráficos
LibrerÃa Skia
1.13.1.1 Desbloquear la pantalla
la pantalla bloqueada pierde el brillo con el objetivo de economizar.
Por software podemos crear un bloqueo para que esto no ocurra y asignarlo a la aplicación.
Para hacerlo por software debemos dar permisos a la aplicación; Para que la aplicación solicite permisos cuando se instala (antes de estar ejecutándose), hay que especificarlo en el fichero Manifest con el elemento uses-permission
<uses-permission>
android.permission.WAKE_LOCK
</uses_permission>
Este permiso permite el uso de objetos PowerManager y WakeLock para evitar que el procesador deje de funcionar al 100% cuando no hay eventos en el sistema con el objetivo de ahorrar energÃa.
Son muchos los permisos que puede solicitar la aplicación al sistema antes de instalarse . ver http://developer.android.com/reference/android/Manifest.permission.html
Una vez hecho esto ya podemos definer un objeto de la clase WakeLock y un objeto de la clase PowerManager.
A partir del sistema context obtenemos un objeto de la clase PowerManager y con el método nextWakeLock instanciamos un objeto de la clase WaleLock.
Este método genera un wake lock (bloqueo para que no se duerma el sistema) según los dos parámetros que le pasemos:
1. El tipo de bloqueo que lo pasamos con una constante, en este caso queremos un bloqueo completo (que no se duerma aunque no haya eventos en el sistema) PowerManager.FULL_WAKE_LOCK
2. Un tag (etiqueta que pongamos a ese bloqueo para identificarlo) ¿??
PowerManager power ;
WakeLock bloqueo ;
power = (PowerManager) getSystemService(Context.POWER_SERVICE);
bloqueo = power.newWakeLock(PowerManager.FULL_WAKE_LOCK,"My bloqueo");
Una vez creado el bloqueo (en realidad el desbloqueo) hay que cargarlo con el método acquire() Y cuando la actividad finalice hay que desactÃvalo, o liberar el bloque con el método release(). Ambos métodos de la clase WaleLock Recordar que debemos invocarlo en los callback onResume() {… objetoWakeLock.acquire()…} y onPause{… objetoWakeLock.release()…}
1.13.1.2 Pantalla completa
Consiste en eliminar del espacio visual elementos ajenos a nuestra aplicación o que formen parte de ella pero no de la vista principal como el barra del tÃtulo, o menus o barra de notificación.
Especialmente en juegos queremos disponer de toda la pantalla
Para ello realizaremos las siguientes llamadas
//Haciendo la pantalla completa y sin los meús o tÃtulos
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
Vemos como el primer método quita la barra de tÃtulo
El segundo se encarga que nuestra actividad ocupe toda la pantalla completa y no use la barra de notificación
1.13.1.3 El código
Para probar la aplicación completa, reescribimos el método SingleTouch
package com.example.api_juegos;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
public class SingleTouch extends Activity implements OnTouchListener{
StringBuilder texto = new StringBuilder();
TextView cajaTexto;
PowerManager power ;
WakeLock bloqueo;
public void onCreate(Bundle instancia){
super.onCreate(instancia);
//desbloqueo
power = (PowerManager)getSystemService(Context.POWER_SERVICE);
bloqueo = power.newWakeLock(PowerManager.FULL_WAKE_LOCK,"Mi bloqueo");
//Pantalla completa
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
cajaTexto = new TextView(this);
cajaTexto.setText("Multiple toque en pantalla");
cajaTexto.setOnTouchListener(this);
setContentView(cajaTexto);
}
@Override
protected void onPause() {
super.onPause();
bloqueo.release();
Log.d("SINGLETOUCH","On Pause");
}
@Override
protected void onResume() {
super.onResume();
bloqueo.acquire();
Log.d("SINGLEtOUCH","On resume");
}
@Override
public boolean onTouch(View v, MotionEvent evento) {
// Igual que antes, no ha cambiado nada
}
1.13.2Dibujando en la interfaz de usuario
Hasta ahora dibujábamos (escribÃamos) en un view que era una caja de texto que se dibujaba en la pantalla cuando invocamos a setContentView()
Ahora vamos a crear nuestra propia vista
Para ello tenemos que crear una clase que extienda de View
class RederView extends View{
//Codigo
}
La clase View tiene un método que se llama onDraw(Canvas lienzo) que android lo invonca siempre que el view se tenga que dibujar
protected void onDraw (Canvas miLienzo){
//dibujar lo que quiero que aparezca en miLienzo….
}
Para que se redibuje a sà sola usamos el método invalidate().
De esta manera se volverá a dibujar una y otra vez, pero lo hará en el mismo hilo de ejecución, pues no hemos creado ningún thread
Canvas es una clase muy especial que engloba una api llamada Skia.
Con Canvas vamos a poder dibujar tanto formas, mapas de bits como texto
Canvas en este caso dibuja dentro del espacio que ocupa View, no dibuja directamente en la pantalla, sino dentro de algún mapa de bit.
Vamos a hacer en nuestra api una aplicación que me muestre como el método invalÃdate() da una frecuencia de ejecución al método onDraw() como si de un bucle en un programa principal se tratara.
Para ello usaremos el método de Canvas
Canvas.drawRGB( int red, int green, int blue) que da un color de fondo a la pantalla según los colores que le pasemos
demosle colores aleatorios
canvas.drawRGB(rand.nextInt(256),rand.nextInt(256),rand.nextInt(256));
Observemos el código completo y ejecutalo (cuidado, no te marees).
intenta relentizar la ejecución
//package e imports igual que en el caso anterior ... creo…
public class RenderView extends Activity {
PowerManager power ;
WakeLock bloqueo ;
//Creamos nuestra propia view
class MiRender extends View{
Random rand = new Random();
public MiRender(Context contexto){
super (contexto);
}
protected void onDraw(Canvas canvas){
canvas.drawRGB(rand.nextInt(256),
rand.nextInt(256),
rand.nextInt(256));
invalidate();
}
}
@Override
protected void onCreate(Bundle estado) {
super.onCreate(estado);
//Desbloqueando la pantalla configurando
power = (PowerManager) getSystemService(Context.POWER_SERVICE);
bloqueo = power.newWakeLock(PowerManager.FULL_WAKE_LOCK,"Mi bloqueo");
//Haciendo la pantalla completa y sin los meús o tÃtulos
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(new MiRender(this));
}
@Override
protected void onPause() {
super.onPause();
bloqueo.release();
Log.d("SINGLETOUCH","On Pause");
}
@Override
protected void onResume() {
super.onResume();
bloqueo.acquire();
Log.d("SINGLEtOUCH","On resume");
}
}