Pregunta

En varios bits de código de Android que he visto:

 public class MyActivity extends Activity {
    public void method() {
       mContext = this;    // since Activity extends Context
       mContext = getApplicationContext();
       mContext = getBaseContext();
    }
 }

Sin embargo, no puedo encontrar ninguna explicación decente sobre cuál es preferible y bajo qué circunstancias se debe usar.

Apuntaría a la documentación sobre esto, y la orientación sobre lo que podría romperse si se elige el equivocado, sería muy apreciada.

¿Fue útil?

Solución

Estoy de acuerdo en que la documentación es escasa cuando se trata de Contextos en Android, pero puede recopilar algunos datos de varias fuentes.

Esta publicación de blog en el Google Android oficial El blog de desarrolladores se escribió principalmente para ayudar a abordar las pérdidas de memoria, pero también proporciona buena información sobre los contextos:

  

En una aplicación de Android normal, usted   generalmente tienen dos tipos de contexto,   Actividad y aplicación.

Leer el artículo un poco más sobre la diferencia entre los dos y cuándo podría considerar usar el contexto de la aplicación ( Activity.getApplicationContext () ) en lugar de usar el contexto de actividad esto ). Básicamente, el contexto de la aplicación está asociado con la aplicación y siempre será el mismo durante todo el ciclo de vida de su aplicación, mientras que el contexto de la actividad está asociado con la actividad y podría destruirse muchas veces a medida que la actividad se destruye durante los cambios de orientación de la pantalla y tal.

No pude encontrar realmente nada sobre cuándo usar getBaseContext () aparte de una publicación de Dianne Hackborn, uno de los ingenieros de Google que trabaja en el SDK de Android:

  

No use getBaseContext (), solo use   el contexto que tienes.

Eso fue de una publicación en grupo de noticias de desarrolladores de Android , es posible que desee considerar hacer su pregunta allí también, porque un puñado de las personas que trabajan en Android monitorean ese grupo de noticias y responden preguntas.

Entonces, en general, parece preferible utilizar el contexto de aplicación global cuando sea posible.

Otros consejos

Esto es lo que he encontrado con respecto al uso del contexto :

1). Dentro de una Activity , use this para inflar diseños y menús, registrar menús contextuales, crear widgets de instancias, iniciar otras actividades , cree un nuevo Intent dentro de una Activity , creando instancias de preferencias u otros métodos disponibles en una Activity .

Diseño de inflado:

View mView = this.getLayoutInflater().inflate(R.layout.myLayout, myViewGroup);

Menú de inflado:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    this.getMenuInflater().inflate(R.menu.mymenu, menu);
    return true;
}

Menú contextual de registro:

this.registerForContextMenu(myView);

Reproductor de instanciación:

TextView myTextView = (TextView) this.findViewById(R.id.myTextView);

Inicie una Actividad:

Intent mIntent = new Intent(this, MyActivity.class);
this.startActivity(mIntent);

Preferencias de instanciación:

SharedPreferences mSharedPreferences = this.getPreferenceManager().getSharedPreferences();

2). Para la clase de toda la aplicación, use getApplicationContext () ya que este contexto existe para la vida útil de la aplicación.

Recupere el nombre del paquete actual de Android:

public class MyApplication extends Application {    
    public static String getPackageName() {
        String packageName = null;
        try {
            PackageInfo mPackageInfo = getApplicationContext().getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), 0);
            packageName = mPackageInfo.packageName;
        } catch (NameNotFoundException e) {
            // Log error here.
        }
        return packageName;
    }
}

Vincula una clase de toda la aplicación:

Intent mIntent = new Intent(this, MyPersistent.class);
MyServiceConnection mServiceConnection = new MyServiceConnection();
if (mServiceConnection != null) {
    getApplicationContext().bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
}

3). Para los oyentes y otro tipo de clases de Android (por ejemplo, ContentObserver), use una sustitución de contexto como:

mContext = this;    // Example 1
mContext = context; // Example 2

donde this o context es el contexto de una clase (Actividad, etc.).

Actividad sustitución de contexto:

public class MyActivity extends Activity {
    private Context mContext;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);        
        mContext = this;
    }
}

Sustitución de contexto de escucha:

public class MyLocationListener implements LocationListener {
    private Context mContext;
    public MyLocationListener(Context context) {
        mContext = context;
    }
}

ContentObserver sustitución de contexto:

public class MyContentObserver extends ContentObserver {
    private Context mContext;
    public MyContentObserver(Handler handler, Context context) {
        super(handler);
        mContext = context;
    }
}

