Jak poprawnie korzystać z obiektu Context w Androidzie
Context to jeden z najważniejszych obiektów w Androidzie - oznacza on kontekst obecnego stanu aplikacji i odpowiada za:
- Zdobywanie informacji dotyczących aktywności oraz aplikacji
- Zdobywanie dostępu do bazy danych, zasobów dotyczących jakiejś aplikacji (potrzebny tekst, drawable itd.) oraz do klas, systemów plików i współdzielonych preferencji
- Up-calls dla operacji na poziomie aplikacji, takich jak uruchamianie aktywności, broadcasting i otrzymywanie intencji (intents).
Jak widać, w Androidzie prawie wszystko musi mieć dostęp do obiektu Context. Jeśli użyjemy go w nieprawidłowy sposób, to możemy wywołać wyciek pamięci. Istnieją dwa typy obiektu Context:
- Application Context: ten rodzaj obiektu Context jest ściśle powiązany z cyklem życia aplikacji. Oznacza to, że jeśli aplikacja nie została uśmiercona, to Context jest nadal dostępny. Zwykle jest to singleton, do którego dostęp można uzyskać z poziomu
getApplicationContext()
. Istotną rzeczą jest tutaj jednak to, że nie jest to kontekst związany z UI. Jeśli chcemy więc rozpocząć jakąś aktywność przy użyciu intencji, pokazania toasta lub czegokolwiek innego związanego z UI, to nawet jeżeli pobieramy, coś co będzie korzystać z motywów, to nie powinniśmy używać kontekstu aplikacji. Zauważ, że trzymanie referencji do aktywności w długo żyjącym obiekcie, czy wątku, może spowodować wyciek pamięci. W takim przypadku także wykorzystaj Context aplikacji. Oto lista funkcji Context w danej aplikacji:
- Załaduj wartości zasobów
- Uruchom serwis
- Połącz z serwisem
- Wyślij transmisję
- Zarejestruj broadcastReceiver
- Activity Context: ten rodzaj obiektu Context jest związany z cyklem życia aktywności. Można do niego uzyskać dostęp przez
getContext()
, jeśli activity nadal żyje. Z Activity Context powinno się korzystać, kiedy chcemy wywołać kontekst z obecnie działającego activity oraz z operacji związanych z UI - na przykład:
- Załaduj wartości zasobów
- Stwórz layout
- Uruchom aktywność
- Pokaż dialog albo toast
- Uruchom serwis
- Połącz z serwisem
- Wyślij transmisję
- Zarejestruj broadcastReceiver
Oprócz getApplicationContext()
i getContext()
, to jako Context w Androidzie zauważysz jeszcze getBaseContext()
oraz this
. getBaseContext()
to metoda ContextWrappera, która:
Tworzy proxy implementacji obiektu Context, które deleguje wszystkie jego wywołania do innego kontekstu. Można stworzyć z niego podklasę, aby modyfikować zachowania bez zmieniania kontekstu oryginalnego.
getBaseContext()
pozwala nam na pobranie obecnego kontekstu znajdującego się wewnątrz ContexWrappera.
this
odnosi się również do instancji klasy i można go używać, gdy Context jest potrzebny wewnątrz danego activity. Poniżej mamy kilka przypadków użycia, które wymagają obiektu Context korzystającego z Javy i Kotlina:
//if you want to start the activity from an activity, you should pass 'this' as context.
val intent = Intent(this, <YourClassname>::class.java)
startActivity(intent)
//view.getContext() refers to the current activity view.
listView.setOnItemClickListener { parent, view, position, id ->
val myElement = adapter.getItemAtPosition(position)
val intent = Intent(view.getContext(), <YourClassname>::class.java)
view.getContext().startActivity(intent)
}
public class ApplicationListAdapter extends RecyclerView.Adapter<
ApplicationListAdapter.ApplicationListViewHolder> {
...
@NonNull
@Override
public ApplicationListAdapter.ApplicationListViewHolder onCreateViewHolder(
@NonNull ViewGroup parent, int viewType) {
//the correct context can be inferred from the parent view as 'parent.getContext()' for inflation.
View view =
LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_row_application, parent, false);
return new ApplicationListViewHolder(view);
}
...
public class ApplicationListViewHolder extends RecyclerView.ViewHolder {
private final ImageView mApplication_icon;
public ApplicationListViewHolder(@NonNull View itemView) {
super(itemView);
mApplication_icon = itemView.findViewById(R.id.application_image);
}
private void bind(Application application) {
//Context is needed outside of the onCreateViewHolder() method which is retrieved via 'itemView.getContext()'.
Glide.with(itemView.getContext())
.load(application.getIcon())
.placeholder(R.mipmap.ic_launcher)
.into(mApplication_icon);
}
}
...
}
Oryginał tekstu w języku angielskim możesz przeczytać tutaj.