Geocoding inside of a coroutine which is inside of an observer isn't running - android-studio

In my fragment i have a bindUI() method which contains some liveData that i am observing and inside of the lambda i want to use the value location (which contains a latitude and longitude value) to retrieve a list of Addresses based on the coordinates it contains. I was told that Geocoding should be done inside of a coroutine so i'm trying to do that but the code inside the launch coroutine doesn't seem to be running. I've placed log statements but they don't run and no result seems to be printed on my textView. The debugger also says that there is no runnable code when i place a breakpoint on it. What am i messing up here?
private fun bindUI() = launch(Dispatchers.Main) {
// fetch the location
val weatherLocation = viewModel.weatherLocation.await()
// Observe the location for changes
weatherLocation.observe(viewLifecycleOwner, Observer { location ->
if (location == null) return#Observer
//TODO:sp update the location text view
launch(Dispatchers.Main) {
val task = updateLocation(location)
locationTxtView.text = task[0].countryName
}
})
}
And here's the updateLocation() fun:
private suspend fun updateLocation(location: WeatherLocation): MutableList<Address> {
return async(Dispatchers.IO) {
val geocoder = Geocoder(activity, Locale.getDefault())
val addr = geocoder.getFromLocation(location.latitude, location.longitude, 10)
return#async addr
}.await()
}

Related

Get value from RoomDB into Composable function from Jetpack Compose

I have looked for many solutions but I found it as a newbie very
complex on how to solve it properly without throwing away all my backend
code.
I want to get an Float value from my RoomDB into a composable
UI value but as far as we all know getting RoomDB values with queries
needs an asynchronus scope. And those aren't capable of returning values
because values stay within a scope and die there too. There is I think
no way to no use Coroutine Scopes or anything else that doesn't block the UI loading
so it can actually work.
What can I do? I don't want to throw away the entire RoomDB database
neither our Jetpack Compose base GUI?
I tried replacing the 0.8f with a method that calls a Coroutine Scope which
should idealistically return a Float value to this part of our code.
#Composable
fun ChargeScreen(){
val context = LocalContext.current
Box(
contentAlignment = Alignment.Center,
modifier = Modifier.fillMaxSize()
){
Column {
ChargeTopText()
CircularChargeBar(percentage = 0.8f, number =100 )
}
}
}
I am also new at Android Jetpack Compose but I can give you a suggestion for your case.
Take a look at the code below
#Composable
fun YourComposable() {
//Use remember for state management
//Read more at https://developer.android.com/jetpack/compose/state
var floatData by remember { mutableStateOf(0F) }
var isLoading by remember { mutableStateOf(true) }
//Side-effects
//Read more at https://developer.android.com/jetpack/compose/side-effects
LaunchedEffect(Unit) {
isLoading = true
floatData = getFloatDataFromDB()
isLoading = false
}
//Just a way to show a progress indicator while we are getting the value from DB.
if(!isLoading) {
Text(text = "FloatData: $floatData")
} else {
CircularProgressIndicator(
modifier = Modifier.size(50.dp),
color = Color.Green,
strokeWidth = 5.dp)
}
}
suspend fun getFloatDataFromDB(): Float {
//Using withContext(Dispatchers.IO) so it will execute in IO Thread.
return withContext(Dispatchers.IO) {
//Pretend this will take 5 seconds to complete
Thread.sleep(5000)
//And return the value
return#withContext 0.9F
}
}
I hope this will help you out!

UI thread slow to respond to Progress updaters on async Task method using VS2022 & Net6.0

