Now i am writing my small molar mass calculator and i can't fix one bug. In MainActivity.kt i fill array from my .xml file, after that i use Regex to parse user input. BUT if i type, for example "C" (carbon) in my program it doesn't recognize it. WHY?
MainActivity.kt:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val adapter = MoleculeAdapter(this)
moleculeView.layoutManager = LinearLayoutManager(this)
moleculeView.setHasFixedSize(true)
moleculeView.adapter = adapter
val parser = resources.getXml(R.xml.elements)
val elements = Array(127) { Element() }
thread {
var i = 0
while (parser.eventType != END_DOCUMENT) {
if (parser.eventType == START_TAG && parser.name == "element") {
elements[i].number = parser.getAttributeIntValue(null, "number", 0)
elements[i].letter = parser.getAttributeValue(null, "letter")
elements[i].name = parser.getAttributeValue(null, "name")
val weight = parser.getAttributeValue(null, "weight")
elements[i].weight = if (weight.isNotEmpty()) weight.toFloat() else 0F
i++
}
parser.next()
}
parser.close()
}.join()
Log.i("elements:", elements.joinToString { it.toString() + "\n" })
val lowerCaseLetters = "abcdefghiklmnopqrstuy"
val elementsRegex = Regex("""[ABCDEFGHIKLMNOPRSTUVWXYZ]([$lowerCaseLetters]{2}|[$lowerCaseLetters]?)\d*""")
val digitsRegex = Regex("""\d+""")
formulaInput.doOnTextChanged { text, _, _, _ ->
lateinit var foundedElements: List<Element>
thread {
foundedElements = elementsRegex
.findAll(text ?: "")
.map {
elements.find { element ->
Log.i("value", it.value + " " + it.value)
if (it.value.filter { it.isLetter() } == element.letter) {
val number = digitsRegex.find(it.value)
if (number != null) {
try {
element.moleculeCount = number.value.toInt()
element.weight = element.weight * number.value.toInt()
} catch (e: NumberFormatException) { }
}
element.percentage = adapter.getTotalWeight(element.weight) * 100
true
} else false
}
}.filterNotNull().toList()
}.join()
adapter.insertElements(foundedElements)
}
}
}
Element.kt:
data class Element(var number: Int = -1,
var letter: String = "",
var name: String = "",
var weight: Float = 0F,
var percentage: Float = 100F,
var moleculeCount: Int = 1)
xml file item example:
<element
number="6"
letter="С"
name="Углерод"
weight="12.011" />
I can't believe it, in my xml file letter "С" was a cyrillic letter "C" (\u0421)! And because of this equals check "С" == "C" was failing.
Huge Thanks to Wiktor Stribiżew for his comment.
Related
I want update progress bar in parent activity where recycler view is located.when user clicked on each radio buttons add a number to progress bar I have done it but I don't know how can I pass data from recycler view adapter to parent activity.
enter image description here
class MbtiQuestionAdapter(val questionList: QuestionList) :
RecyclerView.Adapter<QuestionViewHolder>() {
var maps = arrayListOf<HashMap<String, String>>()
var i = 0
var e = 0
var n = 0
var t = 0
var j = 0
var p = 0
var f = 0
var s = 0
var typeQuestion = ""
var testnumbers = 0
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QuestionViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val cellForRow = layoutInflater.inflate(
AminAmix.com.socialpersonality.R.layout.question_row,
parent,
false
)
return QuestionViewHolder(cellForRow)
}
#SuppressLint("ResourceAsColor")
override fun onBindViewHolder(holder: QuestionViewHolder, position: Int) {
//val question = questions.get(position)
if (questionList.questions[position].tip != "") {
holder.view.txtTitletipsQuestionRow.visibility = View.VISIBLE
// holder.view.imgtips.visibility = View.VISIBLE
holder.view.txtTipsQuestion.visibility = View.VISIBLE
holder.view.txtTipsQuestion.text = questionList.questions[position].tip
} else {
holder.view.imageView15.visibility = View.INVISIBLE
holder.view.shapeBlue.visibility = View.VISIBLE
holder.view.shapeGreen.visibility = View.VISIBLE
holder.view.shapeCircle.visibility = View.VISIBLE
}
holder.view.txtAmountQuestion.text = questionList.questions.size.toString()
holder.view.txtCurrentQuestion.text = (position + 1).toString()
val question = questionList.questions.get(position).title
Log.i("Position", position.toString())
val answers = questionList.questions.get(position).answers
var valueOfRadio = ""
if (questionList.questions.get(position).type == "range") {
holder.view.cardAB.visibility = View.INVISIBLE
for (answer in answers) {
val value = answer.value
typeQuestion = answer.title
Log.i("Position2", value.toString())
if (answer.title == "Agree") {
holder.view.txtQuestionDisAgree.text = answer.title
} else {
holder.view.txtQuestionAgree.text = answer.title
}
}
holder.view.radioGroup.setOnCheckedChangeListener { group, checkedId ->
if (checkedId == AminAmix.com.socialpersonality.R.id.radioButton_middle) {
Log.i("Radio", "0")
valueOfRadio = "0"
}
if (checkedId == AminAmix.com.socialpersonality.R.id.radioButton_agree1) {
Log.i("Radio", "1")
valueOfRadio = "1"
}
if (checkedId == AminAmix.com.socialpersonality.R.id.radioButton_agree2) {
Log.i("Radio", "2")
valueOfRadio = "2"
}
if (checkedId == AminAmix.com.socialpersonality.R.id.radioButton_disagree1) {
Log.i("Radio", "-1")
valueOfRadio = "-1"
}
if (checkedId == AminAmix.com.socialpersonality.R.id.radioButton_disagree_2) {
Log.i("Radio", "-2")
valueOfRadio = "-2"
}
val checked = group.findViewById(checkedId) as RadioButton
val list: ArrayList<String> = ArrayList()
list.add(checked.getText().toString())
Log.i("Chekkk", list.toString())
Log.i(
"checkedId", position.toString()
)
var idIf = ""
var typeIf = ""
var testValue = 0
var map = HashMap<String, String>();
var radioInt = valueOfRadio.toInt()
var selectedAnswers = questionList.questions[position].answers
if (radioInt > 0) {
for (answer in selectedAnswers) {
if (answer.title == "Agree") {
typeIf = answer.type
testValue = answer.value
holder.view.txtQuestionDisAgree.setTextColor(Color.parseColor("#5E5E5E"));
holder.view.txtQuestionAgree.setTextColor(Color.parseColor("#B2B2B2"));
holder.view.txtCurrentQuestion.setTextColor(Color.parseColor("#0B6095"));
holder.view.txtAmountQuestion.setTextColor(Color.parseColor("#0B6095"));
holder.view.txtCurrentQuestion2.setTextColor(Color.parseColor("#0B6095"));
holder.view.txtTitleQuestions.setTextColor(Color.parseColor("#0B6095"));
holder.view.questionsTik.visibility = View.VISIBLE
}
}
} else if (radioInt < 0) {
for (answer in selectedAnswers) {
if (answer.title == "Disagree") {
typeIf = answer.type
testValue = answer.value
holder.view.txtQuestionAgree.setTextColor(Color.parseColor("#5E5E5E"));
holder.view.txtQuestionDisAgree.setTextColor(Color.parseColor("#B2B2B2"));
holder.view.txtCurrentQuestion.setTextColor(Color.parseColor("#0B6095"));
holder.view.txtAmountQuestion.setTextColor(Color.parseColor("#0B6095"));
holder.view.txtCurrentQuestion2.setTextColor(Color.parseColor("#0B6095"));
holder.view.txtTitleQuestions.setTextColor(Color.parseColor("#0B6095"));
holder.view.questionsTik.visibility = View.VISIBLE
}
}
} else {
holder.view.txtQuestionAgree.setTextColor(Color.parseColor("#B2B2B2"));
holder.view.txtQuestionDisAgree.setTextColor(Color.parseColor("#B2B2B2"));
holder.view.txtCurrentQuestion.setTextColor(Color.parseColor("#0B6095"));
holder.view.txtAmountQuestion.setTextColor(Color.parseColor("#0B6095"));
holder.view.txtCurrentQuestion2.setTextColor(Color.parseColor("#0B6095"));
holder.view.txtTitleQuestions.setTextColor(Color.parseColor("#0B6095"));
holder.view.questionsTik.visibility = View.VISIBLE
}
var absolutResultRadio = Math.abs(valueOfRadio.toInt())
// map["Q" + "_" + idIf.toString() + "_" + typeIf.toString()] = valueOfRadio
map["Q" + (position + 1).toString()] =
typeIf.toString() + "_" + absolutResultRadio * testValue
var con = maps.any { it.containsKey("Q" + (position + 1).toString()) }
if (maps.any { con == true }) {// filter
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
maps.removeIf { it.containsKey("Q" + (position + 1)) }
testnumbers = testnumbers - 1
}
testnumbers = testnumbers + 1
maps.add(map)
Log.i("maps", "in dare ejra mishe")
} else {
maps.add(map)
testnumbers = testnumbers + 1
}
}
Log.i ( "testnumber2" , testnumbers.toString())
} else {
holder.view.cardRange.visibility = View.INVISIBLE
holder.view.radioButtonFirstAAndB.text = answers[0].title
holder.view.radioButtonSecondAAndB.text = answers[1].title
holder.view.radioGroup2.setOnCheckedChangeListener { group, checkedId ->
if (checkedId == AminAmix.com.socialpersonality.R.id.radioButtonFirstAAndB) {
Log.i("Radio", "1")
valueOfRadio = "1"
}
if (checkedId == AminAmix.com.socialpersonality.R.id.radioButtonSecondAAndB) {
Log.i("Radio", "-1")
valueOfRadio = "-1"
}
val checked = group.findViewById(checkedId) as RadioButton
val list: ArrayList<String> = ArrayList()
list.add(checked.getText().toString())
Log.i("Chekkk", list.toString())
Log.i(
"checkedId", position.toString()
)
var idIf = ""
var typeIf = ""
var testValue = 0
var map = HashMap<String, String>();
var radioInt = valueOfRadio.toInt()
var selectedAnswers = questionList.questions[position].answers
if (radioInt > 0) {
typeIf = selectedAnswers[0].type
testValue = selectedAnswers[0].value
holder.view.txtCurrentQuestion.setTextColor(Color.parseColor("#0B6095"));
holder.view.txtAmountQuestion.setTextColor(Color.parseColor("#0B6095"));
holder.view.txtCurrentQuestion2.setTextColor(Color.parseColor("#0B6095"));
holder.view.txtTitleQuestions.setTextColor(Color.parseColor("#0B6095"));
holder.view.questionsTik.visibility = View.VISIBLE
} else if (radioInt < 0) {
typeIf = selectedAnswers[1].type
testValue = selectedAnswers[1].value
holder.view.txtCurrentQuestion.setTextColor(Color.parseColor("#0B6095"));
holder.view.txtAmountQuestion.setTextColor(Color.parseColor("#0B6095"));
holder.view.txtCurrentQuestion2.setTextColor(Color.parseColor("#0B6095"));
holder.view.txtTitleQuestions.setTextColor(Color.parseColor("#0B6095"));
holder.view.questionsTik.visibility = View.VISIBLE
}
var absolutResultRadio = Math.abs(valueOfRadio.toInt())
// map["Q" + "_" + idIf.toString() + "_" + typeIf.toString()] = valueOfRadio
map["Q" + (position + 1).toString()] =
typeIf.toString() + "_" + absolutResultRadio * testValue
var con = maps.any { it.containsKey("Q" + (position + 1).toString()) }
if (maps.any { con == true }) {// filter
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
maps.removeIf { it.containsKey("Q" + (position + 1)) }
}
maps.add(map)
Log.i("maps", "in dare ejra mishe")
} else {
maps.add(map)
}
}
}
Log.i("mapSize", maps.toString())
Log.i("mapSize", maps.size.toString())
if (maps.size.toInt() == questionList.questions.size
) {
Log.i("maps", "Halaaaaaaaaaaa in dare ejra mishe")
Log.i("Mapss", "SomeText: " + Gson().toJson(maps))
val dataOfTestToJson = Gson().toJson(maps).toString()
val eRegex = Regex("E_(\\d+)")
val iRegex = Regex("I_(\\d+)")
val sRegex = Regex("S_(\\d+)")
val nRegex = Regex("N_(\\d+)")
val fRegex = Regex("F_(\\d+)")
val tRegex = Regex("T_(\\d+)")
val pRegex = Regex("P_(\\d+)")
val jRegex = Regex("J_(\\d+)")
e = eRegex.findAll(dataOfTestToJson).map { it.groupValues[1].toInt() }.sum()
i = iRegex.findAll(dataOfTestToJson).map { it.groupValues[1].toInt() }.sum()
s = sRegex.findAll(dataOfTestToJson).map { it.groupValues[1].toInt() }.sum()
n = nRegex.findAll(dataOfTestToJson).map { it.groupValues[1].toInt() }.sum()
f = fRegex.findAll(dataOfTestToJson).map { it.groupValues[1].toInt() }.sum()
t = tRegex.findAll(dataOfTestToJson).map { it.groupValues[1].toInt() }.sum()
p = pRegex.findAll(dataOfTestToJson).map { it.groupValues[1].toInt() }.sum()
j = jRegex.findAll(dataOfTestToJson).map { it.groupValues[1].toInt() }.sum()
val data = JSONObject()
data.put("E", e)
data.put("I", i)
data.put("S", s)
data.put("N", n)
data.put("T", t)
data.put("F", f)
data.put("J", j)
data.put("P", p)
Log.i(
"dataSexy",
data.toString()
)
Log.i(
"mapsSexy",
"I = $i" + " " + "E = $e" + " " + "S= $s" + " " + "N = $n" + " " + "F = $f" + " " + "T = $t" + " " + "P = $p" + " " + "J = $j"
)
val context = holder.view.context
val intent = Intent(context, LoadingMbtiActivity::class.java)
intent.putExtra("e", e.toString())
intent.putExtra("i", i.toString())
intent.putExtra("s", s.toString())
intent.putExtra("n", n.toString())
intent.putExtra("f", f.toString())
intent.putExtra("t", t.toString())
intent.putExtra("p", p.toString())
intent.putExtra("j", j.toString())
intent.putExtra("data", data.toString())
context.startActivity(intent)
(context as Activity).finish()
}
holder.view.txtQuestionInRow.text = question
}
override fun getItemCount(): Int {
return questionList.questions.size
}
override fun getItemViewType(position: Int): Int {
return position
}
}
class QuestionViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
}
tps://i.stack.imgur.com/aQiS4.png
class MBTITEST : AppCompatActivity() {
lateinit var token: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_mbtitest)
window.statusBarColor = ContextCompat.getColor(this, R.color.black)
val preferences: SharedPreferences =
applicationContext.getSharedPreferences("SOCIAL_PERSONALITY", Context.MODE_PRIVATE)
token = preferences.getString("TOKEN", null).toString() //second parameter default value.
var tokenBAr = "Bearer $token"
getQuestions(tokenBAr)
}
fun getQuestions(token: String) {
val apilnterface: APIInterface = APIClient().getClient()!!.create(APIInterface::class.java)
var call: Call<QuestionList> = apilnterface.getQuestions(token)
call.enqueue(object : Callback<QuestionList> {
override fun onResponse(
call: Call<QuestionList>,
response: Response<QuestionList>
) {
if (response.code() == 200) {
// Toast.makeText(
// this#MBTITEST,
// "Testatol GolMohammadi",
// Toast.LENGTH_LONG
// )
// .show()
// Log.w("RESGetID", "${response.body().toString()}")
val dataFromResponse = response.body()
val questionList = dataFromResponse?.questions
val size = questionList?.size
val title = questionList?.get(0)?.title
print(questionList)
Log.w("QuestionListDaDa", questionList.toString())
Log.w("QuestionListDaDa", size.toString())
Log.w("QuestionListDaDa", title.toString())
runOnUiThread {
val layoutManager = LinearLayoutManager(
this#MBTITEST,
LinearLayoutManager.HORIZONTAL,
false
)
recycler_questions.layoutManager = layoutManager
recycler_questions.setHasFixedSize(true)
recycler_questions.adapter?.setHasStableIds(true)
Collections.shuffle(dataFromResponse?.questions)
recycler_questions.adapter =
dataFromResponse?.let { MbtiQuestionAdapter(it) }
txtCountTotal.text = questionList?.size.toString()
var mbtiAdapter = dataFromResponse?.let { MbtiQuestionAdapter(it) }
var testnumbers = mbtiAdapter?.testnumbers
textView15.setText(testnumbers.toString())
Log.i("testnumber", testnumbers.toString())
// btnShowRes.setOnClickListener {
// // dataFromResponse?.let { MbtiQuestionAdapter(it) }?.activateButtons(true)
// val intent = Intent(this#MBTITEST, ShowTestResultActivity::class.java)
// startActivity(intent)
// finish()
// }
}
}
if (response.code() == 400) {
try {
val jObjError = JSONObject(response.errorBody()!!.string())
Toast.makeText(
applicationContext,
jObjError.getString("message"),
Toast.LENGTH_LONG
).show()
} catch (e: Exception) {
Toast.makeText(applicationContext, e.message, Toast.LENGTH_LONG).show()
}
}
if (response.code() == 401) {
try {
val preferences: SharedPreferences =
applicationContext.getSharedPreferences(
"SOCIAL_PERSONALITY",
Context.MODE_PRIVATE
)
preferences.edit().putString("TOKEN", "").apply()
val jObjError = JSONObject(response.errorBody()!!.string())
Toast.makeText(
applicationContext,
jObjError.getString("message"),
Toast.LENGTH_LONG
).show()
} catch (e: Exception) {
Toast.makeText(applicationContext, e.message, Toast.LENGTH_LONG).show()
val intent = Intent(this#MBTITEST, FirstPageActivity::class.java)
startActivity(intent)
finish()
}
}
}
override fun onFailure(call: Call<QuestionList>, t: Throwable) {
Toast.makeText(
this#MBTITEST,
" Register is not ok",
Toast.LENGTH_LONG
)
.show()
}
})
}
}
like what #Arpit Shukla mentioned you can pass data between adapter and activity using lambdas or functions
add a function as a parameter to your adapter's constructor
class MbtiQuestionAdapter(val questionList: QuestionList,val onRadioButtonClick : (Int) -> Unit)
in your activity define a function to update your progress bar and it takes a number as a parameter or whatever you want
private fun updateProgressBar(testNumber : Int){
//update progress bar
}
pass the above function to adapter constructor when you initialize it
recycler_questions.adapter = dataFromResponse?.let { MbtiQuestionAdapter(it){number -> updateProgressBar(number)} }
lastly call the onRadioButtonClick in your adapter when you want to pass the number to your activity
onRadioButtonClick(number)
I'm trying to save this data class into database:
#Entity
#Parcelize
data class Rocket(
#SerializedName("active")
val active: Boolean = false,
#SerializedName("boosters")
val boosters: Int = 0,
#SerializedName("company")
val company: String = "",
#SerializedName("cost_per_launch")
val costPerLaunch: Int = 0,
#SerializedName("country")
val country: String = "",
#SerializedName("description")
val description: String = "",
#SerializedName("diameter")
val diameter: Diameter = Diameter(),
#SerializedName("engines")
val engines: Engines = Engines(),
#SerializedName("first_flight")
val firstFlight: String = "",
#SerializedName("first_stage")
val firstStage: FirstStage = FirstStage(),
#SerializedName("flickr_images")
val flickrImages: List<String> = listOf(),
#SerializedName("height")
val height: Height = Height(),
#PrimaryKey
#SerializedName("id")
val id: String = "",
#SerializedName("landing_legs")
val landingLegs: LandingLegs = LandingLegs(),
#SerializedName("mass")
val mass: Mass = Mass(),
#SerializedName("name")
val name: String = "",
#SerializedName("payload_weights")
val payloadWeights: List<PayloadWeight> = listOf(),
#SerializedName("second_stage")
val secondStage: SecondStage = SecondStage(),
#SerializedName("stages")
val stages: Int = 0,
#SerializedName("success_rate_pct")
val successRatePct: Int = 0,
#SerializedName("type")
val type: String = "",
#SerializedName("wikipedia")
val wikipedia: String = ""
): Parcelable
#Parcelize
data class Diameter(
#SerializedName("feet")
val feet: Double = 0.0,
#SerializedName("meters")
val meters: Double = 0.0
): Parcelable
#Parcelize
data class Engines(
#SerializedName("engine_loss_max")
val engineLossMax: Int = 0,
#SerializedName("isp")
val isp: Isp = Isp(),
#SerializedName("layout")
val layout: String = "",
#SerializedName("number")
val number: Int = 0,
#SerializedName("propellant_1")
val propellant1: String = "",
#SerializedName("propellant_2")
val propellant2: String = "",
#SerializedName("thrust_sea_level")
val thrustSeaLevel: ThrustSeaLevel = ThrustSeaLevel(),
#SerializedName("thrust_to_weight")
val thrustToWeight: Double = 0.0,
#SerializedName("thrust_vacuum")
val thrustVacuum: ThrustVacuum = ThrustVacuum(),
#SerializedName("type")
val type: String = "",
#SerializedName("version")
val version: String = ""
): Parcelable
#Parcelize
data class FirstStage(
#SerializedName("burn_time_sec")
val burnTimeSec: Int = 0,
#SerializedName("engines")
val engines: Int = 0,
#SerializedName("fuel_amount_tons")
val fuelAmountTons: Double = 0.0,
#SerializedName("reusable")
val reusable: Boolean = false,
#SerializedName("thrust_sea_level")
val thrustSeaLevel: ThrustSeaLevel = ThrustSeaLevel(),
#SerializedName("thrust_vacuum")
val thrustVacuum: ThrustVacuum = ThrustVacuum()
): Parcelable
#Parcelize
data class Height(
#SerializedName("feet")
val feet: Double = 0.0,
#SerializedName("meters")
val meters: Double = 0.0
): Parcelable {
fun toStringMetric(): String {
return "Height: $meters m"
}
fun toStringImperial(): String {
return "Height: $feet ft"
}
}
#Parcelize
data class LandingLegs(
#SerializedName("material")
val material: String = "",
#SerializedName("number")
val number: Int = 0
): Parcelable
#Parcelize
data class Mass(
#SerializedName("kg")
val kg: Int = 0,
#SerializedName("lb")
val lb: Int = 0
): Parcelable {
fun toStringMetric(): String {
return "Mass: $kg kg"
}
fun toStringImperial(): String {
return "Mass: $lb lbs"
}
}
#Parcelize
data class PayloadWeight(
#SerializedName("id")
val id: String = "",
#SerializedName("kg")
val kg: Int = 0,
#SerializedName("lb")
val lb: Int = 0,
#SerializedName("name")
val name: String = ""
): Parcelable
#Parcelize
data class SecondStage(
#SerializedName("burn_time_sec")
val burnTimeSec: Int = 0,
#SerializedName("engines")
val engines: Int = 0,
#SerializedName("fuel_amount_tons")
val fuelAmountTons: Double = 0.0,
#SerializedName("payloads")
val payloads: Payloads = Payloads(),
#SerializedName("reusable")
val reusable: Boolean = false,
#SerializedName("thrust")
val thrust: Thrust = Thrust()
): Parcelable
#Parcelize
data class Isp(
#SerializedName("sea_level")
val seaLevel: Int = 0,
#SerializedName("vacuum")
val vacuum: Int = 0
): Parcelable
#Parcelize
data class ThrustSeaLevel(
#SerializedName("kN")
val kN: Int = 0,
#SerializedName("lbf")
val lbf: Int = 0
): Parcelable
#Parcelize
data class ThrustVacuum(
#SerializedName("kN")
val kN: Int = 0,
#SerializedName("lbf")
val lbf: Int = 0
): Parcelable
#Parcelize
data class Payloads(
#SerializedName("composite_fairing")
val compositeFairing: CompositeFairing = CompositeFairing(),
#SerializedName("option_1")
val option1: String = ""
): Parcelable
#Parcelize
data class Thrust(
#SerializedName("kN")
val kN: Int = 0,
#SerializedName("lbf")
val lbf: Int = 0
): Parcelable
#Parcelize
data class CompositeFairing(
#SerializedName("diameter")
val diameter: Diameter = Diameter(),
#SerializedName("height")
val height: Height = Height()
): Parcelable
In order to do that, I have to write type converters that convert non-primitive types. My naive solution is to just convert everything into a string that's divided by `;`.
Here's what I wrote:
class RocketTypeConverter {
#TypeConverter
fun fromDiameterToString(diam: Diameter?): String? {
return diam?.let {
"${diam.feet};${diam.meters}"
}
}
#TypeConverter
fun fromStringToDiameter(str: String?): Diameter? {
str?.let {
str.split(";").also {
return Diameter(
feet = it[0].toDouble(),
meters = it[1].toDouble()
)
}
}
return null
}
#TypeConverter
fun fromEnginesToString(engines: Engines?): String? {
engines?.let {
engines.apply {
return "$engineLossMax" +
";" + fromIspToString(isp) +
";" + layout +
";" + "$number" +
";" + propellant1 +
";" + propellant2 +
";" + fromThrustSeaLevelToString(thrustSeaLevel) +
";" + "$thrustToWeight" +
";" + fromThrustVacuumToString(thrustVacuum) +
";" + type +
";" + version
}
}
return null
}
#TypeConverter
fun fromStringToEngines(str: String?): Engines? {
str?.let {
str.split(";").also {
val isp = fromStringToIsp(it[1])
val thrustSeaLevel = fromStringToThrustSeaLevel(it[6])
val thrustVacuum = fromStringToThrustVacuum(it[8])
return if(isp != null && thrustSeaLevel != null && thrustVacuum != null) {
Engines(
engineLossMax = it[0].toInt(),
isp = isp,
layout = it[2],
number = it[3].toInt(),
propellant1 = it[4],
propellant2 = it[5],
thrustSeaLevel = thrustSeaLevel,
thrustToWeight = it[7].toDouble(),
thrustVacuum = thrustVacuum,
type = it[9],
version = it[10]
)
} else {
null
}
}
}
return null
}
#TypeConverter
fun fromFirstStageToString(firstStage: FirstStage?): String? {
firstStage?.let {
firstStage.apply {
return "$burnTimeSec" +
";" + "$engines" +
";" + "$fuelAmountTons" +
";" + (if(reusable) "1" else "0") +
";" + fromThrustSeaLevelToString(thrustSeaLevel) +
";" + fromThrustVacuumToString(thrustVacuum)
}
}
return null
}
#TypeConverter
fun fromStringToFirstStage(str: String?): FirstStage? {
str?.let {
str.split(";").also {
val thrustSeaLevel = fromStringToThrustSeaLevel(it[4])
val thrustVacuum = fromStringToThrustVacuum(it[5])
return if(thrustSeaLevel != null && thrustVacuum != null) {
FirstStage(
burnTimeSec = it[0].toInt(),
engines = it[1].toInt(),
fuelAmountTons = it[2].toDouble(),
reusable = it[3] == "1",
thrustSeaLevel = thrustSeaLevel,
thrustVacuum = thrustVacuum
)
} else {
null
}
}
}
return null
}
#TypeConverter
fun fromHeightToString(height: Height?): String? {
height?.let {
return "${height.feet};${height.meters}"
}
return null
}
#TypeConverter
fun fromStringToHeight(str: String?): Height? {
str?.let {
str.split(";").also {
return Height(
feet = it[0].toDouble(),
meters = it[1].toDouble()
)
}
}
return null
}
#TypeConverter
fun fromLadingLegsToString(landingLegs: LandingLegs?): String? {
landingLegs?.let {
return "${landingLegs.material};${landingLegs.number}"
}
return null
}
#TypeConverter
fun fromStringToLandingLegs(str: String?): LandingLegs? {
str?.let {
str.split(";").also {
return LandingLegs(
material = it[0],
number = it[1].toInt()
)
}
}
return null
}
#TypeConverter
fun fromMassToString(mass: Mass?): String? {
mass?.let {
return "${mass.kg};${mass.lb}"
}
return null
}
#TypeConverter
fun fromStringToMass(str: String?): Mass? {
str?.let {
str.split(";").also {
return Mass(
kg = it[0].toInt(),
lb = it[1].toInt()
)
}
}
return null
}
#TypeConverter
fun fromPayLoadWeightToString(payloadWeight: PayloadWeight?): String? {
payloadWeight?.let {
return "${payloadWeight.id};${payloadWeight.kg};${payloadWeight.lb};${payloadWeight.name}"
}
return null
}
#TypeConverter
fun fromStringToPayloadWeight(str: String?): PayloadWeight? {
str?.let {
str.split(";").also {
return PayloadWeight(
id = it[0],
kg = it[1].toInt(),
lb = it[2].toInt(),
name = it[3]
)
}
}
return null
}
#TypeConverter
fun fromSecondStageToString(secondStage: SecondStage?): String? {
secondStage?.let {
secondStage.apply {
return "$burnTimeSec" +
";" + "$engines" +
";" + "$fuelAmountTons" +
";" + fromPayloadsToString(payloads) +
";" + (if(reusable) "1" else "0") +
";" + fromThrustToString(thrust)
}
}
return null
}
#TypeConverter
fun fromStringToSecondStage(str: String?): SecondStage? {
str?.let {
str.split(";").also {
val payloads = fromStringToPayloads(it[3])
val thrust = fromStringToThrust(it[5])
return if(payloads != null && thrust != null) {
return SecondStage(
burnTimeSec = it[0].toInt(),
engines = it[1].toInt(),
fuelAmountTons = it[2].toDouble(),
payloads = payloads,
reusable = it[4] == "1",
thrust = thrust
)
} else {
null
}
}
}
return null
}
#TypeConverter
fun fromThrustToString(thrust: Thrust?): String? {
thrust?.let {
return "${thrust.kN};${thrust.lbf}"
}
return null
}
#TypeConverter
fun fromStringToThrust(str: String?): Thrust? {
str?.let {
str.split(";").also {
return Thrust(
kN = it[0].toInt(),
lbf = it[1].toInt()
)
}
}
return null
}
#TypeConverter
fun fromPayloadsToString(payloads: Payloads?): String? {
payloads?.let {
return fromCompositeFairingToString(payloads.compositeFairing) + payloads.option1
}
return null
}
#TypeConverter
fun fromStringToPayloads(str: String?): Payloads? {
str?.let {
str.split(";").also {
fromStringToCompositeFairing(it[0])?.let { compositeFairing ->
return Payloads(
compositeFairing = compositeFairing,
option1 = it[1]
)
} ?: return null
}
}
return null
}
#TypeConverter
fun fromCompositeFairingToString(compositeFairing: CompositeFairing?): String? {
compositeFairing?.let {
return fromDiameterToString(compositeFairing.diameter) +
fromHeightToString(compositeFairing.height)
}
return null
}
#TypeConverter
fun fromStringToCompositeFairing(str: String?): CompositeFairing? {
str?.let {
str.split(";").also {
val diameter = fromStringToDiameter(it[0])
val height = fromStringToHeight(it[1])
return if(diameter != null && height != null) {
CompositeFairing(
diameter = diameter,
height = height
)
} else {
null
}
}
}
return null
}
#TypeConverter
fun fromIspToString(isp: Isp?): String? {
isp?.let {
return "${isp.seaLevel};${isp.vacuum}"
}
return null
}
#TypeConverter
fun fromStringToIsp(str: String?): Isp? {
str?.let {
str.split(";").also {
return Isp(
seaLevel = it[0].toInt(),
vacuum = it[1].toInt()
)
}
}
return null
}
#TypeConverter
fun fromThrustSeaLevelToString(thrustSeaLevel: ThrustSeaLevel?): String? {
thrustSeaLevel?.let {
return "${thrustSeaLevel.kN};${thrustSeaLevel.lbf}"
}
return null
}
#TypeConverter
fun fromStringToThrustSeaLevel(str: String?): ThrustSeaLevel? {
str?.let {
str.split(";").also {
return ThrustSeaLevel(
kN = str[0].toInt(),
lbf = str[1].toInt()
)
}
}
return null
}
#TypeConverter
fun fromThrustVacuumToString(thrustVacuum: ThrustVacuum?): String? {
thrustVacuum?.let {
return "${thrustVacuum.kN};${thrustVacuum.lbf}"
}
return null
}
#TypeConverter
fun fromStringToThrustVacuum(str: String?): ThrustVacuum? {
str?.let {
str.split(";").also {
return ThrustVacuum(
kN = str[0].toInt(),
lbf = str[1].toInt()
)
}
}
return null
}
#TypeConverter
fun fromFlickrImagesToString(flickrImages: List<String>?): String? {
flickrImages?.let {
var imagesString = ""
for(image in flickrImages) {
imagesString += "$image;"
}
return imagesString.substring(0, (imagesString.length - 1))
}
return null
}
#TypeConverter
fun fromStringToFlickrImages(str: String?): List<String>? {
str?.let {
return str.split(";")
}
return null
}
#TypeConverter
fun fromPayloadWeightsToString(payloadWeights: List<PayloadWeight>?): String? {
payloadWeights?.let {
var weightsString = ""
for(weight in payloadWeights) {
weightsString += fromPayLoadWeightToString(weight) + ";"
}
return weightsString.substring(0, (weightsString.length - 1))
}
return null
}
#TypeConverter
fun fromStringToPayloadWeights(str: String?): List<PayloadWeight>? {
str?.let {
val weights = mutableListOf<PayloadWeight>()
str.split(";").also {
for(payloadWeight in it) {
fromStringToPayloadWeight(payloadWeight)?.let { payloadWeight ->
weights.add(payloadWeight)
} ?: return null
}
}
return weights
}
return null
}
}
The way I have it is that I have two modules: launch and rocket. Each has their own repository and each repository builds the database:
private val dao: Database = Room.databaseBuilder(
context,
Database::class.java,
Database.NAME_DB
).build()
The problem I'm having is that I get this error: java.lang.IndexOutOfBoundsException: Index: 1, Size: 1.
Right now, the error happens because of fromStringToIsp(). That doesn't seem like an algorithmic error because Isp class only has two fields, so I couldn't have erred with indices. And if I brute-force the fromStringToIsp() to pass, some other function will also report out of bound error.
So where did I go wrong implementing my TypeConverters?
The string that you're passing to fromStringToIsp() does not contain a semicolon because in fromStringToEngines() you're doing the following:
str.split(";").also {
val isp = fromStringToIsp(it[1])
/* ... */
}
Then, in fromStringToIsp(), you do:
str.split(";").also {
return Isp(
seaLevel = it[0].toInt(),
vacuum = it[1].toInt()
)
}
When trying to access it[1] you'll get an exception, because it only has one element, i.e. it[0].
i'm using BulletSpan which is customized.
i want to display long text that has '\n'.
every lines are fine except for the text line which has '\n'.
bulleetspan can't apply the indent to the newline text.
this is the result.
and the last text is one text. and the text has '\n' inside.
and the code is..
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val source = listOf("Spans are powerful markup objects that you can use to style text at a character or paragraph level.",
"By attaching spans to text objects, you can change text in a variety of ways, ",
"including adding color, making the text clickable,\scaling the text size,\nand drawing text in a customized way.")
val sb = SpannableStringBuilder()
for (i in source.indices) {
val length = sb.length
sb.append(source[i])
sb.append("\n")
sb.setSpan(CustomBulletSpan(
bulletRadius = dip(8),
gapWidth = dip(14),
mColor = color(),
mWantColor = true
), length, length + 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
}
binding.tvResult.text = sb
}
private fun dip(dp: Int): Int {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dp.toFloat(),
resources.displayMetrics
).toInt()
}
private fun color(): Int {
return ContextCompat.getColor(applicationContext, R.color.gray);
}
}
and the customBullentSpan code is..
class CustomBulletSpan(
val bulletRadius: Int = STANDARD_BULLET_RADIUS,
val gapWidth: Int = STANDARD_GAP_WIDTH,
val mColor: Int = STANDARD_COLOR,
val mWantColor: Boolean = false
) : LeadingMarginSpan {
companion object {
// Bullet is slightly bigger to avoid aliasing artifacts on mdpi devices.
private const val STANDARD_BULLET_RADIUS = 4
private const val STANDARD_GAP_WIDTH = 2
private const val STANDARD_COLOR = 0
}
private var mBulletPath: Path? = null
override fun getLeadingMargin(first: Boolean): Int {
return 2 * bulletRadius + gapWidth
}
override fun drawLeadingMargin(
c: Canvas,
p: Paint,
x: Int,
dir: Int,
top: Int,
baseline: Int,
bottom: Int,
text: CharSequence,
start: Int,
end: Int,
first: Boolean,
layout: Layout?
) {
if ((text as Spanned).getSpanStart(this) == start) {
val style = p.style
p.style = Paint.Style.FILL
var oldColor = 0
if (mWantColor) {
oldColor = p.color
p.color = mColor
}
val yPosition = if (layout != null) {
val line = layout.getLineForOffset(start)
layout.getLineBaseline(line).toFloat() - bulletRadius * 1.3f
} else {
(top + bottom) / 1.3f
}
val xPosition = (x + dir * bulletRadius).toFloat()
if (c.isHardwareAccelerated) {
if (mBulletPath == null) {
mBulletPath = Path()
mBulletPath!!.addCircle(0.0f, 0.0f, bulletRadius.toFloat(), Path.Direction.CW)
}
c.save()
c.translate(xPosition, yPosition)
c.drawPath(mBulletPath!!, p)
c.restore()
} else {
c.drawCircle(xPosition, yPosition, bulletRadius.toFloat(), p)
}
if (mWantColor) {
p.color = oldColor
}
p.style = style
}
}
}
how can i solve this problem??
You could just get the string and split by \n and apply span
var len = 0
for (i in source.indices) {
if (source[i].contains("\n")) {
val splitted = source[i].split("\n")
for (k in splitted.indices) {
len = sb.length
sb.append(splitted[k])
sb.append("\n")
sb.setSpan(
CustomBulletSpan(
bulletRadius = dip(8),
gapWidth = dip(14),
mColor = color(),
mWantColor = true
), len, len + 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE
)
}
} else {
len = sb.length
sb.append(source[i])
sb.append("\n")
sb.setSpan(
CustomBulletSpan(
bulletRadius = dip(8),
gapWidth = dip(14),
mColor = color(),
mWantColor = true
), len, len + 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE
)
}
}
The other way is to split and add it to new list and iterate over the same and apply spans
val newList = mutableListOf<String>()
for (item in source) {
if(item.contains("\n")) {
val split = item.split("\n")
for (splitItem in split){
newList.add(splitItem)
}
} else{
newList.add(item)
}
}
I get a NumberFormatException if an entry field is left blank in the app. Previously, I had a working try/catch block that would handle it but I needed to add a switch on if/else statement to determine which function to run. I've tried everything I can think of to reformat the try/catch so that error is being handled, but everything just breaks the application. What am I doing wrong here, or is it even possible to do?
package com.WordPlay.awcc
import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
class Setup3 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main
)
editTextNumber2.text.toString().toInt()
editTextNumber3.text.toString().toInt()
editTextNumber4.text.toString().toInt()
editTextNumber5.text.toString().toInt()
editTextNumber6.text.toString().toInt()
editTextNumber15.text.toString().toInt()
}
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
/// Define button for checked
fun essentialexpert() {
val int11 = editTextNumber.text.toString().toInt()
val pay21 = 5
val product11 = int11 * pay21
val int12 = editTextNumber2.text.toString().toInt()
val pay22 = 12.5
val product12 = int12 * pay22
val int13 = editTextNumber3.text.toString().toInt()
val pay23 = 15
val product13 = int13 * pay23
val int16 = editTextNumber6.text.toString().toInt()
val pay24 = 5
val product14 = int16 * pay24
val int15 = editTextNumber5.text.toString().toInt()
val pay25 = 5
val product15 = int15 * pay25
val int14 = editTextNumber4.text.toString().toInt()
val pay26 = 2
val product16 = int14 / pay26
val final =
product11 + product12 + product13 + product14 + product15 + product16
val complete = final.toString()
try {
editTextNumber15?.setText(complete)
} catch (e: NumberFormatException) {
Toast.makeText(
applicationContext,
"Please enter a 0 in the blank field",
Toast.LENGTH_LONG
).show()
}
}
/// Define function for unchecked
fun essential() {
val int1 = editTextNumber.text.toString().toInt()
val pay1 = 5
val product1 = int1 * pay1
val int2 = editTextNumber2.text.toString().toInt()
val pay2 = 7.5
val product2 = int2 * pay2
val int3 = editTextNumber3.text.toString().toInt()
val pay3 = 10
val product3 = int3 * pay3
val int6 = editTextNumber6.text.toString().toInt()
val pay4 = 5
val product4 = int6 * pay4
val int5 = editTextNumber5.text.toString().toInt()
val pay5 = 0
val product5 = int5 * pay5
val int4 = editTextNumber4.text.toString().toInt()
val pay6 = 2
val product6 = int4 / pay6
val final = product1 + product2 + product3 + product4 + product5 + product6
val complete = final.toString()
try {
editTextNumber15?.setText(complete)
} catch (e: NumberFormatException) {
Toast.makeText(
applicationContext,
"Please enter a 0 in the blank field",
Toast.LENGTH_LONG
).show()
}
}
try {
essential()
} catch (e: java.lang.NumberFormatException) {
Toast.makeText(
applicationContext,
"Please enter a 0 in the blank fields",
Toast.LENGTH_LONG
).show()
/// Define buttons to change activity
val button2 = findViewById<Button>(R.id.button2)
button2.setOnClickListener {
val intent = Intent(this, SecondActivity::class.java)
startActivity(intent)
}
val button3 = findViewById<Button>(R.id.button3)
button3.setOnClickListener {
val intent2 = Intent(this, ThirdActivity::class.java)
startActivity(intent2)
}
val button = findViewById<Button>(R.id.button)
button.setOnClickListener {
if (switch1.isChecked) {
essentialexpert()
} else {
essential()
}
}
}
}
}
You shouldn't catch errors when writing to an EditText, but when reading. Something like that:
fun essentialexpert() {
val int11 = try {
editTextNumber.text.toString().toInt()
} catch (e: NumberFormatException) {
Toast.makeText(
applicationContext,
"Please enter a 0 in the blank field",
Toast.LENGTH_LONG ).show()
return
}
val pay21 = 5
val product11 = int11 * pay21
// ...
// If you reach here, all fields are ok
val final = product11 + /* ... */ + product16
val complete = final.toString()
editTextNumber15?.setText(complete)
}
With Kotlin, you can simplify this try/catch using the toIntOrNull method.
var areAllFieldsValid = false
fun essentialexpert() {
val int11 = editTextNumber.text.toString().toIntOrNull() ?: return
val pay21 = 5
val product11 = int11 * pay21
// ...
// If you reach here, all fields are ok
areAllFieldsValid = true
val final = product11 + /* ... */ + product16
val complete = final.toString()
editTextNumber15?.setText(complete)
}
override fun onCreate(savedInstanceState: Bundle?) {
// ...
btnFinish.setOnClickListener {
essentialexpert()
if (!areAllFieldsValid) {
Toast.makeText(
applicationContext,
"Please enter a 0 in the blank fields",
Toast.LENGTH_LONG).show()
} else {
// Do something when all fields are valid
}
}
}
Some tips for you:
Replace final.toString() with "$final"
Replace Toast.makeText(applicationContext, ... with Toast.makeText(this, .... An Activity is a Context.
I'm not sure what Setup3 is, but if it only exists for getting the EditText values, it won't work. You can do it in MainActivity.
The expression 5/2 may not return what you think it returns.
I need to download images from AWS S3 and update ImageViews inside a recycler view. I am using ViewModel for downloading files from S3. A file object is observing inside onBindViewHolder() method and once receive the file my intention was to update the image belongs with that particular holder.
But the problem is if there were two rows, then two images need to download. So each view holder will attach with the observer. After downloading the first file, both the image views inside the recycler view become updated with the first image and after downloading the second image, both images updated with the second image. I am a little bit confuse about working. Please help me with this.
I cannot use Glide for this. Because S3 have authentication. So, I need to use S3 library for downloading files.
override fun onBindViewHolder(holder: ListViewHolder, position: Int) {
val postUrl = listData[position].postUrl
val createdAt = listData[position].createdAt
val postImage = listData[position].postImage
val postVideo = listData[position].postVideo
val postVideoThumbnail = listData[position].postVideoThumbnail
val groupId = listData[position].groupId
val postStatus = listData[position].postStatus
val postId = listData[position].postId
val userId = listData[position].userId
val postHeading = listData[position].postHeading
val postDescription = listData[position].postDescription
val updatedAt = listData[position].updatedAt
val profileName = listData[position].userName
val profileImage = listData[position].profileImage
val likeCount = listData[position].likeCount
val commentCount = listData[position].commentCount
var key = ""
if(!profileImage.isNullOrEmpty()){
Glide.with(activity).load(profileImage) to holder.imgProfile
}
holder.textName.text = profileName.substring(0, 1).toUpperCase() + profileName.substring(1).toLowerCase()
holder.textPostedDateTime.text = SimpleDateFormat(POST_LIST_DATE_FORMAT).format(Date(createdAt))
holder.textPostHeading.text = postHeading
if(postDescription.isNullOrEmpty() || postDescription == "null"){
holder.textPostDescription.visibility = View.GONE
} else{
holder.textPostDescription.visibility = View.VISIBLE
holder.textPostDescription.text = postDescription
}
if(postUrl.isNullOrEmpty() || postUrl == "null"){
holder.textPostLink.visibility = View.GONE
} else{
holder.textPostLink.visibility = View.VISIBLE
holder.textPostLink.text = postUrl
}
if(postVideoThumbnail.isNullOrEmpty() || postVideoThumbnail == "null"){
holder.imgPostVideoPreview.visibility = View.GONE
} else{
holder.imgPostVideoPreview.visibility = View.VISIBLE
loadImageToFile(holder.imgPostVideoPreview, postVideoThumbnail, position)
key = postVideoThumbnail
}
if(postImage.isNullOrEmpty() || postImage == "null"){
holder.imgPostImagePreview.visibility = View.GONE
} else{
holder.imgPostImagePreview.visibility = View.VISIBLE
loadImageToFile(holder.imgPostImagePreview, postImage, position)
key = postImage
}
holder.textLikeCount.text = likeCount.toString()
holder.textCommentCount.text = commentCount.toString()
if(!isSelfPosts){
holder.layoutCommentLikeShare.visibility = View.VISIBLE
holder.imgAddComment.setOnClickListener { }
holder.imgAddLike.setOnClickListener { }
holder.imgShare.setOnClickListener { }
}
holder.itemView.setOnClickListener {
moveTOPostDetails(postId, listData[position], Environment.getExternalStorageDirectory().path + "/" + EXTERNAL_STORAGE_FOLDER_NAME + "/" + key.substring(key.lastIndexOf("/")+1))
}
}
class ListViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val imgProfile: ImageView = itemView.imgProfile
val textName: TextView = itemView.textName
val textPostedDateTime: TextView = itemView.textPostedDateTime
val textPostHeading: TextView = itemView.textPostHeading
val textPostDescription: TextView = itemView.textPostDescription
val textPostLink: TextView = itemView.textPostLink
val imgPostVideoPreview: ImageView = itemView.imgPostVideoPreview
val imgPostImagePreview: ImageView = itemView.imgPostImagePreview
val textCommentCount: TextView = itemView.textCommentCount
val textLikeCount: TextView = itemView.textLikeCount
val layoutCommentLikeShare: LinearLayout = itemView.layoutCommentLikeShare
val imgAddComment: ImageView = itemView.imgAddComment
val imgAddLike: ImageView = itemView.imgAddLike
val imgShare: ImageView = itemView.imgShare
}
private fun moveTOPostDetails(postId: String, fetchPostsResponseModel: FetchPostsResponseModel, imageFileName: String){
val intent = Intent(activity, PostDetails::class.java)
intent.putExtra("POST_DETAILS", fetchPostsResponseModel)
intent.putExtra("IS_SELF_POST", isSelfPosts)
intent.putExtra("IMAGE_FILE_NAME", imageFileName)
activity.startActivity(intent)
}
private fun loadImageToFile(imageView: ImageView, key: String, position: Int){
var postListAdapterViewModel: PostListAdapterViewModel = ViewModelProviders.of(fragment).get(PostListAdapterViewModel::class.java)
postListAdapterViewModel.init(activity)
postListAdapterViewModel.getMediaFile()?.observe(fragment, Observer<File>{ file ->
var a=position
imageView.setImageURI(Uri.fromFile(file))
} )
postListAdapterViewModel.performDownload(key)
}
This is my viewmodel
class PostListAdapterViewModel(application: Application):AndroidViewModel(application){
private val file = MutableLiveData<File>()
private lateinit var context: Context
fun init(context: Context) {
this.context = context
AWSMobileClient.getInstance().initialize(context).execute()
}
fun performDownload(key : String){
val credentials = BasicAWSCredentials(AMAZON_S3_ACCESS_KEY, AMAZON_S3_SECRET_KEY)
val s3Client = AmazonS3Client(credentials)
val transferUtility = TransferUtility.builder()
.context(context)
.awsConfiguration(AWSMobileClient.getInstance().configuration)
.s3Client(s3Client)
.build()
val downloadObserver = transferUtility.download (
key,
File(Environment.getExternalStorageDirectory().path + "/" + EXTERNAL_STORAGE_FOLDER_NAME + "/" + key.substring(key.lastIndexOf("/")+1)))
// Attach a listener to get state updates
downloadObserver.setTransferListener(object : TransferListener {
override fun onStateChanged(id: Int, state: TransferState) {
if (state == TransferState.COMPLETED) {
// Handle a completed upload.
file.value = File(Environment.getExternalStorageDirectory().path + "/" + EXTERNAL_STORAGE_FOLDER_NAME + "/" + key.substring(key.lastIndexOf("/")+1))
}
}
override fun onProgressChanged(id: Int, current: Long, total: Long) {
try {
val done = (((current.toDouble() / total) * 100.0).toInt()) //as Int
Log.d("PostListAdapterVM", "DOWNLOAD - - ID: $id, percent done = $done")
}
catch (e: Exception) {
Log.e("PostListAdapterVM", "Trouble calculating progress percent", e)
}
}
override fun onError(id: Int, ex: Exception) {
Log.d("PostListAdapterVM", "DOWNLOAD ERROR - - ID: $id - - EX: ${ex.message.toString()}")
}
})
// If you prefer to poll for the data, instead of attaching a
// listener, check for the state and progress in the observer.
if (downloadObserver.state == TransferState.COMPLETED) {
// Handle a completed upload.
}
Log.d("PostListAdapterVM", "Bytes Transferrred: ${downloadObserver.bytesTransferred}")
}
fun getMediaFile(): MutableLiveData<File> {
return file
}
}