Skip to content

Commit 5802270

Browse files
authored
Refactoring: Proper data class BitmapLoadingWorkerJob.Result & clean up surroundings. (#515)
1 parent e77fa80 commit 5802270

3 files changed

Lines changed: 80 additions & 98 deletions

File tree

cropper/src/main/kotlin/com/canhub/cropper/BitmapCroppingWorkerJob.kt

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -133,25 +133,20 @@ internal class BitmapCroppingWorkerJob(
133133
it.onImageCroppingAsyncComplete(result)
134134
}
135135
}
136+
136137
if (!completeCalled && result.bitmap != null) {
137-
// fast release of unused bitmap
138+
// Fast release of unused bitmap.
138139
result.bitmap.recycle()
139140
}
140141
}
141142
}
142143

143-
fun cancel() {
144-
job.cancel()
145-
}
144+
fun cancel() = job.cancel()
146145

147146
internal data class Result(
148-
/** The cropped bitmap. */
149147
val bitmap: Bitmap?,
150-
/** The saved cropped bitmap uri. */
151148
val uri: Uri?,
152-
/** The error that occurred during async bitmap cropping. */
153149
val error: Exception?,
154-
/** Sample size used creating the crop bitmap to lower its size. */
155150
val sampleSize: Int,
156151
)
157152
}

cropper/src/main/kotlin/com/canhub/cropper/BitmapLoadingWorkerJob.kt