I’ve run into a performance obstacle and I’m uncertain of the cause, all of this is running under VS2022 & Net6.0. As this is my 1st time using this combination of a modal windows form, and progress bar, with the work running on a background thread and two Progress objects updating the UI, the progress bar, and a text label, I don’t know where to attack the problem. Prior to placing the workload on a background thread, everything was snappy, searching a thousand files with about 600 lines of text in each, in about a minute. Naturally, the windows form was frozen during this, which is why the workload was placed on a background thread.
After doing so, the workload will be 25-50% complete before the UI starts displaying the values from the Progress objects, and overall, the entire process now takes 10x as long to complete. Progress objects aren’t skipping over any values sent to them, the UI thread just seems slow in getting the information. Likewise, if I try to drag the modal form to a new spot on the desktop it’s unresponsive for 20—30 seconds before it finally moves. One more thing, I can step through the code on the background thread and see it calling the Progress updaters, but the UI thread is just very slow in responding to them.
I could use some suggestions on how to uncover the problem or if clearly evident, point out where the likely problem could be. Here are the essential controls and methods used.
public class SearchProgressForm : Form
{
private System.Windows.Forms.Button btnSearch = new Button();
private System.Windows.Forms.TextBox txtTextSearch = new TextBox();
private System.Windows.Forms.Label lblSearchFile = new Label();
private System.Windows.Forms.ProgressBar SearchProgressBar = new ProgressBar();
public event LogSearchEventHandler SearchSucceededEvent;
protected void OnSearchSucceeded(LogSearchEventArguments p_eventArguments)
{
LogSearchEventHandler handler = SearchSucceededEvent;
if (handler != null)
{
handler(this, p_eventArguments);
}
}
private void InitializeComponent()
{
this.btnSearch.Name = "btnSearch";
this.btnSearch.Text = "Search";
this.btnSearch.Click += new System.EventHandler(this.btnSearch_Click);
this.lblSearchFile.Text = "Searching File: ";
this.txtTextSearch.Text = "search string";
}
public SearchProgressForm() { }
private void btnSearch_Click(object sender, EventArgs e)
{
this.SearchByText(this.txtTextSearch.Text);
}
private void SearchByText(string p_searchParameter)
{
// Setup a progress report for thr ProgressBar
var _progressBarUpdate = new Progress<int>(value =>
{
this.SearchProgressBar.Value = value;
this.SearchProgressBar.Refresh();
});
var _progressFileNameUpdate = new Progress<string>(value =>
{
this.lblSearchFile.Text = "Searching File For : " + value;
this.lblSearchFile.Refresh();
});
// Start search on a backgroud thread and report progress as it occurs
Task.Run(async () => await this.SearchByStringAsync(p_searchParameter, _progressBarUpdate, _progressFileNameUpdate));
}
private async Task SearchByStringAsync(string p_searchParameter, IProgress<int> p_progressBar, IProgress<string> p_progressFileName)
{
await Task.Delay(1);
TextFileReader textFileReader = new TextFileReader();
LogSearchEventArguments logSearchEventArguments = null;
long _sessionloopCount = 0;
long _totalTextLinesCount = this.GetTotalSearchCount(p_searchParameter, SearchType.TextString);
// Get file names from SQL table
var _logFiles = DataOperations.LogFileSortableList(null);
foreach (var log in _logFiles)
{
// Format a file name to be read from the file system
string _fileName = log.Directory + "\\" + log.FileName;
p_progressFileName.Report(log.FileName);
// If we've raised an event for this file, then stop iterating over remaning text
if (logSearchEventArguments != null)
{
logSearchEventArguments = null;
break;
}
// Read in file contents from file system
List<string> _fileContents = textFileReader.ReadAndReturnStringList(_fileName);
long _fileTotalRecordCount = _fileContents.Count;
long _fileRecordCount = 0;
foreach (var _line in _fileContents)
{
if (_line.ToUpper().Contains(p_searchParameter.ToUpper()))
{
// Raise an event so search parameter and file name can be captured in another form
logSearchEventArguments =
new LogSearchEventArguments
(
"TextSearch", p_searchParameter, SearchType.TextString, true, log,
new DateTime(
Convert.ToInt32("20" + log.FileName.Substring(14, 2)),
Convert.ToInt32(log.FileName.Substring(16, 2)),
Convert.ToInt32(log.FileName.Substring(18, 2)))
);
// We found a match, so no further searching is needed in this log file,
// and it's been flagged in the DB, so raise the event to save search parameter and file name
// then break out of this loop to get the next file to search in.
this.OnSearchSucceeded(logSearchEventArguments);
break;
}
// These calcs are based on actual searches performed
_fileRecordCount++;
_sessionloopCount++;
p_progressBar.Report(Convert.ToInt32((_sessionloopCount * 100) / _totalTextLinesCount));
}
// Because we exit a search as soon as the 1st match is made, need to resynch all counts
// and update the progress bar accordingly
if (_fileRecordCount < _fileTotalRecordCount)
{
long _countDifference = _fileTotalRecordCount - _fileRecordCount;
// Add count difference to sessionLoopCount and update progress bar
_sessionloopCount += _countDifference;
p_progressBar.Report(Convert.ToInt32((_sessionloopCount * 100) / _totalTextLinesCount));
}
}
//Search is complete set Progress to 100% and report before exiting
p_progressBar.Report(100);
// Close the modal SearchForm and exit
this.Close();
}
}
I solved this problem but I'm still not certain of what caused it. I eliminated the method "private void SearchByText(string p_searchParameter)" and moved the code there into the btnSearch_Click event handler so I could call my background worker "SearchByStringAsync" directly from the button click event handler.
I also updated the EFCore NuGet Packages, which were version Net6.0 to version 6.0.4, because of single line of code in my Async background method, "var _logFiles = DataOperations.LogFileSortableList(null)".
That call returned a Sortable BindingList, using BindingList <T>. Between the NuGet updates and a minor change on a custom comparer method in my BindingList <T> class, the windows modal form now updates the ProgressBar and Label text as expected, and the form now responds immediately to user interaction.

