Skip to content

Commit 7bf98da

Browse files
committed
Fix Lint errors and use viewBinding in ImagesFragment
1 parent f85a851 commit 7bf98da

File tree

2 files changed

+96
-99
lines changed

2 files changed

+96
-99
lines changed

app/build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ android {
3131
minifyEnabled false
3232
}
3333
}
34+
35+
buildFeatures {
36+
viewBinding true
37+
}
38+
3439
compileOptions {
3540
sourceCompatibility = JavaVersion.VERSION_17
3641
targetCompatibility = JavaVersion.VERSION_17

app/src/main/java/ai/elimu/content_provider/ui/image/ImagesFragment.kt

Lines changed: 91 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package ai.elimu.content_provider.ui.image
22

33
import ai.elimu.content_provider.BaseApplication
44
import ai.elimu.content_provider.R
5+
import ai.elimu.content_provider.databinding.FragmentImagesBinding
56
import ai.elimu.content_provider.rest.ImagesService
67
import ai.elimu.content_provider.room.GsonToRoomConverter
78
import ai.elimu.content_provider.room.db.RoomDb
@@ -14,55 +15,49 @@ import android.util.Log
1415
import android.view.LayoutInflater
1516
import android.view.View
1617
import android.view.ViewGroup
17-
import android.widget.ProgressBar
18-
import android.widget.TextView
1918
import androidx.fragment.app.Fragment
20-
import androidx.lifecycle.Observer
2119
import androidx.lifecycle.ViewModelProvider
2220
import com.google.android.material.snackbar.Snackbar
21+
import kotlinx.coroutines.CoroutineScope
22+
import kotlinx.coroutines.Dispatchers
23+
import kotlinx.coroutines.launch
24+
import kotlinx.coroutines.withContext
2325
import retrofit2.Call
2426
import retrofit2.Callback
2527
import retrofit2.Response
2628
import java.io.FileNotFoundException
2729
import java.io.FileOutputStream
2830
import java.io.IOException
29-
import java.util.concurrent.Executors
3031

3132
class ImagesFragment : Fragment() {
32-
private var imagesViewModel: ImagesViewModel? = null
33+
private lateinit var imagesViewModel: ImagesViewModel
3334

34-
private var progressBar: ProgressBar? = null
35-
36-
private var textView: TextView? = null
35+
private lateinit var binding: FragmentImagesBinding
3736

3837
private val TAG = ImagesFragment::class.java.name
3938

4039
override fun onCreateView(
4140
inflater: LayoutInflater,
4241
container: ViewGroup?,
4342
savedInstanceState: Bundle?
44-
): View? {
43+
): View {
4544
Log.i(TAG, "onCreateView")
4645

47-
imagesViewModel = ViewModelProvider(this).get(ImagesViewModel::class.java)
48-
val root = inflater.inflate(R.layout.fragment_images, container, false)
49-
progressBar = root.findViewById(R.id.progress_bar_images)
50-
textView = root.findViewById(R.id.text_images) as? TextView
51-
imagesViewModel!!.text.observe(viewLifecycleOwner, object : Observer<String?> {
52-
override fun onChanged(s: String?) {
53-
Log.i(TAG, "onChanged")
54-
textView?.text = s
55-
}
56-
})
57-
return root
46+
imagesViewModel = ViewModelProvider(this)[ImagesViewModel::class.java]
47+
binding = FragmentImagesBinding.inflate(layoutInflater)
48+
imagesViewModel.text.observe(viewLifecycleOwner) { s ->
49+
Log.i(TAG, "onChanged")
50+
binding.textImages.text = s
51+
}
52+
return binding.root
5853
}
5954

6055
override fun onStart() {
6156
Log.i(TAG, "onStart")
6257
super.onStart()
6358

6459
// Download Images from REST API, and store them in the database
65-
val baseApplication = activity!!.application as BaseApplication
60+
val baseApplication = activity?.application as? BaseApplication ?: return
6661
val retrofit = baseApplication.retrofit
6762
val imagesService = retrofit.create(ImagesService::class.java)
6863
val imageGsonsCall = imagesService.listImages()
@@ -76,18 +71,18 @@ class ImagesFragment : Fragment() {
7671

7772
Log.i(TAG, "response: $response")
7873
if (response.isSuccessful) {
79-
val imageGsons = response.body()!!
74+
val imageGsons = response.body() ?: return
8075
Log.i(TAG, "imageGsons.size(): " + imageGsons.size)
8176

82-
if (imageGsons.size > 0) {
77+
if (imageGsons.isNotEmpty()) {
8378
processResponseBody(imageGsons)
8479
}
8580
} else {
8681
// Handle error
87-
Snackbar.make(textView!!, response.toString(), Snackbar.LENGTH_LONG)
82+
Snackbar.make(binding.textImages, response.toString(), Snackbar.LENGTH_LONG)
8883
.setBackgroundTint(resources.getColor(R.color.deep_orange_darken_4))
8984
.show()
90-
progressBar!!.visibility = View.GONE
85+
binding.progressBarImages.visibility = View.GONE
9186
}
9287
}
9388

@@ -97,93 +92,90 @@ class ImagesFragment : Fragment() {
9792
Log.e(TAG, "t.getCause():", t.cause)
9893

9994
// Handle error
100-
Snackbar.make(textView!!, t.cause.toString(), Snackbar.LENGTH_LONG)
95+
Snackbar.make(binding.textImages, t.cause.toString(), Snackbar.LENGTH_LONG)
10196
.setBackgroundTint(resources.getColor(R.color.deep_orange_darken_4))
10297
.show()
103-
progressBar!!.visibility = View.GONE
98+
binding.progressBarImages.visibility = View.GONE
10499
}
105100
})
106101
}
107102

108103
private fun processResponseBody(imageGsons: List<ImageGson>) {
109104
Log.i(TAG, "processResponseBody")
110105

111-
val executorService = Executors.newSingleThreadExecutor()
112-
executorService.execute(object : Runnable {
113-
override fun run() {
114-
Log.i(TAG, "run")
115-
116-
val roomDb = RoomDb.getDatabase(context)
117-
val imageDao = roomDb.imageDao()
118-
val image_WordDao = roomDb.image_WordDao()
119-
120-
// Empty the database table before downloading up-to-date content
121-
image_WordDao.deleteAll()
122-
imageDao.deleteAll()
123-
124-
// TODO: also delete corresponding image files (only those that are no longer used)
125-
for (imageGson in imageGsons) {
126-
Log.i(TAG, "imageGson.getId(): " + imageGson.id)
127-
128-
val image = GsonToRoomConverter.getImage(imageGson)
129-
130-
// Check if the corresponding image file has already been downloaded
131-
val imageFile = FileHelper.getImageFile(imageGson, context)
132-
Log.i(TAG, "imageFile: $imageFile")
133-
Log.i(TAG, "imageFile.exists(): " + imageFile.exists())
134-
if (!imageFile.exists()) {
135-
// Download file bytes
136-
val baseApplication = activity!!.application as BaseApplication
137-
val downloadUrl = if (imageGson.bytesUrl.startsWith("http"))
138-
imageGson.bytesUrl
139-
else
140-
baseApplication.baseUrl + imageGson.bytesUrl
141-
Log.i(TAG, "downloadUrl: $downloadUrl")
142-
val bytes = MultimediaDownloader.downloadFileBytes(downloadUrl)
143-
Log.i(TAG, "bytes.length: " + bytes.size)
144-
145-
// Store the downloaded file in the external storage directory
146-
try {
147-
val fileOutputStream = FileOutputStream(imageFile)
148-
fileOutputStream.write(bytes)
149-
} catch (e: FileNotFoundException) {
150-
Log.e(TAG, null, e)
151-
} catch (e: IOException) {
152-
Log.e(TAG, null, e)
153-
}
154-
Log.i(TAG, "imageFile.exists(): " + imageFile.exists())
155-
}
156-
157-
// Store the Image in the database
158-
imageDao.insert(image)
159-
Log.i(TAG, "Stored Image in database with ID " + image.id)
160-
161-
// Store all the Image's Word labels in the database
162-
val wordGsons = imageGson.words
163-
Log.i(TAG, "wordGsons.size(): " + wordGsons.size)
164-
for (wordGson in wordGsons) {
165-
Log.i(TAG, "wordGson.getId(): " + wordGson.id)
166-
val image_Word = Image_Word()
167-
image_Word.image_id = imageGson.id
168-
image_Word.words_id = wordGson.id
169-
image_WordDao.insert(image_Word)
170-
Log.i(
171-
TAG,
172-
"Stored Image_Word in database. Image_id: " + image_Word.image_id + ", words_id: " + image_Word.words_id
173-
)
106+
CoroutineScope(Dispatchers.IO).launch {
107+
Log.i(TAG, "run")
108+
109+
val roomDb = RoomDb.getDatabase(context)
110+
val imageDao = roomDb.imageDao()
111+
val image_WordDao = roomDb.image_WordDao()
112+
113+
// Empty the database table before downloading up-to-date content
114+
image_WordDao.deleteAll()
115+
imageDao.deleteAll()
116+
117+
// TODO: also delete corresponding image files (only those that are no longer used)
118+
for (imageGson in imageGsons) {
119+
Log.i(TAG, "imageGson.getId(): " + imageGson.id)
120+
121+
val image = GsonToRoomConverter.getImage(imageGson)
122+
123+
// Check if the corresponding image file has already been downloaded
124+
val imageFile = FileHelper.getImageFile(imageGson, context)
125+
Log.i(TAG, "imageFile: $imageFile")
126+
Log.i(TAG, "imageFile.exists(): " + imageFile.exists())
127+
if (!imageFile.exists()) {
128+
// Download file bytes
129+
val baseApplication = activity?.application as? BaseApplication ?: return@launch
130+
val downloadUrl = if (imageGson.bytesUrl.startsWith("http"))
131+
imageGson.bytesUrl
132+
else
133+
baseApplication.baseUrl + imageGson.bytesUrl
134+
Log.i(TAG, "downloadUrl: $downloadUrl")
135+
val bytes = MultimediaDownloader.downloadFileBytes(downloadUrl)
136+
Log.i(TAG, "bytes.length: " + bytes.size)
137+
138+
// Store the downloaded file in the external storage directory
139+
try {
140+
val fileOutputStream = FileOutputStream(imageFile)
141+
fileOutputStream.write(bytes)
142+
} catch (e: FileNotFoundException) {
143+
Log.e(TAG, null, e)
144+
} catch (e: IOException) {
145+
Log.e(TAG, null, e)
174146
}
147+
Log.i(TAG, "imageFile.exists(): " + imageFile.exists())
175148
}
176149

177-
// Update the UI
178-
val images = imageDao.loadAll()
179-
Log.i(TAG, "images.size(): " + images.size)
180-
activity!!.runOnUiThread {
181-
textView!!.text = "images.size(): " + images.size
182-
Snackbar.make(textView!!, "images.size(): " + images.size, Snackbar.LENGTH_LONG)
183-
.show()
184-
progressBar!!.visibility = View.GONE
150+
// Store the Image in the database
151+
imageDao.insert(image)
152+
Log.i(TAG, "Stored Image in database with ID " + image.id)
153+
154+
// Store all the Image's Word labels in the database
155+
val wordGsons = imageGson.words
156+
Log.i(TAG, "wordGsons.size(): " + wordGsons.size)
157+
for (wordGson in wordGsons) {
158+
Log.i(TAG, "wordGson.getId(): " + wordGson.id)
159+
val image_Word = Image_Word()
160+
image_Word.image_id = imageGson.id
161+
image_Word.words_id = wordGson.id
162+
image_WordDao.insert(image_Word)
163+
Log.i(
164+
TAG,
165+
"Stored Image_Word in database. Image_id: " + image_Word.image_id + ", words_id: " + image_Word.words_id
166+
)
185167
}
186168
}
187-
})
169+
170+
// Update the UI
171+
val images = imageDao.loadAll()
172+
Log.i(TAG, "images.size(): " + images.size)
173+
withContext(Dispatchers.Main) {
174+
binding.textImages.text = "images.size(): " + images.size
175+
Snackbar.make(binding.textImages, "images.size(): " + images.size, Snackbar.LENGTH_LONG)
176+
.show()
177+
binding.progressBarImages.visibility = View.GONE
178+
}
179+
}
188180
}
189181
}

0 commit comments

Comments
 (0)