Use LiveData to update UI and prevent context leak
app/src/main/java/eu/lepiller/nani/DictionaryActivity.java
| 4 | 4 | import android.os.AsyncTask; | |
| 5 | 5 | import android.os.Bundle; | |
| 6 | 6 | import androidx.appcompat.app.AppCompatActivity; | |
| 7 | + | import androidx.lifecycle.LiveData; | |
| 8 | + | import androidx.lifecycle.MutableLiveData; | |
| 9 | + | import androidx.lifecycle.Observer; | |
| 7 | 10 | import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; | |
| 8 | 11 | ||
| 9 | 12 | import android.util.Log; | |
… | |||
| 28 | 31 | ||
| 29 | 32 | public class DictionaryActivity extends AppCompatActivity { | |
| 30 | 33 | static final int DICO_REQUEST = 1; | |
| 31 | - | static final String TAG = "DLIST"; | |
| 34 | + | static final String TAG = "DICO_LIST"; | |
| 32 | 35 | DictionariesAdapter adapter; | |
| 33 | 36 | ArrayList<Dictionary> dictionaries; | |
| 37 | + | private SwipeRefreshLayout refresher; | |
| 34 | 38 | ||
| 35 | 39 | @Override | |
| 36 | 40 | protected void onCreate(Bundle savedInstanceState) { | |
… | |||
| 38 | 42 | setContentView(R.layout.activity_dictionary); | |
| 39 | 43 | ||
| 40 | 44 | final ListView list_view = findViewById(R.id.dictionary_view); | |
| 41 | - | final SwipeRefreshLayout refresher = findViewById(R.id.dictionary_refresh_layout); | |
| 45 | + | refresher = findViewById(R.id.dictionary_refresh_layout); | |
| 42 | 46 | ||
| 43 | 47 | dictionaries = DictionaryFactory.getDictionnaries(getApplicationContext()); | |
| 44 | 48 | adapter = new DictionariesAdapter(this, dictionaries); | |
… | |||
| 47 | 51 | if(dictionaries.size() == 0) { | |
| 48 | 52 | Snackbar.make(findViewById(R.id.dictionary_view), getString(R.string.no_dico_list), | |
| 49 | 53 | Snackbar.LENGTH_LONG).show(); | |
| 50 | - | new DownloadTask(refresher).execute(); | |
| 54 | + | refresh(); | |
| 51 | 55 | } | |
| 52 | 56 | ||
| 53 | 57 | list_view.setOnItemClickListener(new AdapterView.OnItemClickListener() { | |
… | |||
| 58 | 62 | startActivityForResult(intent, DICO_REQUEST); | |
| 59 | 63 | } | |
| 60 | 64 | }); | |
| 65 | + | } | |
| 61 | 66 | ||
| 67 | + | @Override | |
| 68 | + | protected void onResume() { | |
| 69 | + | super.onResume(); | |
| 70 | + | setObserver(); | |
| 62 | 71 | refresher.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { | |
| 63 | 72 | @Override | |
| 64 | 73 | public void onRefresh() { | |
| 65 | - | new DownloadTask(refresher).execute(); | |
| 74 | + | refresh(); | |
| 66 | 75 | } | |
| 67 | 76 | }); | |
| 77 | + | updateDataSet(); | |
| 68 | 78 | } | |
| 69 | 79 | ||
| 70 | 80 | @Override | |
| 71 | - | protected void onResume() { | |
| 72 | - | super.onResume(); | |
| 73 | - | updateDataset(); | |
| 81 | + | protected void onPause() { | |
| 82 | + | unsetObserver(); | |
| 83 | + | super.onPause(); | |
| 84 | + | } | |
| 85 | + | ||
| 86 | + | private void refresh() { | |
| 87 | + | new DownloadTask().execute(); | |
| 74 | 88 | } | |
| 75 | 89 | ||
| 76 | - | private class DownloadTask extends AsyncTask<String, Integer, Integer> { | |
| 77 | - | private SwipeRefreshLayout refresher; | |
| 90 | + | private void setObserver() { | |
| 91 | + | LiveData<Boolean> data = DownloadTask.getRefreshingData(); | |
| 92 | + | data.observe(this, new Observer<Boolean>() { | |
| 93 | + | @Override | |
| 94 | + | public void onChanged(Boolean refreshing) { | |
| 95 | + | refresher.setRefreshing(refreshing); | |
| 96 | + | } | |
| 97 | + | }); | |
| 98 | + | } | |
| 78 | 99 | ||
| 79 | - | DownloadTask(SwipeRefreshLayout r) { | |
| 80 | - | refresher = r; | |
| 100 | + | private void unsetObserver() { | |
| 101 | + | LiveData<Boolean> data = DownloadTask.getRefreshingData(); | |
| 102 | + | data.removeObservers(this); | |
| 103 | + | } | |
| 104 | + | ||
| 105 | + | private static class DownloadTask extends AsyncTask<String, Integer, Integer> { | |
| 106 | + | final private static MutableLiveData<Boolean> refreshing = new MutableLiveData<>(); | |
| 107 | + | ||
| 108 | + | static LiveData<Boolean> getRefreshingData() { | |
| 109 | + | return refreshing; | |
| 81 | 110 | } | |
| 82 | 111 | ||
| 83 | 112 | @Override | |
| 84 | 113 | protected Integer doInBackground(String... strings) { | |
| 114 | + | refreshing.postValue(true); | |
| 85 | 115 | try { | |
| 86 | 116 | URL url = DictionaryFactory.getListUrl(); | |
| 87 | 117 | HttpURLConnection connection = (HttpURLConnection) url.openConnection(); | |
… | |||
| 119 | 149 | @Override | |
| 120 | 150 | protected void onPostExecute(Integer i) { | |
| 121 | 151 | super.onPostExecute(i); | |
| 122 | - | refresher.setRefreshing(false); | |
| 123 | - | updateDataset(); | |
| 124 | - | if(i == null) | |
| 125 | - | return; | |
| 126 | - | Snackbar.make(findViewById(R.id.dictionary_view), getString(i), | |
| 127 | - | Snackbar.LENGTH_LONG).show(); | |
| 152 | + | refreshing.setValue(false); | |
| 128 | 153 | } | |
| 129 | 154 | } | |
| 130 | 155 | ||
| 131 | - | private void updateDataset() { | |
| 156 | + | private void updateDataSet() { | |
| 132 | 157 | DictionaryFactory.updatePackageList(); | |
| 133 | 158 | dictionaries.clear(); | |
| 134 | 159 | dictionaries.addAll(DictionaryFactory.getDictionnaries(getApplicationContext())); | |
… | |||
| 139 | 164 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { | |
| 140 | 165 | super.onActivityResult(requestCode, resultCode, data); | |
| 141 | 166 | if (requestCode == DICO_REQUEST) { | |
| 142 | - | DictionaryFactory.updatePackageList(); | |
| 143 | - | adapter.notifyDataSetChanged(); | |
| 167 | + | updateDataSet(); | |
| 144 | 168 | } | |
| 145 | 169 | } | |
| 146 | 170 | ||