Stop Thread in Kotlin

First of all, I'm new in Kotlin, so please be nice :).
It's also my first time posting on StackOverflow
I want to literally STOP the current thread that I created but nothing works.
I tried quit(), quitSafely(), interrupt() but nothing works.
I created a class (Data.kt), in which I create and initialize a Handler and HandlerThread as follows :
class Dispatch(private val label: String = "main") {
var handler: Handler? = null
var handlerThread: HandlerThread? = null
init {
if (label == "main") {
handlerThread = null
handler = Handler(Looper.getMainLooper())
} else {
handlerThread = HandlerThread(label)
handlerThread!!.start()
handler = Handler(handlerThread!!.looper)
}
}
fun async(runnable: Runnable) = handler!!.post(runnable)
fun async(block: () -> (Unit)) = handler!!.post(block)
fun asyncAfter(milliseconds: Long, function: () -> (Unit)) {
handler!!.postDelayed(function, milliseconds)
}
fun asyncAfter(milliseconds: Long, runnable: Runnable) {
handler!!.postDelayed(runnable, milliseconds)
}
companion object {
val main = Dispatch()
private val global = Dispatch("global")
//fun global() = global
}
}
And now, in my DataManager, I use these to do asynchronous things :
fun getSomething(forceNetwork: Boolean ) {
val queue1 = Dispatch("thread1") // Create a thread called "thread1"
queue1.async {
for (i in 0..2_000_000) {
print("Hello World")
// Do everything i want in the current thread
}
// And on the main thread I call my callback
Dispatch.main.async {
//callback?.invoke(.........)
}
}
}
Now, in my MainActivity, I made 2 buttons :
One for running the function getSomething()
The other one is used for switching to another Controller View :
val button = findViewById<Button>(R.id.button)
button.setOnClickListener {
DataManager.getSomething(true)
}
val button2 = findViewById<Button>(R.id.button2)
button2.setOnClickListener {
val intent = Intent(this, Test::class.java) // Switch to my Test Controller
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
startActivity(intent)
finish()
}
Is there a way to stop the thread, because when I switch to my second View, print("Hello World") is still triggered, unfortunately.
Thanks for helping me guys I hope that you understand !
A thread needs to periodically check a (global) flag and when it becomes true then the thread will break out from the loop. Java threads cannot be safely stopped without its consent.
Refer to page 252 here http://www.rjspm.com/PDF/JavaTheCompleteReference.pdf that describes the true story behind the legend.
I think that a truly interruptible thread is only possible through the support of the operating system kernel. The actual true lock is held deep down by the CPU hardware microprocessor.