4). Para BroadcastReceiver (incluido el receptor en línea / incorporado), utilice el contexto propio del receptor.

Externo BroadcastReceiver:

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
        if (action.equals(Intent.ACTION_SCREEN_OFF)) {
            sendReceiverAction(context, true);
        }
        private static void sendReceiverAction(Context context, boolean state) {
            Intent mIntent = new Intent(context.getClass().getName() + "." + context.getString(R.string.receiver_action));
            mIntent.putExtra("extra", state);
            context.sendBroadcast(mIntent, null);
        }
    }
}

Incode / Embedded BroadcastReceiver:

public class MyActivity extends Activity {
    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final boolean connected = intent.getBooleanExtra(context.getString(R.string.connected), false);
            if (connected) {
                // Do something.
            }
        }
    };
}

5). Para los Servicios, utilice el contexto propio del servicio.

public class MyService extends Service {
    private BroadcastReceiver mBroadcastReceiver;
    @Override
    public void onCreate() {
        super.onCreate();
        registerReceiver();
    }
    private void registerReceiver() {
        IntentFilter mIntentFilter = new IntentFilter();
        mIntentFilter.addAction(Intent.ACTION_SCREEN_OFF);
        this.mBroadcastReceiver = new MyBroadcastReceiver();
        this.registerReceiver(this.mBroadcastReceiver, mIntentFilter);
    } 
}

6). Para Toasts, generalmente use getApplicationContext () , pero cuando sea posible, use el contexto pasado de una Actividad, Servicio, etc.

Usar el contexto de la aplicación:

Toast mToast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG);
mToast.show();

Usar contexto pasado de una fuente:

public static void showLongToast(Context context, String message) {
    if (context != null && message != null) {
        Toast mToast = Toast.makeText(context, message, Toast.LENGTH_LONG);
        mToast.show();
    }
}

Y por último, no use getBaseContext () como lo aconsejan los desarrolladores de framework de Android.

ACTUALIZACIÓN: agregue ejemplos de uso de Context .

Leí este hilo hace unos días, haciéndome la misma pregunta. Mi decisión después de leer esto fue simple: siempre use applicationContext.

Sin embargo, encontré un problema con esto, pasé unas horas para encontrarlo y unos segundos para resolverlo ... (cambiando una palabra ...)

Estoy usando un LayoutInflater para inflar una vista que contiene un Spinner.

Entonces, aquí hay dos posibilidades:

1)

    LayoutInflater layoutInflater = LayoutInflater.from(this.getApplicationContext());

2)

    LayoutInflater layoutInflater = LayoutInflater.from(this.getBaseContext());

Entonces, estoy haciendo algo como esto:

    // managing views part
    View view = ContactViewer.mLayoutInflater.inflate(R.layout.aViewContainingASpinner, theParentView, false);
    Spinner spinner = (Spinner) view.findViewById(R.id.theSpinnerId);
    String[] myStringArray = new String[] {"sweet","love"};

    // managing adapter part
    // The context used here don't have any importance -- both work.
    ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this.getApplicationContext(), myStringArray, android.R.layout.simple_spinner_item);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapter);

    theParentView.addView(view);

Lo que noté: si instanciaste tu Linealayout con el applicationContext, cuando hagas clic en el spinner en tu actividad, tendrás una excepción no detectada, proveniente de la máquina virtual dalvik (no de tu código, es por eso que tengo Pasé mucho tiempo para encontrar dónde estaba mi error ...).

Si usa el baseContext, entonces está bien, el menú contextual se abrirá y podrá elegir entre sus opciones.

Así que aquí está mi conclusión: supongo (no lo he probado más) que el baseContext cuando se trata de contextMenu en su actividad ...

La prueba se realizó codificando con API 8 y se probó en un HTC Desire, Android 2.3.3.

Espero que mi comentario no te haya aburrido hasta ahora y te deseo todo lo mejor. Feliz codificación ;-)

Primero, estoy de acuerdo en que deberíamos usar appcontext siempre que sea posible. entonces " esto " en actividad Nunca he tenido necesidad de basecontext.

En mis pruebas, en la mayoría de los casos se pueden intercambiar. En la mayoría de los casos, la razón por la que desea obtener un contexto es para acceder a archivos, preferencias, base de datos, etc. Estos datos eventualmente se reflejan como archivos en la carpeta de datos privados de su aplicación (/ data / data /). Independientemente del contexto que utilice, se asignarán a la misma carpeta / archivos para que esté bien.

