Merge branch 'performance-tweaks' into 'master'

Performance tweaks

Closes #268

See merge request pixeldroid/PixelDroid!267
This commit is contained in:
Matthieu 2020-12-19 13:33:13 +01:00
commit 10a96a33d4
3 changed files with 85 additions and 78 deletions

View File

@ -67,17 +67,21 @@ class MainActivity : BaseActivity() {
} else { } else {
setupDrawer() setupDrawer()
val tabs: List<Fragment> = listOf( val tabs: List<() -> Fragment> = listOf(
PostFeedFragment<HomeStatusDatabaseEntity>() {
.apply { PostFeedFragment<HomeStatusDatabaseEntity>()
arguments = Bundle().apply { putBoolean("home", true) } .apply {
arguments = Bundle().apply { putBoolean("home", true) }
}
}, },
SearchDiscoverFragment(), { SearchDiscoverFragment() },
CameraFragment(), { CameraFragment() },
NotificationsFragment(), { NotificationsFragment() },
PostFeedFragment<PublicFeedStatusDatabaseEntity>() {
.apply { PostFeedFragment<PublicFeedStatusDatabaseEntity>()
arguments = Bundle().apply { putBoolean("home", false) } .apply {
arguments = Bundle().apply { putBoolean("home", false) }
}
} }
) )
setupTabs(tabs) setupTabs(tabs)
@ -234,13 +238,13 @@ class MainActivity : BaseActivity() {
private fun fillDrawerAccountInfo(account: String) { private fun fillDrawerAccountInfo(account: String) {
val users = db.userDao().getAll().toMutableList() val users = db.userDao().getAll().toMutableList()
users.sortWith(Comparator { l, r -> users.sortWith { l, r ->
when { when {
l.isActive && !r.isActive -> -1 l.isActive && !r.isActive -> -1
r.isActive && !l.isActive -> 1 r.isActive && !l.isActive -> 1
else -> 0 else -> 0
} }
}) }
val profiles: MutableList<IProfile> = users.map { user -> val profiles: MutableList<IProfile> = users.map { user ->
ProfileDrawerItem().apply { ProfileDrawerItem().apply {
isSelected = user.isActive isSelected = user.isActive
@ -264,10 +268,10 @@ class MainActivity : BaseActivity() {
} }
private fun setupTabs(tab_array: List<Fragment>){ private fun setupTabs(tab_array: List<() -> Fragment>){
view_pager.adapter = object : FragmentStateAdapter(this) { view_pager.adapter = object : FragmentStateAdapter(this) {
override fun createFragment(position: Int): Fragment { override fun createFragment(position: Int): Fragment {
return tab_array[position] return tab_array[position]()
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {
@ -275,9 +279,6 @@ class MainActivity : BaseActivity() {
} }
} }
//Keep the tabs active to prevent reloads and stutters
view_pager.offscreenPageLimit = tab_array.size - 1
TabLayoutMediator(tabs, view_pager) { tab, position -> TabLayoutMediator(tabs, view_pager) { tab, position ->
tab.icon = ContextCompat.getDrawable(applicationContext, tab.icon = ContextCompat.getDrawable(applicationContext,
when(position){ when(position){

View File

@ -7,120 +7,122 @@ import com.h.pixeldroid.objects.*
import java.util.* import java.util.*
class Converters { class Converters {
private val gson = Gson()
@TypeConverter @TypeConverter
fun listToJson(list: List<String>): String = Gson().toJson(list) fun listToJson(list: List<String>): String = gson.toJson(list)
@TypeConverter @TypeConverter
fun jsonToList(json: String): List<String> = fun jsonToList(json: String): List<String> =
Gson().fromJson(json, Array<String>::class.java).toList() gson.fromJson(json, Array<String>::class.java).toList()
@TypeConverter @TypeConverter
fun dateToJson(date: Date): String = Gson().toJson(date) fun dateToJson(date: Date): String = gson.toJson(date)
@TypeConverter @TypeConverter
fun jsonToDate(json: String): Date = Gson().fromJson(json, Date::class.java) fun jsonToDate(json: String): Date = gson.fromJson(json, Date::class.java)
@TypeConverter @TypeConverter
fun accountToJson(account: Account): String = Gson().toJson(account) fun accountToJson(account: Account): String = gson.toJson(account)
@TypeConverter @TypeConverter
fun jsonToAccount(json: String): Account = Gson().fromJson(json, Account::class.java) fun jsonToAccount(json: String): Account = gson.fromJson(json, Account::class.java)
@TypeConverter @TypeConverter
fun statusToJson(status: Status?): String = Gson().toJson(status) fun statusToJson(status: Status?): String = gson.toJson(status)
@TypeConverter @TypeConverter
fun jsonToStatus(json: String): Status? = Gson().fromJson(json, Status::class.java) fun jsonToStatus(json: String): Status? = gson.fromJson(json, Status::class.java)
@TypeConverter @TypeConverter
fun notificationTypeToJson(type: Notification.NotificationType?): String = Gson().toJson(type) fun notificationTypeToJson(type: Notification.NotificationType?): String = gson.toJson(type)
@TypeConverter @TypeConverter
fun jsonToNotificationType(json: String): Notification.NotificationType? = Gson().fromJson( fun jsonToNotificationType(json: String): Notification.NotificationType? = gson.fromJson(
json, json,
Notification.NotificationType::class.java Notification.NotificationType::class.java
) )
@TypeConverter @TypeConverter
fun applicationToJson(type: Application?): String = Gson().toJson(type) fun applicationToJson(type: Application?): String = gson.toJson(type)
@TypeConverter @TypeConverter
fun jsonToApplication(json: String): Application? = Gson().fromJson( fun jsonToApplication(json: String): Application? = gson.fromJson(
json, json,
Application::class.java Application::class.java
) )
@TypeConverter @TypeConverter
fun cardToJson(type: Card?): String = Gson().toJson(type) fun cardToJson(type: Card?): String = gson.toJson(type)
@TypeConverter @TypeConverter
fun jsonToCard(json: String): Card? = Gson().fromJson(json, Card::class.java) fun jsonToCard(json: String): Card? = gson.fromJson(json, Card::class.java)
@TypeConverter @TypeConverter
fun attachmentToJson(type: Attachment?): String = Gson().toJson(type) fun attachmentToJson(type: Attachment?): String = gson.toJson(type)
@TypeConverter @TypeConverter
fun jsonToAttachment(json: String): Attachment? = Gson().fromJson(json, Attachment::class.java) fun jsonToAttachment(json: String): Attachment? = gson.fromJson(json, Attachment::class.java)
@TypeConverter @TypeConverter
fun attachmentListToJson(type: List<Attachment>?): String { fun attachmentListToJson(type: List<Attachment>?): String {
val listType = object : TypeToken<List<Attachment?>?>() {}.type val listType = object : TypeToken<List<Attachment?>?>() {}.type
return Gson().toJson(type, listType) return gson.toJson(type, listType)
} }
@TypeConverter @TypeConverter
fun jsonToAttachmentList(json: String): List<Attachment>? { fun jsonToAttachmentList(json: String): List<Attachment>? {
val listType = object : TypeToken<List<Attachment?>?>() {}.type val listType = object : TypeToken<List<Attachment?>?>() {}.type
return Gson().fromJson(json, listType) return gson.fromJson(json, listType)
} }
@TypeConverter @TypeConverter
fun mentionListToJson(type: List<Mention>?): String { fun mentionListToJson(type: List<Mention>?): String {
val listType = object : TypeToken<List<Mention?>?>() {}.type val listType = object : TypeToken<List<Mention?>?>() {}.type
return Gson().toJson(type, listType) return gson.toJson(type, listType)
} }
@TypeConverter @TypeConverter
fun jsonToMentionList(json: String): List<Mention>? { fun jsonToMentionList(json: String): List<Mention>? {
val listType = object : TypeToken<List<Mention?>?>() {}.type val listType = object : TypeToken<List<Mention?>?>() {}.type
return Gson().fromJson(json, listType) return gson.fromJson(json, listType)
} }
@TypeConverter @TypeConverter
fun emojiListToJson(type: List<Emoji>?): String { fun emojiListToJson(type: List<Emoji>?): String {
val listType = object : TypeToken<List<Emoji?>?>() {}.type val listType = object : TypeToken<List<Emoji?>?>() {}.type
return Gson().toJson(type, listType) return gson.toJson(type, listType)
} }
@TypeConverter @TypeConverter
fun jsonToEmojiList(json: String): List<Emoji>? { fun jsonToEmojiList(json: String): List<Emoji>? {
val listType = object : TypeToken<List<Emoji?>?>() {}.type val listType = object : TypeToken<List<Emoji?>?>() {}.type
return Gson().fromJson(json, listType) return gson.fromJson(json, listType)
} }
@TypeConverter @TypeConverter
fun tagListToJson(type: List<Tag>?): String { fun tagListToJson(type: List<Tag>?): String {
val listType = object : TypeToken<List<Tag?>?>() {}.type val listType = object : TypeToken<List<Tag?>?>() {}.type
return Gson().toJson(type, listType) return gson.toJson(type, listType)
} }
@TypeConverter @TypeConverter
fun jsonToTagList(json: String): List<Tag>? { fun jsonToTagList(json: String): List<Tag>? {
val listType = object : TypeToken<List<Tag?>?>() {}.type val listType = object : TypeToken<List<Tag?>?>() {}.type
return Gson().fromJson(json, listType) return gson.fromJson(json, listType)
} }
@TypeConverter @TypeConverter
fun pollToJson(type: Poll?): String = Gson().toJson(type) fun pollToJson(type: Poll?): String = gson.toJson(type)
@TypeConverter @TypeConverter
fun jsonToPoll(json: String): Poll? = Gson().fromJson(json, Poll::class.java) fun jsonToPoll(json: String): Poll? = gson.fromJson(json, Poll::class.java)
@TypeConverter @TypeConverter
fun visibilityToJson(type: Status.Visibility?): String = Gson().toJson(type) fun visibilityToJson(type: Status.Visibility?): String = gson.toJson(type)
@TypeConverter @TypeConverter
fun jsonToVisibility(json: String): Status.Visibility? = Gson().fromJson( fun jsonToVisibility(json: String): Status.Visibility? = gson.fromJson(
json, json,
Status.Visibility::class.java Status.Visibility::class.java
) )

View File

@ -188,41 +188,45 @@ class CameraFragment : Fragment() {
// CameraProvider // CameraProvider
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// Preview if (camera == null || preview == null || imageCapture == null || !cameraProvider.isBound(preview!!) || !cameraProvider.isBound(imageCapture!!)) {
preview = Preview.Builder()
// We request aspect ratio but no resolution
.setTargetAspectRatio(screenAspectRatio)
// Set initial target rotation
.setTargetRotation(rotation)
.build()
// ImageCapture
imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
// We request aspect ratio but no resolution to match preview config, but letting
// CameraX optimize for whatever specific resolution best fits our use cases
.setTargetAspectRatio(screenAspectRatio)
// Set initial target rotation, we will have to call this again if rotation changes
// during the lifecycle of this use case
.setTargetRotation(rotation)
.build()
// Must unbind the use-cases before rebinding them // Preview
cameraProvider.unbindAll() preview = Preview.Builder()
// We request aspect ratio but no resolution
.setTargetAspectRatio(screenAspectRatio)
// Set initial target rotation
.setTargetRotation(rotation)
.build()
try { // ImageCapture
// A variable number of use-cases can be passed here - imageCapture = ImageCapture.Builder()
// camera provides access to CameraControl & CameraInfo .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
camera = cameraProvider.bindToLifecycle( // We request aspect ratio but no resolution to match preview config, but letting
this, cameraSelector, preview, imageCapture // CameraX optimize for whatever specific resolution best fits our use cases
) .setTargetAspectRatio(screenAspectRatio)
// Set initial target rotation, we will have to call this again if rotation changes
// during the lifecycle of this use case
.setTargetRotation(rotation)
.build()
// Attach the viewfinder's surface provider to preview use case // Must unbind the use-cases before rebinding them
preview?.setSurfaceProvider(viewFinder.surfaceProvider) cameraProvider.unbindAll()
} catch (exc: Exception) {
Log.e(TAG, "Use case binding failed", exc) try {
// A variable number of use-cases can be passed here -
// camera provides access to CameraControl & CameraInfo
camera = cameraProvider.bindToLifecycle(
this, cameraSelector, preview, imageCapture
)
// Attach the viewfinder's surface provider to preview use case
preview?.setSurfaceProvider(viewFinder.surfaceProvider)
} catch (exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
} }
}, ContextCompat.getMainExecutor(requireContext())) }, ContextCompat.getMainExecutor(requireContext()))
} }
@ -290,7 +294,7 @@ class CameraFragment : Fragment() {
private fun setupUploadImage(controls: View) { private fun setupUploadImage(controls: View) {
// Listener for button used to view the most recent photo // Listener for button used to view the most recent photo
controls.findViewById<ImageButton>(R.id.photo_view_button).setOnClickListener { controls.findViewById<ImageButton>(R.id.photo_view_button)?.setOnClickListener {
Intent().apply { Intent().apply {
type = "image/*" type = "image/*"
action = Intent.ACTION_GET_CONTENT action = Intent.ACTION_GET_CONTENT
@ -306,7 +310,7 @@ class CameraFragment : Fragment() {
private fun setupFlipCameras(controls: View) { private fun setupFlipCameras(controls: View) {
// Listener for button used to switch cameras // Listener for button used to switch cameras
controls.findViewById<ImageButton>(R.id.camera_switch_button).setOnClickListener { controls.findViewById<ImageButton>(R.id.camera_switch_button)?.setOnClickListener {
lensFacing = if (CameraSelector.LENS_FACING_FRONT == lensFacing) { lensFacing = if (CameraSelector.LENS_FACING_FRONT == lensFacing) {
CameraSelector.LENS_FACING_BACK CameraSelector.LENS_FACING_BACK
} else { } else {
@ -327,7 +331,7 @@ class CameraFragment : Fragment() {
private fun setupImageCapture(controls: View) { private fun setupImageCapture(controls: View) {
// Listener for button used to capture photo // Listener for button used to capture photo
controls.findViewById<ImageButton>(R.id.camera_capture_button).setOnClickListener { controls.findViewById<ImageButton>(R.id.camera_capture_button)?.setOnClickListener {
// Get a stable reference of the modifiable image capture use case // Get a stable reference of the modifiable image capture use case
imageCapture?.let { imageCapture -> imageCapture?.let { imageCapture ->