Getting information from background thread onto the main thread for Swift

I seem to be having some trouble getting information from my global queue into my main queue.
override func viewDidLoad() {
super.viewDidLoad()
dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INTERACTIVE.value), 0)) {
let query = PFQuery(className: "VenueData")
query.whereKey("name", equalTo: "Sedona")
var object = query.findObjects()
if let myObject = object as? [PFObject] {
for x in myObject {
var hotelLabel: String? = x.objectForKey("name") as? String
println(hotelLabel)
dispatch_async(dispatch_get_main_queue()) {
self.new = hotelLabel!
self.hotelarray.append(self.new)
}
}
}
}
}
Even though I am able to change the UI through the dispatch_get_main_queue, I seem to be having trouble updating other stuff (e.g. Array) and if I were to println(hotelarray) outside of the block, only an empty array would show up.
I understand this happens because the mainthread loads significantly faster than the time it takes for the background thread to load its data. What is puzzles me is that it seems as if the hotel array will not get updated regardless of what happens inside the dispatch_get_main_queue whereas UI related stuff such as UILabels updates accordingly. Any help is greatly appreciated.

How can I get a value from a the ScalaFX thread?

I have a myNode: scalafx.scene.Node that I'd like to turn into a bitmap so that I can save it to disk, compare it to other bitmaps, etc. I think the correct code to turn it into a scalafx.scene.image.WritableImage is
val writableImg = new Scene { root = new Group(myNode) }.snapshot(null)
and then I should be able to turn that into a java.awt.image.RenderedImage with
val renderedImg = SwingFXUtils.fromFXImage(writableImg, null)
The problem, as you've probably realized, is that I have to run the code to get wrImg on the ScalaFX thread. There's a question here that explains how to return a value, but I'm not having any luck translating that to Scala. I tried this:
lazy val writableImg: WritableImage = {
val wrImg = new FutureTask(new Callable[WritableImage]() {
override def call(): WritableImage = {
new Scene { root = new Group(myNode) }.snapshot(null)
}
})
Platform.runLater(wrImg)
wrImg.get()
}
but the code just hangs and never completes. Can anyone provide an idiomatic Scala version and/or tell me why the code never returns?
If you just want to save the image to disk you can simply do it on the same thread avoiding complication passing the image around. Something like this will work:
Platform.runLater {
val node = new Circle {
centerX = 200
centerY = 200
radius = 50
stroke = Color.BROWN
strokeWidth = 2
fill = Color.DARKKHAKI
}
val jfxImage = node.snapshot(new SnapshotParameters(), null)
val bufferedImage = SwingFXUtils.fromFXImage(jfxImage, null)
val file = new File("./snapshot.png")
println("Writing snapshot to: " + file.getAbsolutePath)
javax.imageio.ImageIO.write(bufferedImage, "png", file)
()
}
The empty () to have closure returning Unit, so ScalaFX Platform.runLater is happy.
Update:
If you want to have a value from Platform.runLater the approach you suggested in your question should be in general fine. However, you want to make sure that you do not block the FX Application Thread. If you call Platform.runLater on FX Application Thread you will lock out, so you may want to have something like this
def makeSnapshot() = myNode.snapshot(new SnapshotParameters(), null)
val writableImg = if (Platform.isFxApplicationThread) {
makeSnapshot()
} else {
val futureTask = new FutureTask(new Callable[WritableImage]() {
override def call(): WritableImage = makeSnapshot()
})
Platform.runLater(futureTask)
futureTask.get()
}

Resources