Anda di halaman 1dari 8

Curso de Android: Contextos

Contextos de Android

El Context oContexto de Android es una clase fundamental a la hora de desarrollar


aplicacionesparaestesistemaoperativo.Siaccedesaladocumentacinoficialpuedesleer
losiguiente(traducido):

Es la interfaz global de informacin acerca del entorno de la aplicacin. Es una clase


abstracta que implementa Android. Permite acceder a los recursos especficos de la
aplicacin y a sus clases, as como llamar al padre para realizar operaciones a nivel de la
aplicacin,comolanzarActividades,difundirmensajesalsistema,recibirIntenciones,etc.

SeguroquealgunaveztehaocurridoelmaldemuchosprogramadoresAndroid,creerque
elContextosirveparaalgoyaplicarlocadavezqueunaclaseounmtodolopidesinsaber
muybienparaqusirverealmente.Vamosaintentarexplicarenesteanexoesteconcepto
unpocoenrevesado.

LadefinicindeunContextodeAndroidesqueesunsimpleContexto,esdecir,cumpleala
perfeccin el segundo significado que figura en el diccionario de la RAE (Definicinde
contextoenlaRAE):

2. m. Entorno fsicoo de situacin,ya seapoltico, histrico,culturalo de cualquierotra


ndole,enelcualseconsideraunhecho.

Enconcreto,elcontextoleindicaaunobjetosuscaractersticasactuales,dequien
depende,etctera.

Tipos de Contexto

EnAndroidexistendostiposdecontextos:

Aplicacin: una aplicacin tiene un nico contexto que engloba a todos contextos
delasActividades,Servicios,etcteraquecontiene.Paraaccederaestecontextode
aplicacin desde unaActivity oun Service podemos escribir laorden
getApplication(). Desde otra clase cualquiera que se herede de Context
utilizaremoslaorden getApplicationContext().

Activity oService: las actividadesy servicios se heredan de la clase


ContextWrapper que, a su vez, se hereda de Context. ContextWrapper es
unaclasedetipoProxy(intermediario)querecibe todaslasllamadasdela
Actividad o el Servicio y las enva a una instancia oculta de Context denominada
BaseContext,paradiferenciarladelcontextodelaaplicacin.

Curso de Android: Contextos

Sin embargo,los siguientescomponentesfundamentalesde Android no se heredan de la


clase Context como ocurre con las anteriores, pero lo necesitan. Por esto, el sistema
operativodisponedeotrosmecanismosparahacerlo:

BroadcastReceiver: cadavezque elsistemadifundeunnuevoevento,medianteel


mtodoonReceive(Context context, Intent intent), sepasael
ContextoenelqueseejecutaelReceptordemensajes.

ContentProvider: mediante la orden getContext() se puede obtener el


Contexto de la aplicacin que lo est ejecutando.Ten en cuentaque puede ser la
mismaaplicacinquelodefineuotradiferentequelousa.

IMPORTANTE: siunaActividadoServiciosedestruye,suContextodesaparece,esdecir,el
Contextoestligadoalciclodevidadelelementoalqueestasociado.

Context esunaclaseabstracta queimplementa Android, porlotanto,loselementos que


contienen un Context se heredan de la clase Context.Es decir, no todos los objetosen
AndroidtienenobligatoriamenteunContextoasociado,nielobjetoeselpropioContexto,
dependedesiseheredandelaclaseContext ono.

VemosendefinicindelaclaseActivity que,efectivamente, seheredadelaclase


Context:

Cundo utilizamos el Contexto al programar en


Android?

Alaccederalosrecursoscomoimgenes,Strings,etcteradelaaplicacin:

contexto.getResources().getDrawable(R.drawable.imagen_de_recursos);

Alcrearnuevos Views,Listeners,Adapters,Intents,etctera.Porejemplo:

TextView miTexto = new TextView(contexto);

Intent intencion = new Intent(contexto, claseActivityArrancar.class);

AlaccederdirectamenteacomponentescomoActionBar,Intents,etctera:
2

Curso de Android: Contextos

contexto.getIntent();

Cmo obtener el Contexto?

Acontinuacin,vamosavercmoobtenerelContextodependiendodeltipodeelemento
deAndroidenelqueestemostrabajando:

