Cet article
Ceci est une suite du message intitulé "Référence implicite des objets englobants détenus par des classes imbriquées non statiques".
Par conséquent, je vous serais reconnaissant si vous pouviez y jeter un coup d'œil en premier.
Cet article est, pour le dire franchement, "Ajouter le modificateur static
à la classe imbriquée".
Dès que vous le démarrez, le décompte commencera par incréments d'une seconde. Si vous partez de START!, Comptez jusqu'à "9" et vous avez terminé. (Ce GIF animé est une animation qui se répète START! Quand il atteint 3, mais je suis désolé car il n'y a aucun moyen d'arrêter le GIF animé collé sur cette Qiita)
L'environnement est le suivant.
Android Studio 3.6.1 Build #AI-192.7142.36.36.6241897, built on February 27, 2020 Runtime version: 1.8.0_212-release-1586-b04 amd64 VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o Windows 10 10.0 GC: ParNew, ConcurrentMarkSweep Memory: 1237M Cores: 8 Registry: ide.new.welcome.screen.force=true Non-Bundled Plugins:
Non développé à Kotlin. Je vais le faire en Java.
L'activité de cette application est la suivante.
MainActivity.java
public class MainActivity extends AppCompatActivity {
private TextView textView;
private MyTask task;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.text_view);
task = new MyTask();
task.execute();
}
@Override
protected void onDestroy() {
super.onDestroy();
task.cancel(true);
}
class MyTask extends AsyncTask<Void, String, Void> {
@Override
protected Void doInBackground(Void... voids) {
for (int i = 0; i < 10; i++) { if (isCancelled()) {
return null; // break;Mais peut-être
}
try {
Thread.sleep(1000);
publishProgress(String.valueOf(i));
} catch (InterruptedException e) {
Log.e("MyTask", e.getMessage(), e);
}
}
return null;
}
@Override
protected void onProgressUpdate(String... values) {
textView.setText(values[0]);
}
}
}
Ensuite, Android Studio donne cet avertissement.
This 'AsyncTask' class should be static or leaks might occur
Je blâme la classe imbriquée nommée MyTask
pour ne pas avoir le modificateur static
.
Le but de cet article est d'éviter d'émettre cet avertissement.
Tout d'abord, je posterai le code de la conclusion.
Nous décidons de conserver la ** référence faible ** de l'objet de classe englobante MainActicity
dans l'objet de classe imbriqué statique. Alors, utilisez java.lang.ref.WeakReference
.
La meilleure solution
public class MainActivityGood extends AppCompatActivity {
//Arrêtez le champ TextView.
private MyTask task;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.text_view);
//Passez-vous ça? Pourquoi? C'est parce que j'ai un constructeur dans MyTask.
task = new MyTask(this);
task.execute(textView);
}
@Override
protected void onDestroy() {
super.onDestroy();
task.cancel(true);
}
static class MyTask extends AsyncTask<Void, String, Void> {
WeakReference<Activity> activityReference; //Attention ici!
//J'ai un constructeur.
public MyTask(Activity activity) {
//Nous conserverons l'objet de la classe englobante avec une référence faible.
activityReference= new WeakReference<>(activity);
}
@Override
protected Void doInBackground(Void... voids) {
for (int i = 0; i < 10; i++) { if (isCancelled()) {
return null; // break;Mais peut-être
}
try {
Thread.sleep(1000);
publishProgress(String.valueOf(i));
} catch (InterruptedException e) {
Log.e("MyTask", e.getMessage(), e);
}
}
return null;
}
@Override
protected void onProgressUpdate(String... values) {
//De faibles références aux objets de la classe englobante peuvent être obtenues avec la méthode get.
Activity activity = activityReference.get();
//Et vérifions si la référence faible obtenue est nulle.
if (activity == null || activity.isFinishing()) {
return; // ※
}
TextView textView = activity.findViewById(R.id.text_view);
textView.setText(values[0]);
}
}
}
La conclusion est comme ça, mais comme c'est un gros problème, j'aimerais avoir un grand cercle à la fin pendant que je suis sur le point d'arriver à cette conclusion.
Comme l'a dit l'avertissement d'Android Studio, j'ai ajouté aveuglément (rires) le modificateur static
à la sous-classe ʻAsyncTask nommée
MyTask`.
Cependant, si vous prenez de telles mesures, vous vous fâcherez en accédant au champ non statique de la classe englobante, comme indiqué dans l'image ci-dessous. Pourquoi. En effet, les classes imbriquées statiques ne peuvent accéder qu'aux membres statiques du composant.
Puis
N'est-il pas bon de modifier MainActivity comme ça? Avec une sensation de facilité
public class MainActivity extends AppCompatActivity {
private static TextView textView;
//Ce qui suit est omis
}
Non, n'est-ce pas un peu différent? Je te blâme.
Cela semble intentionnel, mais jetez un œil. Mais c'est pourquoi l'avertissement d'exemple d'Android Studio disparaît.
MainActivityDasai.java
public class MainActivityDasai extends AppCompatActivity {
private MyTask task;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = findViewById(R.id.text_view);
task = new MyTask();
task.execute(textView);
}
@Override
protected void onDestroy() {
super.onDestroy();
task.cancel(true);
}
static class MyTask extends AsyncTask<TextView, Object, Void> {
@Override
protected Void doInBackground(TextView... textViews) {
for (int i = 0; i < 100000; i++) {
if (isCancelled()) {
return null; // break;Mais peut-être
}
try {
Thread.sleep(1000);
publishProgress(textViews[0], String.valueOf(i));
} catch (InterruptedException e) {
Log.e("MyTask", e.getMessage(), e);
}
}
return null;
}
@Override
protected void onProgressUpdate(Object... values) {
((TextView)values[0]).setText((String)values[1]);
}
}
}
Ma patrouille égare mon corps et mon âme.
--Ce MyTask
est une classe qui n'est utilisée que dans cette MainActivity
, donc je veux en faire une classe imbriquée.
TextTview
maintenant, mais lorsqu'il s'agit de gérer plusieurs autres vues, passer des références est gênant. ** **
――Ensuite, voulez-vous en faire une classe imbriquée?Cette exploration est venue à l'idée que "* Alors, arrêtons de faire de TextView
un champ de la classe englobante! *", Et c'est devenu un programme tellement merdique.
Alors je voulais me reprocher d'avoir écrit ce programme merdique.
Ce que je n'aime pas, c'est que ** j'en ai assez de spécifier ʻObject pour les génériques **. Grâce à cela, la partie de "
((TextView) values [0]). SetText ((String) values [1]); " est castée, et quel est l'index du tableau? Prête à confusion. De plus, je n'aime pas le fait que l'argument de la méthode
doInBackground et le premier générique de ʻAsyncTask
soient TextView
. Que faire si le nombre de vues autres que «TextView» augmente?
J'ai décidé d'utiliser java.lang.ref.WeakReference
et de le traiter comme une ** référence faible **. Veuillez consulter MainActivityGood.java ci-dessus.
Le point est
--Définissez un constructeur pour MyTask
, qui est une classe imbriquée statique.
--Définissez également un champ de type WeakReference
avec la classe englobante spécifiée dans les génériques.
--Et faites-le "nouveau" en utilisant les arguments du constructeur. Cela garde une référence faible pour MainActivityGood
!
MainActivityGood
à partir de WeakReference
(le nom de la méthode est également get ()
) et utilisez-le.Contrairement à la manière merdique ci-dessus, cela facilite le traitement des vues autres que TextView
, et vous n'avez pas à faire la chose stupide de spécifier ʻObject` dans les génériques.
c'est tout.
Ceci est similaire à l'article de Qiita "Cette classe Handler devrait être statique ou des fuites pourraient se produire".
ʻAndroid.os.AsyncTask` est obsolète depuis le niveau d'API R [^ 1]. Cet article est également voué à être obsolète ...
[^ 1]: Bien que le niveau d'API soit indiqué par un nombre, il est "R" au moment de la rédaction de cet article.
L'alternative est
--Utilisez le package java.util.concurrent comme standard ou -Utilisez les utilitaires de concurrence Kotlin.
... Apparemment ... Ce dernier est, par essence, les Coroutines de Kotlin.
Recommended Posts