Lines changed: 33 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,24 @@ import kotlin.coroutines.CoroutineContext
1515
internal class BitmapLoadingWorkerJob internal constructor(
1616
private val context: Context,
1717
cropImageView: CropImageView,
18-
val uri: Uri,
18+
internal val uri: Uri,
1919
) : CoroutineScope {
2020
private val width: Int
2121
private val height: Int
2222
private val cropImageViewReference = WeakReference(cropImageView)
23-
private var currentJob: Job = Job()
23+
private var job: Job = Job()
2424

25-
override val coroutineContext: CoroutineContext get() = Dispatchers.Main + currentJob
25+
override val coroutineContext: CoroutineContext get() = Dispatchers.Main + job
2626

2727
init {
2828
val metrics = cropImageView.resources.displayMetrics
29-
val densityAdj = if (metrics.density > 1) (1.0 / metrics.density) else 1.0
30-
width = (metrics.widthPixels * densityAdj).toInt()
31-
height = (metrics.heightPixels * densityAdj).toInt()
29+
val densityAdjustment = if (metrics.density > 1) (1.0 / metrics.density) else 1.0
30+
width = (metrics.widthPixels * densityAdjustment).toInt()
31+
height = (metrics.heightPixels * densityAdjustment).toInt()
3232
}
3333

3434
fun start() {
35-
currentJob = launch(Dispatchers.Default) {
35+
job = launch(Dispatchers.Default) {
3636
try {
3737
if (isActive) {
3838
val decodeResult = BitmapUtils.decodeSampledBitmap(
@@ -41,6 +41,7 @@ internal class BitmapLoadingWorkerJob internal constructor(
4141
reqWidth = width,
4242
reqHeight = height,
4343
)
44+
4445
if (isActive) {
4546
val orientateResult = BitmapUtils.orientateBitmapByExif(
4647
bitmap = decodeResult.bitmap,
@@ -56,21 +57,27 @@ internal class BitmapLoadingWorkerJob internal constructor(
5657
degreesRotated = orientateResult.degrees,
5758
flipHorizontally = orientateResult.flipHorizontally,
5859
flipVertically = orientateResult.flipVertically,
60+
error = null,
5961
),
6062
)
6163
}
6264
}
6365
} catch (e: Exception) {
64-
onPostExecute(Result(uri, e))
66+
onPostExecute(
67+
Result(
68+
uri = uri,
69+
bitmap = null,
70+
loadSampleSize = 0,
71+
degreesRotated = 0,
72+
flipHorizontally = false,
73+
flipVertically = false,
74+
error = e,
75+
),
76+
)
6577
}
6678
}
6779
}
6880

69-
/**
70-
* Once complete, see if ImageView is still around and set bitmap.
71-
*
72-
* [result] the result of bitmap loading
73-
*/
7481
private suspend fun onPostExecute(result: Result) {
7582
withContext(Dispatchers.Main) {
7683
var completeCalled = false
@@ -80,65 +87,23 @@ internal class BitmapLoadingWorkerJob internal constructor(
8087
it.onSetImageUriAsyncComplete(result)
8188
}
8289
}
90+
8391
if (!completeCalled && result.bitmap != null) {
84-
// fast release of unused bitmap
92+
// Fast release of unused bitmap.
8593
result.bitmap.recycle()
8694
}
8795
}
8896
}
8997

90-
fun cancel() {
91-
currentJob.cancel()
92-
}
93-
94-
/** The result of BitmapLoadingWorkerJob async loading. */
95-
internal companion object class Result {
96-
/**
97-
* The Android URI of the image to load.
98-
*/
99-
val uriContent: Uri
100-
101-
/** The loaded bitmap. */
102-
val bitmap: Bitmap?
103-
104-
/** The sample size used to load the given bitmap. */
105-
val loadSampleSize: Int
106-
107-
/** The degrees the image was rotated. */
108-
val degreesRotated: Int
109-
110-
/** If the image was flipped horizontally. */
111-
var flipHorizontally: Boolean = false
112-
113-
/** If the image was flipped vertically. */
114-
var flipVertically: Boolean = false
115-
116-
/** The error that occurred during async bitmap loading. */
117-
val error: Exception?
118-
119-
internal constructor(
120-
uri: Uri,
121-
bitmap: Bitmap?,
122-
loadSampleSize: Int,
123-
degreesRotated: Int,
124-
flipHorizontally: Boolean,
125-
flipVertically: Boolean,
126-
) {
127-
uriContent = uri
128-
this.bitmap = bitmap
129-
this.loadSampleSize = loadSampleSize
130-
this.degreesRotated = degreesRotated
131-
this.flipHorizontally = flipHorizontally
132-
this.flipVertically = flipVertically
133-
error = null
134-
}
135-
136-
internal constructor(uri: Uri, error: Exception?) {
137-
uriContent = uri
138-
bitmap = null
139-
loadSampleSize = 0
140-
degreesRotated = 0
141-
this.error = error
142-
}
143-
}
98+
fun cancel() = job.cancel()
99+
100+
internal data class Result(
101+
val uri: Uri,
102+
val bitmap: Bitmap?,
103+
val loadSampleSize: Int,
104+
val degreesRotated: Int,
105+
val flipHorizontally: Boolean,
106+
val flipVertically: Boolean,
107+
val error: Exception?,
108+
)
144109
}

cropper/src/main/kotlin/com/canhub/cropper/CropImageView.kt

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,13 @@ class CropImageView @JvmOverloads constructor(
467467
if (resId != 0) {
468468
mCropOverlayView!!.initialCropWindowRect = null
469469
val bitmap = BitmapFactory.decodeResource(resources, resId)
470-
setBitmap(bitmap, resId, null, 1, 0)
470+
setBitmap(
471+
bitmap = bitmap,
472+
imageResource = resId,
473+
imageUri = null,
474+
loadSampleSize = 1,
475+
degreesRotated = 0,
476+
)
471477
}
472478
}
473479

@@ -727,7 +733,13 @@ class CropImageView @JvmOverloads constructor(
727733
*/
728734
fun setImageBitmap(bitmap: Bitmap?) {
729735
mCropOverlayView!!.initialCropWindowRect = null
730-
setBitmap(bitmap, 0, null, 1, 0)
736+
setBitmap(
737+
bitmap = bitmap,
738+
imageResource = 0,
739+
imageUri = null,
740+
loadSampleSize = 1,
741+
degreesRotated = 0,
742+
)
731743
}
732744

733745
/**
@@ -754,7 +766,13 @@ class CropImageView @JvmOverloads constructor(
754766
}
755767

756768
mCropOverlayView!!.initialCropWindowRect = null
757-
setBitmap(setBitmap, 0, null, 1, degreesRotated)
769+
setBitmap(
770+
bitmap = setBitmap,
771+
imageResource = 0,
772+
imageUri = null,
773+
loadSampleSize = 1,
774+
degreesRotated = degreesRotated,
775+
)
758776
}
759777

760778
/**
@@ -766,15 +784,11 @@ class CropImageView @JvmOverloads constructor(
766784
*/
767785
fun setImageUriAsync(uri: Uri?) {
768786
if (uri != null) {
769-
val currentTask =
770-
if (bitmapLoadingWorkerJob != null) bitmapLoadingWorkerJob!!.get() else null
771-
currentTask?.cancel()
772-
// either no existing task is working or we canceled it, need to load new URI
787+
bitmapLoadingWorkerJob?.get()?.cancel()
773788
clearImageInt()
774789
mCropOverlayView!!.initialCropWindowRect = null
775-
bitmapLoadingWorkerJob =
776-
WeakReference(BitmapLoadingWorkerJob(context, this, uri))
777-
bitmapLoadingWorkerJob!!.get()!!.start()
790+
bitmapLoadingWorkerJob = WeakReference(BitmapLoadingWorkerJob(context, this, uri))
791+
bitmapLoadingWorkerJob?.get()?.start()
778792
setProgressBarVisibility()
779793
}
780794
}
@@ -908,14 +922,18 @@ class CropImageView @JvmOverloads constructor(
908922
mFlipHorizontally = result.flipHorizontally
909923
mFlipVertically = result.flipVertically
910924
setBitmap(
911-
result.bitmap,
912-
0,
913-
result.uriContent,
914-
result.loadSampleSize,
915-
result.degreesRotated,
925+
bitmap = result.bitmap,
926+
imageResource = 0,
927+
imageUri = result.uri,
928+
loadSampleSize = result.loadSampleSize,
929+
degreesRotated = result.degreesRotated,
916930
)
917931
}
918-
mOnSetImageUriCompleteListener?.onSetImageUriComplete(this, result.uriContent, result.error)
932+
mOnSetImageUriCompleteListener?.onSetImageUriComplete(
933+
view = this,
934+
uri = result.uri,
935+
error = result.error,
936+
)
919937
}
920938

921939
/**
@@ -1092,11 +1110,9 @@ class CropImageView @JvmOverloads constructor(
10921110
bundle.putString("LOADED_IMAGE_STATE_BITMAP_KEY", key)
10931111
}
10941112

1095-
if (bitmapLoadingWorkerJob != null) {
1096-
val task = bitmapLoadingWorkerJob!!.get()
1097-
if (task != null) {
1098-
bundle.putParcelable("LOADING_IMAGE_URI", task.uri)
1099-
}
1113+
val task = bitmapLoadingWorkerJob?.get()
1114+
if (task != null) {
1115+
bundle.putParcelable("LOADING_IMAGE_URI", task.uri)
11001116
}
11011117

11021118
bundle.putParcelable("instanceState", super.onSaveInstanceState())
@@ -1131,7 +1147,13 @@ class CropImageView @JvmOverloads constructor(
11311147
}
11321148
BitmapUtils.mStateBitmap = null
11331149
if (stateBitmap != null && !stateBitmap.isRecycled) {
1134-
setBitmap(stateBitmap, 0, uri, state.getInt("LOADED_SAMPLE_SIZE"), 0)
1150+
setBitmap(
1151+
bitmap = stateBitmap,
1152+
imageResource = 0,
1153+
imageUri = uri,
1154+
loadSampleSize = state.getInt("LOADED_SAMPLE_SIZE"),
1155+
degreesRotated = 0,
1156+
)
11351157
}
11361158
}
11371159
imageUri ?: setImageUriAsync(uri)

0 commit comments

Comments
 (0)