Sou desenvolvedor java há 2 anos.
Mas eu nunca escrevi uma WeakReference no meu código. Como usar o WeakReference para tornar meu aplicativo mais eficiente, especialmente o aplicativo Android?
Sou desenvolvedor java há 2 anos.
Mas eu nunca escrevi uma WeakReference no meu código. Como usar o WeakReference para tornar meu aplicativo mais eficiente, especialmente o aplicativo Android?
Respostas:
Usar um WeakReference
no Android não é diferente de usar um no Java antigo comum. Aqui está um ótimo guia que fornece uma explicação detalhada: Noções básicas sobre referências fracas .
Você deve pensar em usar um sempre que precisar de uma referência a um objeto, mas não deseja que essa referência proteja o objeto do coletor de lixo. Um exemplo clássico é um cache no qual você deseja coletar lixo quando o uso da memória fica muito alto (geralmente implementado com WeakHashMap
).
Certifique-se de verificar SoftReference
e PhantomReference
também.
EDIT: Tom levantou algumas preocupações sobre a implementação de um cache com WeakHashMap
. Aqui está um artigo descrevendo os problemas: WeakHashMap não é um cache!
Tom está certo de que houve reclamações sobre o fraco desempenho do Netbeans devido ao WeakHashMap
cache.
Ainda acho que seria uma boa experiência de aprendizado implementar um cache WeakHashMap
e compará-lo com seu próprio cache implementado manualmente SoftReference
. No mundo real, você provavelmente não usaria nenhuma dessas soluções, pois faz mais sentido usar uma biblioteca de terceiros como o Apache JCS .
WeakHashMap
usado como cache é fatal. As entradas podem ser removidas assim que são criadas. Provavelmente isso não acontecerá quando você estiver testando, mas pode muito bem quando estiver em uso. É importante notar que o NetBeans pode ser levado a uma parada efetiva de 100% da CPU.
WeakHashMap
mesmo se você está correto que é uma má escolha;)
[EDIT2] Encontrei outro bom exemplo de WeakReference
. Processando bitmaps Fora da página Thread da interface do usuário no guia de treinamento Exibindo bitmaps com eficiência , mostra um uso WeakReference
no AsyncTask.
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private int data = 0;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
// Decode image in background.
@Override
protected Bitmap doInBackground(Integer... params) {
data = params[0];
return decodeSampledBitmapFromResource(getResources(), data, 100, 100));
}
// Once complete, see if ImageView is still around and set bitmap.
@Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
Diz,
O WeakReference para o ImageView garante que o AsyncTask não impeça que o ImageView e tudo o que ele referencia seja coletado como lixo . Não há garantia de que o ImageView ainda esteja disponível quando a tarefa terminar, portanto, você também deve verificar a referência em onPostExecute (). O ImageView pode não existir mais, se, por exemplo, o usuário sair da atividade ou se ocorrer uma alteração na configuração antes que a tarefa seja concluída.
Feliz codificação!
[EDIT] Encontrei um bom exemplo WeakReference
do facebook-android-sdk . A classe ToolTipPopup nada mais é do que uma simples classe de widget que mostra a dica de ferramenta acima da visualização âncora. Eu capturei uma captura de tela.
A aula é realmente simples (cerca de 200 linhas) e digna de ser vista. Nessa classe, a WeakReference
classe é usada para manter referência à exibição de âncora, o que faz todo sentido, porque possibilita que a exibição de âncora seja coletada como lixo, mesmo quando uma instância de dica de ferramenta vive mais que sua exibição de âncora.
Feliz codificação! :)
Deixe-me compartilhar um exemplo WeakReference
prático de classe. É um pequeno trecho de código do widget de estrutura do Android chamado AutoCompleteTextView
.
Em resumo, a WeakReference
classe é usada para armazenar View
objetos para evitar vazamento de memória neste exemplo.
Vou copiar e colar a classe PopupDataSetObserver, que é uma classe aninhada AutoCompleteTextView
. É realmente simples e os comentários explicam bem a classe. Feliz codificação! :)
/**
* Static inner listener that keeps a WeakReference to the actual AutoCompleteTextView.
* <p>
* This way, if adapter has a longer life span than the View, we won't leak the View, instead
* we will just leak a small Observer with 1 field.
*/
private static class PopupDataSetObserver extends DataSetObserver {
private final WeakReference<AutoCompleteTextView> mViewReference;
private PopupDataSetObserver(AutoCompleteTextView view) {
mViewReference = new WeakReference<AutoCompleteTextView>(view);
}
@Override
public void onChanged() {
final AutoCompleteTextView textView = mViewReference.get();
if (textView != null && textView.mAdapter != null) {
// If the popup is not showing already, showing it will cause
// the list of data set observers attached to the adapter to
// change. We can't do it from here, because we are in the middle
// of iterating through the list of observers.
textView.post(updateRunnable);
}
}
private final Runnable updateRunnable = new Runnable() {
@Override
public void run() {
final AutoCompleteTextView textView = mViewReference.get();
if (textView == null) {
return;
}
final ListAdapter adapter = textView.mAdapter;
if (adapter == null) {
return;
}
textView.updateDropDownForFilter(adapter.getCount());
}
};
}
E o PopupDataSetObserver
é usado na configuração do adaptador.
public <T extends ListAdapter & Filterable> void setAdapter(T adapter) {
if (mObserver == null) {
mObserver = new PopupDataSetObserver(this);
} else if (mAdapter != null) {
mAdapter.unregisterDataSetObserver(mObserver);
}
mAdapter = adapter;
if (mAdapter != null) {
//noinspection unchecked
mFilter = ((Filterable) mAdapter).getFilter();
adapter.registerDataSetObserver(mObserver);
} else {
mFilter = null;
}
mPopup.setAdapter(mAdapter);
}
Uma última coisa. Eu também queria saber o exemplo de trabalho WeakReference
no aplicativo Android e poderia encontrar alguns exemplos em seus aplicativos oficiais. Mas eu realmente não conseguia entender o uso de alguns deles. Por exemplo, os aplicativos ThreadSample e ExibindoBitmaps usam WeakReference
em seu código, mas depois de executar vários testes, descobri que o método get () nunca retorna null
, porque o objeto de exibição referenciado é reciclado em adaptadores, e não em lixo coletado.
Algumas das outras respostas parecem incompletas ou excessivamente longas. Aqui está uma resposta geral.
Você pode executar as seguintes etapas:
WeakReference
variávelMyClass
tem uma referência fraca a AnotherClass
.
public class MyClass {
// 1. Create a WeakReference variable
private WeakReference<AnotherClass> mAnotherClassReference;
// 2. Set the weak reference (nothing special about the method name)
void setWeakReference(AnotherClass anotherClass) {
mAnotherClassReference = new WeakReference<>(anotherClass);
}
// 3. Use the weak reference
void doSomething() {
AnotherClass anotherClass = mAnotherClassReference.get();
if (anotherClass == null) return;
// do something with anotherClass
}
}
AnotherClass
tem uma forte referência a MyClass
.
public class AnotherClass {
// strong reference
MyClass mMyClass;
// allow MyClass to get a weak reference to this class
void someMethod() {
mMyClass = new MyClass();
mMyClass.setWeakReference(this);
}
}
MyClass
estava A e AnotherClass
foi B.WeakReference
é fazer com que outra classe implemente uma interface. Isso é feito no padrão de ouvinte / observador .// allow MyClass to get a weak reference to this class void someMethod() { mMyClass = new MyClass(); mMyClass.someMethod(this); }
??
weakreference
próprio objeto na doSomething
função para não estar null
antes de chamar a get
função.
Um mapeamento "canonizado" é o local onde você mantém uma instância do objeto em questão na memória e todas as outras pesquisam essa instância em particular por meio de ponteiros ou de algum mecanismo desse tipo. É aqui que as referências fracas podem ajudar. A resposta curta é que WeakReference objetos podem ser usados para criar ponteiros para objetos em seu sistema, enquanto ainda permitem que esses objetos sejam recuperados pelo coletor de lixo depois que eles saem do escopo. Por exemplo, se eu tivesse um código como este:
class Registry {
private Set registeredObjects = new HashSet();
public void register(Object object) {
registeredObjects.add( object );
}
}
Qualquer objeto que eu registrar nunca será recuperado pelo GC porque há uma referência a ele armazenado no conjunto de registeredObjects
. Por outro lado, se eu fizer isso:
class Registry {
private Set registeredObjects = new HashSet();
public void register(Object object) {
registeredObjects.add( new WeakReference(object) );
}
}
Então, quando o GC quiser recuperar os objetos no Conjunto, poderá fazê-lo. Você pode usar esta técnica para armazenar em cache, catalogar etc. Veja abaixo as referências a discussões muito mais aprofundadas sobre GC e armazenamento em cache.