Domanda

In vari bit di codice Android ho visto:

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

Tuttavia non riesco a trovare una spiegazione decente di quale sia preferibile e in quali circostanze dovrebbe essere usato.

I puntatori alla documentazione su questo, e la guida su cosa potrebbe rompersi se viene scelto quello sbagliato, sarebbe molto apprezzato.

È stato utile?

Soluzione

Sono d'accordo che la documentazione è scarsa quando si tratta di Contesti in Android, ma puoi mettere insieme alcuni fatti da varie fonti.

Questo post sul blog sul Google Android ufficiale il blog degli sviluppatori è stato scritto principalmente per aiutare a risolvere le perdite di memoria, ma fornisce anche alcune buone informazioni sui contesti:

  

In una normale applicazione Android, tu   di solito hanno due tipi di contesto,   Attività e applicazione.

Leggendo l'articolo un po 'di più si parla della differenza tra i due e quando si potrebbe voler prendere in considerazione l'uso dell'applicazione Context ( Activity.getApplicationContext () ) piuttosto che usare il contesto Activity questo ). Fondamentalmente il contesto dell'applicazione è associato all'applicazione e sarà sempre lo stesso per tutto il ciclo di vita della tua app, dove il contesto dell'attività è associato all'attività e potrebbe essere distrutto molte volte poiché l'attività viene distrutta durante i cambiamenti di orientamento dello schermo e ad esempio.

Non sono riuscito a trovare davvero nulla su quando usare getBaseContext () diverso da un post di Dianne Hackborn, uno degli ingegneri di Google che lavora su Android SDK:

  

Non usare getBaseContext (), basta usare   il contesto che hai.

Deriva da un post su newsgroup per sviluppatori Android , potresti prendere in considerazione di porre la tua domanda anche lì, perché una manciata di persone che lavorano su Android effettivamente monitora quel newsgroup e risponde alle domande.

Quindi nel complesso sembra preferibile utilizzare il contesto dell'applicazione globale quando possibile.

Altri suggerimenti

Ecco cosa ho trovato sull'uso del contesto :

1). All'interno di un Activity stesso, usa this per gonfiare layout e menu, registrare menu contestuali, creare istanze di widget, avviare altre attività , crea un nuovo Intent all'interno di un Activity , istanziando le preferenze o altri metodi disponibili in un Activity .

Gonfia layout:

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

Gonfia menu:

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

Menu contestuale Registra:

this.registerForContextMenu(myView);

Widget di istanza:

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

Avvia un Attività:

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

Preferenze di istanza:

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

2). Per la classe a livello di applicazione, utilizzare getApplicationContext () poiché questo contesto esiste per la durata dell'applicazione.

Recupera il nome dell'attuale pacchetto 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;
    }
}

Associa una classe a livello di applicazione:

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

3). per gli ascoltatori e altri tipi di lezioni Android (ad es. ContentObserver), utilizzare una sostituzione di contesto come:

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

dove questo o contesto è il contesto di una classe (attività, ecc.).

Sostituzione del contesto

Attività :

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

Sostituzione del contesto dell'ascoltatore:

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

ContentObserver :

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

4). Per BroadcastReceiver (incluso il ricevitore incorporato / incorporato), utilizzare il proprio contesto del destinatario.

BroadcastReceiver:

esterno
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);
        }
    }
}

Inline / 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). Per i Servizi, utilizzare il contesto del servizio.

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). Per i toast, generalmente usa getApplicationContext () , ma dove possibile, usa il contesto passato da un'attività, un servizio, ecc.

Utilizza il contesto dell'applicazione:

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

Usa contesto passato da una fonte:

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

E infine, non utilizzare getBaseContext () come consigliato dagli sviluppatori del framework Android.

AGGIORNAMENTO: aggiungi esempi di utilizzo contesto .

Ho letto questa discussione qualche giorno fa, ponendomi la stessa domanda. La mia decisione dopo aver letto questo è stata semplice: utilizzare sempre applicationContext.

Tuttavia, ho riscontrato un problema con questo, ho trascorso alcune ore per trovarlo e alcuni secondi per risolverlo ... (cambiando una parola ...)

Sto usando un LayoutInflater per gonfiare una vista contenente uno Spinner.

Quindi qui ci sono due possibilità:

1)

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

2)

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

Quindi, sto facendo qualcosa del genere:

    // 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);

Quello che ho notato: se hai istanziato il tuo linearLayout con applicationContext, quindi quando fai clic sullo spinner nella tua attività, avrai un'eccezione non rilevata, proveniente dalla macchina virtuale Dalvik (non dal tuo codice, ecco perché ho ho trascorso molto tempo a scoprire dov'era il mio errore ...).

Se usi baseContext, allora va bene, il menu contestuale si aprirà e sarai in grado di scegliere tra le tue scelte.

Quindi ecco la mia conclusione: suppongo (non l'ho testato ulteriormente) di quanto sia richiesto il baseContext quando si tratta di menu contestuale nella propria attività ...

Il test è stato eseguito con la codifica con API 8 e testato su un HTC Desire, Android 2.3.3.

Spero che il mio commento non ti abbia annoiato finora e ti auguro il meglio. Buona codifica ;-)

In primo luogo, sono d'accordo che dovremmo usare appcontext ogni volta che è possibile. quindi " questo " in attività. non ho mai avuto bisogno di basecontext.

