Jaka jest różnica między różnymi metodami uzyskania kontekstu?

W różnych fragmentach kodu Androida widziałem:

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

Jednak nie mogę znaleźć żadnego przyzwoitego wyjaśnienia, które jest lepsze i w jakich okolicznościach, które należy użyć.

Wskazówki do dokumentacji na ten temat i wskazówki dotyczące tego, co może się zepsuć, jeśli zostanie wybrany niewłaściwy, będą bardzo mile widziane.

Author: cuihtlauac, 2009-06-22

8 answers

Zgadzam się, że dokumentacja jest rzadka, jeśli chodzi o konteksty w Androidzie, ale możesz poskładać kilka faktów z różnych źródeł.

Ten wpis na oficjalnym blogu programistów Google Android został napisany głównie po to, aby pomóc w usuwaniu wycieków pamięci, ale zawiera również dobre informacje o kontekstach:]}

W zwykłej aplikacji na Androida, można zwykle mają dwa rodzaje kontekstu, Aktywność i zastosowanie.

Czytanie artykułu a nieco dalej mówi o różnicy między tymi dwoma i kiedy można rozważyć użycie kontekstu aplikacji (Activity.getApplicationContext()) zamiast korzystania z kontekstu aktywności this). Zasadniczo kontekst aplikacji jest powiązany z aplikacją i zawsze będzie taki sam przez cały cykl życia aplikacji, gdzie jako kontekst aktywności jest powiązany z aktywnością i może zostać zniszczony wiele razy, ponieważ aktywność jest zniszczona podczas zmiany orientacji ekranu i może zostać zniszczona. takie.

Nie mogłem znaleźć naprawdę nic o tym, kiedy używać getBaseContext () oprócz postu od Dianne Hackborn, jednego z inżynierów Google pracujących nad Android SDK:

Nie używaj getBaseContext (), po prostu użyj kontekst, który masz.

To było z postu na Android-developers newsgroup , możesz rozważyć pytanie tam również, ponieważ garstka ludzi pracujących na Androidzie faktycznie monitoruje tę grupę dyskusyjną i odpowiadaj na pytania.

Więc ogólnie wydaje się, że lepiej jest używać globalnego kontekstu aplikacji, gdy jest to możliwe.

 306
Author: snctln,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-28 10:51:21

Oto co znalazłem odnośnie użycia context:

1) . Wewnątrz Activity, używaj this do nadmuchiwania układów i menu, rejestrowania menu kontekstowych, tworzenia instancji widżetów, uruchamiania innych działań, tworzenia nowych Intent w obrębie Activity, tworzenia instancji preferencji lub innych metod dostępnych w Activity.

Układ nadmuchiwania:

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

Menu nadmuchiwania:

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

Kontekst rejestru menu:

this.registerForContextMenu(myView);

Instantiate widget:

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

Start an Activity:

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

Preferencje Instantiate:

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

2) . dla całej klasy aplikacji, użyj getApplicationContext(), ponieważ ten kontekst istnieje dla długości życia aplikacji.

Pobierz nazwę bieżącego pakietu Androida:

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

Bind a application-wide class:

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

3) . dla słuchaczy i ContentObserver), używają podstawienia kontekstu, takiego jak:

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

Gdzie this lub context jest kontekstem klasy (aktywności itp.).

Activity substytucja kontekstu:

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

Substytucja kontekstu słuchacza:

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

ContentObserver substytucja kontekstu:

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

4) . Dla BroadcastReceiver (w tym wbudowanego/wbudowanego odbiornika), użyj własnego odbiornika kontekst.

Zewnętrzne 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);
        }
    }
}

Inlined / 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) . W przypadku usług, użyj własnego kontekstu usługi.

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) . do toastów, zazwyczaj używaj getApplicationContext(), ale jeśli to możliwe, użyj kontekstu przekazanego z aktywności, usługi itp.

Użyj kontekstu aplikacji:

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

Użyj kontekstu przekazanego ze źródła:

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

I ostatnia, nie używaj getBaseContext() zgodnie z zaleceniami programistów Androida.

UPDATE: Dodaj przykłady użycia Context.

 54
Author: ChuongPham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-27 05:12:38

Przeczytałem ten wątek kilka dni temu, zadając sobie to samo pytanie. Moja decyzja po przeczytaniu była prosta: Zawsze używaj applicationContext.

Jednak napotkałem z tym problem, spędziłem kilka godzin, aby go znaleźć i kilka sekund, aby go rozwiązać... (zmieniając jedno słowo...)

Używam Layoutinflatera do nadmuchiwania widoku zawierającego Spinner.

Oto dwie możliwości:

1)

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

2)

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

Wtedy robię coś takiego jak to:

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

Co zauważyłem: jeśli utworzyłeś instancję linearLayout z applicationContext, to po kliknięciu na spinner w swojej aktywności, będziesz miał nieobciążony wyjątek, pochodzący z maszyny wirtualnej dalvik (nie z twojego kodu, dlatego spędziłem dużo czasu, aby znaleźć, gdzie był mój błąd...).

Jeśli używasz baseContext, to w porządku, otworzy się menu kontekstowe i będziesz mógł wybierać spośród swoich wyborów.

Oto mój wniosek: przypuszczam (nie testowałem go dalej), że baseContext jest wymagany przy radzeniu sobie z contextMenu w Twojej działalności...

Test został wykonany przy użyciu API 8 i przetestowany na HTC Desire, android 2.3.3.

Mam nadzieję, że mój komentarz do tej pory cię nie nudził i życzę Ci Wszystkiego najlepszego. Happy coding; -)

 13
Author: Mav3656,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-06 17:14:49