Eso es lo que observé. Tal vez hay casos en los que debería distinguirlos.

En algunos casos, puede usar el contexto de actividad sobre el contexto de la aplicación al ejecutar algo en un hilo. Cuando el subproceso completa la ejecución y necesita devolver el resultado a la actividad del llamador, necesita ese contexto con un controlador.

((YourActivity) context).yourCallbackMethod(yourResultFromThread, ...);

En palabras simples

getApplicationContext () como sugiere el nombre del método hará que su aplicación conozca todos los detalles de la aplicación a los que puede acceder desde cualquier lugar de la aplicación. Por lo tanto, puede hacer uso de esto en el enlace de servicio, registro de transmisión, etc. Contexto de la aplicación estará activo hasta que la aplicación salga.

getActivity () o this hará que su aplicación conozca la pantalla actual, que también es visible y los detalles de nivel de aplicación proporcionados por contexto de aplicación . Entonces, lo que sea que desee saber sobre la pantalla actual, como Window ActionBar Fragementmanger , estará disponible en este contexto. Básicamente y Activity extiende Context . Este contexto estará vivo hasta que el componente actual (actividad) esté vivo

Solo he usado esto y getBaseContext al tostar desde un onClick (novato muy verde para Java y Android). Lo uso cuando mi clicker está directamente en la actividad y tengo que usar getBaseContext en un clicker interno anónimo. Supongo que ese es el truco con getBaseContext , tal vez está devolviendo el contexto de la actividad en la que se oculta la clase interna.

  

La confusión surge del hecho de que hay numerosas formas de   Contexto de acceso, con (en la superficie) sin diferencias discernibles.   A continuación se presentan cuatro de las formas más comunes a las que puede acceder   Contexto en una actividad.

getContext()
getBaseContext()
getApplicationContext()
getActionBar().getThemedContext() //new

¿Qué es un contexto? Personalmente, me gusta pensar en Context como el estado de su solicitud en un momento dado. El contexto de la aplicación representa una configuración global o básica de su aplicación y una Actividad o Servicio puede basarse en ella y representa una instancia de configuración de su Aplicación o un estado transitivo para ella.

Si observa la fuente de android.content.Context, verá que Context es una clase abstracta y los comentarios sobre la clase son los siguientes:

Interfaz con información global sobre un entorno de aplicación. Esta es una clase abstracta cuya implementación es proporcionada por el sistema Android. Eso permite el acceso a recursos y clases específicos de la aplicación , así como también llamadas ascendentes para operaciones de nivel de aplicación tales como actividades de lanzamiento, difusión y recepción de intenciones, etc. Lo que quito de esto es que Context proporciona una implementación común para acceder a nivel de aplicación y recursos a nivel de sistema. Los recursos de nivel de aplicación pueden acceder a cosas como recursos de cadena [getResources ()] o activos [getAssets ()] y el recurso de nivel de sistema es cualquier cosa a la que acceda con Context.getSystemService ().

De hecho, eche un vistazo a los comentarios sobre los métodos y parecen reforzar esta noción:

getSystemService () : Devuelva el identificador a un servicio a nivel de sistema por nombre. La clase del objeto devuelto varía según el nombre solicitado. getResources () : devuelve una instancia de Recursos para el paquete de su aplicación. getAssets () : devuelve una instancia de Recursos para el paquete de su aplicación. ¡Vale la pena señalar que en la clase abstracta Context, todos los métodos anteriores son abstractos! Solo una instancia de getSystemService (Class) tiene una implementación y eso invoca un método abstracto. Esto significa que la implementación de estos debe ser proporcionada principalmente por las clases de implementación, que incluyen:

ContextWrapper
Application
Activity
Service
IntentService

Mirando la documentación de la API, la jerarquía de las clases se ve así:

Contexto

| - ContextWrapper

| - - Aplicación

| - - ContextThemeWrapper

| - - - - Actividad

| - - Servicio

| - - - IntentService

Como sabemos que el Context en sí mismo no proporciona ninguna información, nos movemos hacia abajo en el árbol y echamos un vistazo al ContextWrapper y nos damos cuenta de que no hay mucho allí ya sea. Dado que la aplicación extiende ContextWrapper , tampoco hay mucho que ver allí ya que no anula la implementación proporcionada por ContextWrapper . Esto significa que la implementación del contexto la proporciona el sistema operativo y está oculta de la API . Puede echar un vistazo a la implementación concreta de Context mirando la fuente de la clase ContextImpl.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top