Nei miei test, nella maggior parte dei casi possono essere scambiati. Nella maggior parte dei casi, il motivo per cui si desidera acquisire un contesto è accedere a file, preferenze, database ecc. Questi dati vengono infine riflessi come file nella cartella dei dati privati ??dell'app (/ data / data /). Indipendentemente dal contesto che utilizzi, verranno mappati nella stessa cartella / file, quindi stai bene.

Questo è quello che ho osservato. Forse ci sono casi in cui dovresti distinguerli.

In alcuni casi puoi usare il contesto Activity sul contesto dell'applicazione quando esegui qualcosa in un thread. Quando il thread completa l'esecuzione ed è necessario restituire il risultato all'attività del chiamante, è necessario quel contesto con un gestore.

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

In parole semplici

getApplicationContext () , come suggerisce il nome del metodo, renderà la tua app consapevole dei dettagli a livello di applicazione a cui puoi accedere da qualsiasi parte dell'app. Quindi puoi farne uso nel collegamento al servizio, nella registrazione della trasmissione, ecc. Contesto dell'applicazione sarà attivo fino alla chiusura dell'app.

getActivity () o this renderà la tua app consapevole della schermata corrente che è visibile anche i dettagli a livello di app forniti da contesto dell'applicazione . Quindi, qualunque cosa tu voglia sapere sulla schermata attuale come Window ActionBar Fragementmanger e quindi sono disponibili in questo contesto. Fondamentalmente e Activity estendono Context . Questo contesto rimarrà attivo fino a quando l'attuale componente (attività) non sarà attivo

Ho usato questo e getBaseContext quando brindavo da un onClick (un angolo molto verde sia per Java che per Android). Lo uso quando il mio clicker è direttamente nell'attività e devo usare getBaseContext in un clicker interno anonimo. Immagino che sia praticamente il trucco con getBaseContext , forse sta restituendo il contesto dell'attività in cui si nasconde la classe interna.

  

La confusione deriva dal fatto che ci sono molti modi per farlo   accesso al contesto, con (in superficie) differenze non distinguibili.   Di seguito sono riportati quattro dei modi più comuni a cui potresti essere in grado di accedere   Contesto in un'attività.

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

Che cos'è un contesto? Personalmente mi piace pensare al contesto come lo stato della tua domanda in qualsiasi momento. Il contesto dell'applicazione rappresenta una configurazione globale o di base dell'applicazione e un'attività o un servizio può basarsi su di essa e rappresenta un'istanza di configurazione dell'applicazione o uno stato transitivo per essa.

Se guardi alla fonte per android.content.Context, vedi che Context è una classe astratta e i commenti sulla classe sono i seguenti:

Interfaccia con informazioni globali su un ambiente applicativo. Questa è una classe astratta la cui implementazione è fornita dal sistema Android. esso consente l'accesso a risorse e classi specifiche per l'applicazione , nonché inviti a operazioni a livello di applicazione come l'avvio di attività, la trasmissione e la ricezione di intenti, ecc. Ciò che tolgo da questo è che il contesto fornisce un'implementazione comune per accedere alle risorse a livello di applicazione e di sistema. Le risorse a livello di applicazione potrebbero accedere ad elementi come le risorse String [getResources ()] o gli asset [getAssets ()] e la risorsa a livello di sistema è tutto ciò a cui accedi con Context.getSystemService ().

In effetti, dai un'occhiata ai commenti sui metodi e sembrano rafforzare questa nozione:

getSystemService () : restituisce l'handle a un servizio a livello di sistema per nome. La classe dell'oggetto restituito varia in base al nome richiesto. getResources () : restituisce un'istanza di risorse per il pacchetto dell'applicazione. getAssets () : restituisce un'istanza di risorse per il pacchetto dell'applicazione. Potrebbe valere la pena sottolineare che nella classe astratta Context, tutti i metodi sopra indicati sono astratti! Solo un'istanza di getSystemService (Class) ha un'implementazione e che richiama un metodo astratto. Ciò significa che l'attuazione per questi dovrebbe essere fornita principalmente dalle classi di attuazione, che includono:

ContextWrapper
Application
Activity
Service
IntentService

Guardando la documentazione API, la gerarchia delle classi appare così:

Contesto

| & # 8202; & # 8212; & # 8202; ContextWrapper

| & # 8212; & # 8202; & # 8212; & # 8202; applicazione

| & # 8202; & # 8212; & # 8202; & # 8212; ContextThemeWrapper

| & # 8212; & # 8202; & # 8212; & # 8202; & # 8212; & # 8202; & # 8212; & # 8202; attività

| & # 8202; & # 8212; & # 8202; & # 8212; Servizio

| & # 8212; & # 8202; & # 8212; & # 8202; & # 8212; IntentService

Dato che sappiamo che Context non fornisce informazioni dettagliate, scendiamo dall'albero e diamo un'occhiata al ContextWrapper e ci rendiamo conto che non c'è molto o. Poiché l'applicazione estende ContextWrapper , non c'è molto da guardare anche lì poiché non sovrascrive l'implementazione fornita da ContextWrapper . Ciò significa che l'implementazione per Context è fornita dal sistema operativo ed è nascosta da API . Puoi dare un'occhiata all'implementazione concreta di Context esaminando l'origine della classe ContextImpl.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top