Po pierwsze, zgadzam się, że powinniśmy używać appcontext w miarę możliwości. następnie" to " w aktywności. nigdy nie potrzebowałem basecontext.

W moich testach w większości przypadków można je wymieniać. W większości przypadków powodem, dla którego chcesz zdobyć kontekst, jest dostęp do plików, preferencji, bazy danych itp. Dane te są ostatecznie odzwierciedlane jako pliki w folderze danych prywatnych aplikacji (/data/data/). Bez względu na to, jakiego kontekstu używasz, zostaną one zmapowane do tego samego folderu/plików, więc jesteś OK.

To właśnie zaobserwowałem. Może są przypadki, które powinieneś odróżnić.

 6
Author: samsonsu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-20 08:48:21

W niektórych przypadkach możesz użyć kontekstu aktywności nad kontekstem aplikacji, gdy uruchomisz coś w wątku. Gdy wątek zakończy wykonywanie i musisz zwrócić wynik z powrotem do aktywności wywołującej, potrzebujesz tego kontekstu z obsługą.

((YourActivity) context).yourCallbackMethod(yourResultFromThread, ...);
 3
Author: Paul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-24 23:29:29

W prostych słowach

getApplicationContext() jak sugeruje nazwa metody, aplikacja będzie świadoma szczegółów aplikacji, do których można uzyskać dostęp z dowolnego miejsca w aplikacji. Możesz więc wykorzystać to w wiązaniu usług, rejestracji transmisji itp. Application context będzie żył do momentu wyjścia aplikacji.

getActivity() lub this sprawi, że Twoja aplikacja będzie świadoma bieżącego ekranu, który jest widoczny również szczegóły poziomu aplikacji dostarczone przez application context. Więc cokolwiek chcesz wiedzieć o bieżącym ekranie jak Window ActionBar Fragementmanger i tak są dostępne w tym kontekście. Zasadniczo i Activity rozszerzyć Context. Ten kontekst będzie żywy, dopóki bieżący komponent (aktywność) nie będzie żywy

 2
Author: arjun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-09 12:49:16

Zamieszanie wynika z faktu, że istnieje wiele sposobów na dostęp do kontekstu, z (na powierzchni) bez dostrzegalnych różnic. Poniżej znajdują się cztery najczęstsze sposoby dostępu Kontekst w działaniu.

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

Czym jest kontekst? Osobiście lubię myśleć o kontekście jako o stanie Twojej aplikacji w danym momencie. Kontekst aplikacji reprezentuje globalną lub podstawową konfigurację aplikacji i aktywności lub Usługa może opierać się na niej i reprezentuje instancję konfiguracji aplikacji lub stan przejściowy dla niej.

Jeśli spojrzysz na źródło dla Androida.treść.Context, widzisz, że Context jest klasą abstrakcyjną, a komentarze na jej temat są następujące:

Interfejs do globalnych informacji o środowisku aplikacji. Jest to klasa abstrakcyjna, której implementację zapewnia system Android. Informatyka umożliwia dostęp do zasobów i klas application-specific, a także up-call for application-level operations such as starting activities, broadcasting and receiving intents, etc. Co odbieram z tego jest to, że kontekst zapewnia wspólną implementację dostępu do poziomu aplikacji, a także zasobów na poziomie systemu. Zasoby na poziomie aplikacji mogą mieć dostęp do takich zasobów, jak zasoby łańcuchowe [getResources()] lub zasoby [getAssets()], a zasoby na poziomie systemu to wszystko, do czego uzyskujesz dostęp za pomocą Context.getSystemService().

[17]} w rzeczywistości, spójrz na komentarze na temat metod i wydają się wzmocnienie tego pojęcia:

getSystemService(): zwraca uchwyt do usługi system-level według nazwy. Klasa zwracanego obiektu różni się w zależności od żądanej nazwy. getResources(): zwraca instancję zasobów dla pakietu aplikacji. getAssets(): zwraca instancję zasobów dla pakietu aplikacji. Warto zwrócić uwagę, że w klasie context abstract wszystkie powyższe metody są abstrakcyjne! Tylko jedna instancja getSystemService(Class) posiada implementację, która wywołuje metodę abstrakcyjną. Oznacza to, że implementacja dla nich powinna być zapewniona głównie przez klasy implementujące, które obejmują:

ContextWrapper
Application
Activity
Service
IntentService

Patrząc na dokumentację API, hierarchia klas wygląda następująco:

Kontekst

| - ContextWrapper

|- - zastosowanie

| - - - ContextThemeWrapper

|- - - - aktywność

| - - serwis

|- - - IntentService

Ponieważ wiemy, że Context samo w sobie nie dostarcza żadnych insight, poruszamy się w dół drzewa i spojrzymy na ContextWrapper i zdajemy sobie sprawę, że tam też nie ma wiele. Ponieważ aplikacja rozszerza ContextWrapper, nie ma na co patrzeć, ponieważ nie nadpisuje implementacji dostarczonej przez ContextWrapper. Oznacza to, że implementacja kontekstu jest dostarczana przez system operacyjny i jest ukryta przed API. Możesz przyjrzeć się konkretnej implementacji dla kontekstu, patrząc na źródło dla klasy ContextImpl.

 1
Author: Chanaka Weerasinghe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-02 07:48:03

Używałem tylko tego i getBaseContext podczas toastowania z onClick (bardzo zielony noob zarówno do Javy jak i Androida). Używam tego, gdy mój zatrzask jest bezpośrednio w aktywności i muszę użyć getBaseContext w anonimowym wewnętrznym zatrzasku. Domyślam się, że jest to prawie sztuczka z getBaseContext, być może jest to zwrócenie kontekstu aktywności, w której ukrywa się Klasa wewnętrzna.

 0
Author: Tony,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-12 17:15:12