ClasequeseheredadeContext(comoActivity oService):this

public class MainActivity extends Activity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context contexto = this;
}
}

ClasequeseheredadeContextdesdeunaclaseannima: ClaseActivity.this

public class MainActivity extends Activity {


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

Button boton = (Button)


findViewById(R.id.button_obtenerContext_boton);

boton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Context contexto = MainActivity.this;
}
});
}
}

PuedesobservarquelaclaseOnClickListener noseheredadeContext yaquees


unainterfaz:

Por esto, para acceder al contexto de la actividad que lo contiene utilizamos la


sentenciaMainActivity.this.

ClasequeNOseheredadeContext(porejemplo,seheredadesdeView):
mi_view.getContext()

public class MainActivity extends Activity {


@Override

Curso de Android: Contextos

protected void onCreate(Bundle savedInstanceState) {


super.onCreate(savedInstanceState);

Button boton = (Button)


findViewById(R.id.button_obtenerContext_boton);

Context contexto = boton.getContext();


}
}

PuedesobservarquelaclaseButton noseheredadeContext:

As,obtenemoselcontextodondeestasociadoelbotn.

Aplicacin(desdecualquierclaseheredadadeContext):getApplicationContext()

public class MainActivity extends Activity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context contexto = getApplicationContext();
}
}

Actividad delFragmentoquelocontiene(desdeunFragment):getActivity()

public class MainActivityFragment extends Fragment {

@Override
public void onAttach (Activity activity) {
super.onAttach(activity);
Context contexto = getActivity();
}
}

Cmo evitar problemas con el Context

Sinembargo,elusode Context puedeprovocarfugas dememoria. Unafugadememoria


(ms conocido por el trmino ingls memory leak) es un error de software que ocurre
cuando un bloque de memoria reservada por un programa no se libera correctamente.

Curso de Android: Contextos

Dependiendo de la cantidad de memoria perdida y el tiempo que el programa siga en


ejecucin, este problema puede llevar al agotamiento de la memoria disponible en el
sistema.

Recordamosque un Contexto est asociado al elemento al que pertenece, por lo tanto,


dependedelciclodevidadeste.

Por ejemplo, el Context de una Activity existir mientras la Activity se est


ejecutando. As mismo, el Context de una aplicacin existe hasta que se termina por
completolaaplicacin(hastaquemuere,nomientrasseencuentraenpausa).

Enteora,deberamosusarsiempreel Context mspequeoquesuelesereldelelemento


alquepertenece.Sinembargo,aveces,seobtieneprdidadememoriadeldispositivo,por
loqueesmuyrecomendableusardirectamenteelContext delaaplicacin.

Esteefectosucedeporladoblereferenciaexistentecuandounobjetoapuntaaotroobjeto
y el Garbage Collection(recolector de basura de Java, para la liberacin automtica de
memoria)nopuedeeliminardichosobjetos,loque,asuvez,implicanopoderliberaresa
memoria.

Es msfcilexplicarel problemacon un ejemplo.Supongamosque queremosguardaren


unavariableestticaunaimagendefondoparanotenerqueestaraccediendotodoelrato
a la memoria cada vez que giremos el dispositivo, recuerda que al girar el dispositivo se
destruye la actividad y se vuelve a crear. Un programador pensara que si la variable es
estticasiempreestarenmemoriaaunqueseadestruidaconloqueelcdigoiramucho
msrpido:

public class mainActivity extends Activity {


private static Drawable sFondoDelTexto;

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

Context contexto = this;

TextView label = new TextView(contexto);


label.setText("Texto con fondo");

if (sFondoDelTexto == null) {
sFondoDelTexto = getDrawable(R.drawable.mi_imagen);
}

label.setBackgroundDrawable(sFondoDelTexto);
setContentView(label);
}
}

Curso de Android: Contextos

Aunque este cdigo anterior es correcto sintcticamente,al utilizar el Context this al


crearel TextView yasignarleunaimagenquenovaaserdestruidaalrotareldispositivo,
tenemosunproblemadeprdidadememoriadeldispositivo.

Como esta imagen apunta al objeto TextView y la imagen no se destruir al girar el


dispositivo,tampocosedestruirel TextView niel Context, porloquetampocose
destruirlaActivity queest,asuvez,ligadoalContext.

