The step counter code works, but it counts the steps inaccurately (for example I make 10 steps and it shows either 0 or more than 10). It also takes some time to show how many steps were made. The code is written in Android Studio, Java language. Can anyone help to optimize it or tell where is the problem?
Here is the Main activity code
`
package com.example.stepcounter14
import android.content.Context
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import android.widget.Toast
class MainActivity : AppCompatActivity(), SensorEventListener {
// Added SensorEventListener the MainActivity class
// Implement all the members in the class MainActivity
// after adding SensorEventListener
// we have assigned sensorManger to nullable
private var sensorManager: SensorManager? = null
// Creating a variable which will give the running status
// and initially given the boolean value as false
private var running = false
// Creating a variable which will counts total steps
// and it has been given the value of 0 float
private var totalSteps = 0f
// Creating a variable which counts previous total
// steps and it has also been given the value of 0 float
private var previousTotalSteps = 0f
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
loadData()
resetSteps()
// Adding a context of SENSOR_SERVICE aas Sensor Manager
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
}
override fun onResume() {
super.onResume()
running = true
// Returns the number of steps taken by the user since the last reboot while activated
// This sensor requires permission android.permission.ACTIVITY_RECOGNITION.
// So don't forget to add the following permission in AndroidManifest.xml present in manifest folder of the app.
val stepSensor = sensorManager?.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)
if (stepSensor == null) {
// This will give a toast message to the user if there is no sensor in the device
Toast.makeText(this, "No sensor detected on this device", Toast.LENGTH_SHORT).show()
} else {
// Rate suitable for the user interface
sensorManager?.registerListener(this, stepSensor, SensorManager.SENSOR_DELAY_UI)
}
}
override fun onSensorChanged(event: SensorEvent?) {
// Calling the TextView that we made in activity_main.xml
// by the id given to that TextView
var tv_stepsTaken = findViewById<TextView>(R.id.tv_stepsTaken)
if (running) {
totalSteps = event!!.values[0]
// Current steps are calculated by taking the difference of total steps
// and previous steps
val currentSteps = totalSteps.toInt() - previousTotalSteps.toInt()
// It will show the current steps to the user
tv_stepsTaken.text = ("$currentSteps")
}
}
fun resetSteps() {
var tv_stepsTaken = findViewById<TextView>(R.id.tv_stepsTaken)
tv_stepsTaken.setOnClickListener {
// This will give a toast message if the user want to reset the steps
Toast.makeText(this, "Long tap to reset steps", Toast.LENGTH_SHORT).show()
}
tv_stepsTaken.setOnLongClickListener {
previousTotalSteps = totalSteps
// When the user will click long tap on the screen,
// the steps will be reset to 0
tv_stepsTaken.text = 0.toString()
// This will save the data
saveData()
true
}
}
private fun saveData() {
// Shared Preferences will allow us to save
// and retrieve data in the form of key,value pair.
// In this function we will save data
val sharedPreferences = getSharedPreferences("myPrefs", Context.MODE_PRIVATE)
val editor = sharedPreferences.edit()
editor.putFloat("key1", previousTotalSteps)
editor.apply()
}
private fun loadData() {
// In this function we will retrieve data
val sharedPreferences = getSharedPreferences("myPrefs", Context.MODE_PRIVATE)
val savedNumber = sharedPreferences.getFloat("key1", 0f)
// Log.d is used for debugging purposes
Log.d("MainActivity", "$savedNumber")
previousTotalSteps = savedNumber
}
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
// We do not have to write anything in this function for this app
}
}
`
Related
I would like to build an activity, which displays a set of strings in a loop until the user clicks on the screen.
Any suggestions is greatly appreciated.
I am trying to do this in Kotlin, but Java advice is also welcomed.
I have built an activity with TextSwitcher and a variable (isClicked) that indicates whether the user has clicked on the screen. I set up a listener that sets the isClicked when user clicks. Then in a loop I check the value of isClicked and if it is not checked I change the value of the text.
class SelectionActivity : AppCompatActivity() {
var isClicked = true
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.selection)
val textSwitcher = findViewById<TextSwitcher>(R.id.selectionText)
textSwitcher.setFactory {
val textView = TextView(this)
textView.gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
textView.textSize = 32f
textView
}
textSwitcher.setCurrentText("Start")
textSwitcher.setOnClickListener {
isClicked = false;
}
var i = 0;
while (isClicked) {
textSwitcher.setText(i.toString())
i++;
}
}
}
This does not seem to work. The app just hangs and becomes non-responsive. If I understand correctly, it might have something to do with activity class being in the UI thread and while loop being too heavy for it. However, I am not sure how this should be solved.
Android: I have made a simple Todo list app using Kotlin. And the theme (Light/Dark) of this app is set to system default theme MODE_NIGHT_FOLLOW_SYSTEM. Now the problem is that when I changed theme to Dark mode(because my emulator's theme was set to Light theme previously), all added Todo items were gone and same when I changed to Light mode again. Then I noticed the size of my ArrayList became 0 (empty).
Here is screenshots to understand it better:
Light Mode
https://i.stack.imgur.com/eWbzO.png
after changing system theme to Dark
Dark Mode
https://i.stack.imgur.com/B9iqg.png
tasks are added to list: ArrayList when saveButton: Textview is clicked
class MainActivity : AppCompatActivity() {
var modified = false
private lateinit var listView: ListView
private lateinit var input: EditText
private lateinit var saveButton: TextView
private lateinit var cancelButton: TextView
private val list = ArrayList<String>()
private lateinit var listAdapter: CustomAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
listView = findViewById(R.id.listView)
input = findViewById(R.id.input)
saveButton = findViewById(R.id.saveBtn)
cancelButton = findViewById(R.id.cancelBtn)
listAdapter = CustomAdapter(this, list)
listView.adapter = listAdapter
val warningToast = Toast.makeText(this,
"The text may be empty or contains only spaces",
Toast.LENGTH_LONG)
saveButton.setOnClickListener {
val text = input.text.toString()
// if text is empty or only contains blank
if (text.isEmpty() || text.isBlank()) {
warningToast.show()
return#setOnClickListener
}
if (!modified) {
// output list size 0 after changing theme
Log.d("MY_DEBUG", "size fo list is : ${list.size}")
list.add(input.text.toString())
} else {
// ...
}
input.text.clear()
listAdapter.notifyDataSetChanged()
}
// ...
}
}
I thought that this is because it triggers a uiMode configuration change when theme mode is changed. So, the activity is recreated automatically. I want to keep added items even after changing theme. Is there any way to prevent loss of added items. Thank you!
Changing theme recreates your activity and it reinitiates your list. It is not because of changing theme itself.
You have to save your data persistently, in a database or in a SharedPreferences instance with your own serialization method (like JSON).
i am translating an app in Kotlin and the user have the choice to choose between two different languages i created new Activity:
#Suppress("DEPRECATION")
class Languages_Activity : AppCompatActivity() {
lateinit var spinner: Spinner
lateinit var locale: Locale
var back_btn: LinearLayout? = null
private var currentLanguage = "en"
private var currentLang: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_languages_)
title = "KotlinApp"
currentLanguage = intent.getStringExtra(currentLang).toString()
spinner = findViewById(R.id.spinner)
val list = ArrayList<String>()
list.add("Select Language")
list.add("English")
list.add("Malay")
val adapter = ArrayAdapter(this, R.layout.support_simple_spinner_dropdown_item, list)
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinner.adapter = adapter
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
when (position) {
0 -> {
}
1 -> setLocale("en")
2 -> setLocale("my")
}
}
override fun onNothingSelected(parent: AdapterView<*>) {}
}
back_btn = findViewById(R.id.back_btn_language)
back_btn?.setOnClickListener {
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
}
}
private fun setLocale(localeName: String) {
if (localeName != currentLanguage) {
locale = Locale(localeName)
val res = resources
val dm = res.displayMetrics
val conf = res.configuration
conf.locale = locale
res.updateConfiguration(conf, dm)
val refresh = Intent(
this,
Languages_Activity::class.java
)
refresh.putExtra(currentLang, localeName)
startActivity(refresh)
} else {
Toast.makeText(
this#Languages_Activity, "Language, , already, , selected)!", Toast.LENGTH_SHORT).show();
}
}
override fun onBackPressed() {
val intent = Intent(Intent.ACTION_MAIN)
intent.addCategory(Intent.CATEGORY_HOME)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
startActivity(intent)
finish()
exitProcess(0)
}
}
and when i choose a language the app will display the values of the chosen language but when i close the app and run it again it the choice will reset
how can i keep the item selected even after closing the app and run it again?
you can use shared preferences
for this usecase.
shared preferences are helpful when you want to store key-value pairs that can persist data across app close and open.
this data will get deleted only when you clear your app data in settings or uninstall the app
in your onCreate you can add this snippet
val sharedPref = activity?.getPreferences(Context.MODE_PRIVATE)
val selectedLanguageIndex = sharedPref?.getInt("LANGUAGE_SELECTED", 0)?:0
spinner.setSelection(selectedLanguageIndex)
in your onItemSelected
val sharedPref = requireActivity().getPreferences(Context.MODE_PRIVATE)
with (sharedPref.edit()) {
putInt("LANGUAGE_SELECTED", position)
apply()
}
kotlin has sharedpreference system.
it can help when u have to remember some options until change.
I have some private Int variables initialized in kotlin.
class multiply : AppCompatActivity() {
.
.
private var score:Int=0;
private var score2=0;
.
.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState);
if(savedInstanceState==null) {
score=score2;
}
.
.
}
.
.
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
score=savedInstanceState.getInt("val_score");
}
My question is while I rotate my phone, a new is activity is created and in the present code score is getting assigned to 0. Is there any way for initializing only once? What is the way out?
I have some calculations inside onCreate using score. Since onRestoreInstanceState is executed after onCreate is there any way to keep the value of score unaffected on screen rotation other than defining it in onStart?
Your code should look like this:
class MultiplyActivity : AppCompatActivity() {
private var score = 0;
private var score2 = 0;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if(savedInstanceState != null) {
score = savedInstanceState.getInt("score", 0)
score2 = savedInstanceState.getInt("score2", 0)
}
}
override fun onSaveInstanceState(bundle: Bundle) {
super.onSaveInstanceState(bundle)
bundle.putInt("score", score)
bundle.putInt("score2", score2)
}
I have an activity that shows two fragments at the same time on tablet and one at a time on handset. Because I am making the app for both tablets and android, I have to separate the functionality of the navigation between fragments into a separate function "displaySecondFragmentOnHandset()".
On the smaller handset when a move from the first fragment to the second and the then try to go back to the first, the screen is blank.
MyActivity:
class CentralActivity : AppCompatActivity() {
val manager = supportFragmentManager
var firstFrag : FirstFrag? = null
override fun onCreate(savedInstanceState: Bundle?) {
...
var ft: FragmentTransaction = manager.beginTransaction();
firstFrag = FirstFrag.newInstance()
ft.add(R.id.real_container, firstFrag!!, "firstFrag")
if (screenLayoutSize >= Configuration.SCREENLAYOUT_SIZE_LARGE) {
var secondFrag = SecondFrag.newInstance()
ft.add(R.id.real_container, secondFrag, "secondFrag")
}
ft.commit()
}
fun displaySecondFragmentOnHandset (){
var secondFrag = SecondFrag.newInstance()
var ft: FragmentTransaction = manager.beginTransaction();
ft!!.replace(R.id.real_container, secondFrag).addToBackStack("secondFrag").commit()
}
Then in my FirstFragemnt, if i'm on a smaller handset I do:
class FirstFragemnt : Fragment() {
private var viewModel: SharedViewModel? = null
fun goToSecondFragment(){
if (screenLayoutSize!! < Configuration.SCREENLAYOUT_SIZE_LARGE) {
viewModel!!.setMsgInCommunicator(collection)
var centralActivity: CentralActivity = activity as CentralActivity
centralActivity.displaySecondFragmentOnHandset()
}
}
The problem is when I press the back button to go to the first fragment, The screen is blank.
in CentralActivity replace
ft!!.replace(R.id.real_container, secondFrag).addToBackStack("secondFrag").commit()
with
ft!!.add(R.id.real_container, secondFrag).addToBackStack("secondFrag").commit()
The solution was to put the fun goToSecondFragment() inside of override fun onViewCreated