As aparece el problema de prdida de memoria, pues al volverse a crear, la imagen


apuntaraotro Context deotra Activity creada;yasencadagirodelmvil,hastaque
nosquedemossinmemoriayaparezcaunerroreneldispositivo.Sloalcerrarla
aplicacin,seliberaratodalamemoriareservada.

Parasolucionaresteproblemalomejoresutilizarelcontextodelaaplicacinmediantelas
rdenes Context.getApplicationContext() ocon Activity.getApplication() yaque
noest asociado alciclodevida delaActivity. As, aldestruirse elContext dela
Activity quedarlibrecuandotengaqueserdestruidaypodrserrecolectada:

public class miActivity extends Activity {

private static Drawable sFondoDelTexto;

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

Context contexto = getApplicationContext();

TextView label = new TextView(contexto);


label.setText("Texto con fondo");

if (sFondoDelTexto == null) {

sFondoDelTexto = getDrawable(R.drawable.mi_imagen);
}

label.setBackgroundDrawable(sFondoDelTexto);

setContentView(label);
}
}

TambinhayquetenercuidadoalcrearunaclaseSingletonqueguardenuestroContext.

Elpatrndediseosingleton(instancianica)estdiseadopararestringirlacreacinde
objetospertenecientesaunaclaseoelvalordeuntipoaunnicoobjeto.

Curso de Android: Contextos

Suintencinconsisteengarantizarqueunaclaseslotengaunainstanciayproporcionar
unpuntodeaccesoglobalaella.

ElejemplotpicoenJavaeselsiguiente:

public class Singleton {

private static Singleton INSTANCE = new Singleton();

// El constructor privado no permite que se genere un constructor por


// defecto, con mismo modificador de acceso que la definicin de la
// clase.
private Singleton() {}

public static Singleton getInstance() {


return INSTANCE;
}
}

Enel casodeAndroid, no recomendamosguardarun Context niconel esquema


Singleton niconvariablesestticas,sehadepasarsiempreel Context paranoperdersu
control.Volvemosainsistirquesila Activity sedestruyenuncaseborrardememoriaya
que, como el ejemplo anterior, existir una doble referencia que no permita al Garbage
Collectorliberardichamemoria,porloquelaActivity seguirocupandotodalamemoria
peseaestardestruida.Fjateenesteejemplo:

public class miSingleton {

private static miSingleton sInstancia;

private Context mContexto;

public static miSingleton getInstance(Context contexto) {


if (sInstancia == null) {
sInstancia = new miSingleton(contexto);
}
return sInstancia;
}

private miSingleton(Context contexto) {


mContexto = contexto;
}
}

ParacorregiresteproblemasepuedeusardenuevoelContext delaaplicacin:

public class miSingleton {

private static miSingleton sInstance;

private Context mContexto;

Curso de Android: Contextos

public static miSingleton getInstance(Context contexto) {


if (sInstance == null) {
sInstancia = new
miSingleton(contexto.getApplicationContext());
}

return sInstancia;
}

private miSingleton(Context contexto) {


mContexto = contexto;
}
}

Conclusin:hayquetenercuidadoalcrearvariablesestticasenunaclaseAndroidyaque,siestn
indirectamente asociadas a un Contexto, y ste se debe destruir (Actividad o Servicio), podramos
provocar un fallo de prdida de memoria. En estos casos, lo mejor es utilizar el Contexto de la
aplicacin. Adems, siempre es bueno pasar el contexto entre clases de Android cuando sea
necesarioenlosmtodoscorrespondientes.

Fjateenesteejemplodecdigofuentedonde,enunaclaseextendidade ArrayAdapter,
pasamoselContextocomoparmetroyloguardamoscomounapropiedadnoestticadelaclase:

class AdaptadorOpciones extends ArrayAdapter<Opcion> {

Activity contexto;
private Opcion[] datos;

// Contructor del adaptador usando el contexto de la aplicacin


// actual
AdaptadorOpciones(Activity contexto, Opcion[] datos) {
// Llamamos al constructor de la clase superior
super(contexto, R.layout.opcion, datos);
// Guardamos estas variables de la aplicacin principal para
// usarlas luego
this.datos = datos;
this.contexto = contexto;
}

...

Anda mungkin juga menyukai