Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Tunga
May 7, 2004

Grimey Drawer
Wait, where is the EditText?

(Also, tip: use the tools namespace for dummy data, e.g. tools:text=@string/whatever, this will be used in the IDE layout preview but not in the app itself so you don't risk accidentally showing "Hello world" to the user.)

Adbot
ADBOT LOVES YOU

SimonChris
Apr 24, 2008

The Baron's daughter is missing, and you are the man to find her. No problem. With your inexhaustible arsenal of hard-boiled similes, there is nothing you can't handle.
Grimey Drawer
Sorry, it turns out that the xml layout is not used at all. It's all dynamically generated in code. Most of this was written by someone else, so I'm only just figuring out how everything works myself.

I suppose all sorts of things can go wrong in this process, so I'll just have to debug some more. I just wish I knew what was different in Lollipop.

SimonChris
Apr 24, 2008

The Baron's daughter is missing, and you are the man to find her. No problem. With your inexhaustible arsenal of hard-boiled similes, there is nothing you can't handle.
Grimey Drawer


Look, the text was hiding right above the green line all along! It turns out that the height of the EditText was set to getMinimumRequiredHeight(). This used to take the size of the text into account, but apparently doesn't on Lollipop, so the EditText would just be a thin line. Maybe this is because the EditText is empty at the time it is sized? I've fixed it for now by hardcoding a minimum height, but that's obviously not ideal. Is there a better way to programmatically determine the appropriate height of an EditText?

This still doesn't explain why the OnKeyDown is never called, though. Googling around, I've found a couple of people saying that OnKeyDown is unreliable for soft keyboards and to use a TextWatcher instead. I've attached a TextWatcher to the EditText and it works!

Now I can get everything working, but I would still like to know why OnKeyDown suddenly stops working on Lollipop. Does the Lollipop keyboard work in a different way than previous keyboards? Should you really just never rely on KeyDown/Up events when using soft keyboards?

SimonChris fucked around with this message at 11:11 on Mar 6, 2015

Tunga
May 7, 2004

Grimey Drawer

SimonChris posted:

Look, the text was hiding right above the green line all along! It turns out that the height of the EditText was set to getMinimumRequiredHeight(). This used to take the size of the text into account, but apparently doesn't on Lollipop, so the EditText would just be a thin line. Maybe this is because the EditText is empty at the time it is sized?
Yes, that is most likely the case.

quote:

I've fixed it for now by hardcoding a minimum height, but that's obviously not ideal. Is there a better way to programmatically determine the appropriate height of an EditText?
It should just be defined in the layout XML with the height set to wrap_content. You shouldn't ever need to programmatically control the height of an EditText unless your layout is super wacky or you're doing an expanding box or something.

quote:

This still doesn't explain why the OnKeyDown is never called, though. Googling around, I've found a couple of people saying that OnKeyDown is unreliable for soft keyboards and to use a TextWatcher instead. I've attached a TextWatcher to the EditText and it works!

Now I can get everything working, but I would still like to know why OnKeyDown suddenly stops working on Lollipop. Does the Lollipop keyboard work in a different way than previous keyboards? Should you really just never rely on KeyDown/Up events when using soft keyboards?
Most likely this has nothing to do with the specific keyboard that you happen to have on a certain emulator/device. There is no such thing as "the Android Lollipop keyboard" because Android supports third-party keyboards. What you are seeing is part of the platform itself. I'm not sure why behaviour of KeyUp/Down events would be inconsistent (I can think of some good reasons for why they would not work ever) but you're correct in thinking that you shouldn't be using these methods anyway. You are interested in the contents of EditText so just add a TextChangedListener (as you already did). There are many ways that the text in an EditText can change: keyboard, voice input, via some other accessibility service, cut/copy/paste, etc. So you shouldn't ever mess with the method of input directly, just watch the text and do what you need to do.

Tunga fucked around with this message at 14:29 on Mar 6, 2015

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...

SimonChris posted:


Now I can get everything working, but I would still like to know why OnKeyDown suddenly stops working on Lollipop. Does the Lollipop keyboard work in a different way than previous keyboards? Should you really just never rely on KeyDown/Up events when using soft keyboards?

Lets say that I have a soft keyboard that corrects my spelling automatically. I type "Anroid<space>" and the word is autocorrected to "Android". What series of onKeyWhatever events do I expect to have occurred?

SimonChris
Apr 24, 2008

The Baron's daughter is missing, and you are the man to find her. No problem. With your inexhaustible arsenal of hard-boiled similes, there is nothing you can't handle.
Grimey Drawer

Volmarias posted:

Lets say that I have a soft keyboard that corrects my spelling automatically. I type "Anroid<space>" and the word is autocorrected to "Android". What series of onKeyWhatever events do I expect to have occurred?

Well, I was only using OnKeyDown to listen for the enter key, after which the text would be retrieved with a call to getText(). I'm not trying to parse the input one keypress at a time or anything like that. Pre-Lollipop, every keypress would trigger an event and I would watch for the enter key event. Post-Lollipop the event handler is never called at all, no matter what keys are pressed. I can get around it with the TextWatcher, but I would still like to understand how EditText event handling has apparently changed.

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...

SimonChris posted:

Well, I was only using OnKeyDown to listen for the enter key, after which the text would be retrieved with a call to getText(). I'm not trying to parse the input one keypress at a time or anything like that. Pre-Lollipop, every keypress would trigger an event and I would watch for the enter key event. Post-Lollipop the event handler is never called at all, no matter what keys are pressed. I can get around it with the TextWatcher, but I would still like to understand how EditText event handling has apparently changed.

Pull the AOSP source and delta EditText between K and L.

You should probably consider setting the imeOptions flag so that the Done button actually does something, instead of listening for the enter key.

speng31b
May 8, 2010

Volmarias posted:

Pull the AOSP source and delta EditText between K and L.

You should probably consider setting the imeOptions flag so that the Done button actually does something, instead of listening for the enter key.

Or if you're feeling lazy and you're not a bad enough dude to be pulling AOSP look up the files on grepcode.

To be fair soft key event listening is clear as dirt to an Android newbie. Unrelated, but to this day it still bugs me that there's no non-hacky soft keyboard visibility listener. I always get about 3/4 through a project thinking it won't become an issue when some designer decides the screen needs to totally change layouts (w/ animated in between states of course!) based on soft keyboard visibility.

speng31b fucked around with this message at 05:41 on Mar 13, 2015

Tunga
May 7, 2004

Grimey Drawer

speng31b posted:

I always get about 3/4 through a project thinking it won't become an issue when some designer decides the screen needs to totally change layouts (w/ animated in between states of course!) based on soft keyboard visibility.
This is a lot of truth. Every time. I recently needed a screen that was centre aligned vertically unless it didn't fit and then it would be top aligned and scroll. All worked fine until someone added an EditText that had to be bottom aligned and it just would not behave properly once the keyboard appeared.

fritz
Jul 26, 2003

Has anybody here had success getting libpd/pd-android up and running in Android Studio? I found this: http://www.journal.deviantdev.com/update-using-libpd-with-android-studio/ but I can't get the dependency stuff set up properly, and trying to build with gradle from the command line fails with :

code:
A problem occurred evaluating project ':CircleOfFifths'.
> Could not create plugin of type 'AppPlugin'.

* Try:
Run with --info or --debug option to get more log output.

* Exception is:
org.gradle.api.GradleScriptException: A problem occurred evaluating project ':CircleOfFifths'.
	at org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:54)
....

Mr Newsman
Nov 8, 2006
Did somebody say news?
Let me preface by saying that I'm working on learning Android (and subsequently Java as well) so keep this in mind if I'm doing something incredibly unorthodox.
e: ps I'm sure my naming conventions are dumb and wrong and feel free to mock them.

What's the best way to start a loop without locking the UI thread?


Background:
I'm working on a rock paper scissors game that when you click the start button a timer starts and the computer's choice is displayed. You have x seconds to make the right choice before the image disappears and you lose. If you make the winning choice, the computer presents a new choice and the timer is reduced. This happens until you tie / lose and the game is over. I want the loop to continue as long as the number of losses is still equal to 0 (code is here http://pastebin.com/jvnYwzDW)

I coded this all into a while loop that was under my main activity only to find that nothing happened and the app didn't respond. After a bit of research I figured out that the UI thread can't (won't?) update and I think that I need to implement a handler or an async task to do the work but I'm having a hard time wrapping my head around either of these options (and have failed to implement them a few times now).

How can I repetitively call gamestart() without showing my start button again until the user loses? It works just fine but I'd like it to repeat and go faster until the user loses.
Why does the UI thread lock if there's a while loop going on that consists of a bunch of different UI changes?


e: just realized that I still have a start button setvisiblity in my onclicklisteners, ignore that.

Mr Newsman fucked around with this message at 19:07 on Mar 23, 2015

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...

Mr Newsman posted:

Let me preface by saying that I'm working on learning Android (and subsequently Java as well) so keep this in mind if I'm doing something incredibly unorthodox.
e: ps I'm sure my naming conventions are dumb and wrong and feel free to mock them.

What's the best way to start a loop without locking the UI thread?


Background:
I'm working on a rock paper scissors game that when you click the start button a timer starts and the computer's choice is displayed. You have x seconds to make the right choice before the image disappears and you lose. If you make the winning choice, the computer presents a new choice and the timer is reduced. This happens until you tie / lose and the game is over. I want the loop to continue as long as the number of losses is still equal to 0 (code is here http://pastebin.com/jvnYwzDW)

I coded this all into a while loop that was under my main activity only to find that nothing happened and the app didn't respond. After a bit of research I figured out that the UI thread can't (won't?) update and I think that I need to implement a handler or an async task to do the work but I'm having a hard time wrapping my head around either of these options (and have failed to implement them a few times now).

How can I repetitively call gamestart() without showing my start button again until the user loses? It works just fine but I'd like it to repeat and go faster until the user loses.
Why does the UI thread lock if there's a while loop going on that consists of a bunch of different UI changes?


e: just realized that I still have a start button setvisiblity in my onclicklisteners, ignore that.

The problem, as you discovered, is that you were blocking the thread that's responsible for actually drawing and otherwise updating the UI. You're on the right track, though there's a few android-specific things to note, without touching on the general CS design issues here:

1) Your UI elements, such as your buttons etc should generally live in your Activity or Fragment's class as member variables, and be set after you've inflated the layout. This way, you don't have to keep getting references to them.
2) You're creating onClickListeners for multiple buttons with just about the same code; the only real difference seems to be what argument you're passing to mGameplay.setChoice. Since you're given a reference to the View that was clicked, I'd recommend determining the value to pass setChoice by comparing the view that you were passed to the buttons you're expecting, e.g.

code:
public void onClick(View v) {
  int choice = 0;
  if (v == paperButton) { 
    choice = 1;
  } else if (v == scissorsButton) {
    choice = 2;
  } else if (v == rockButton) {
    choice = 3;
  }
  mGameplay.setChoice(choice);
  ...
That said, to address your initial question, the best (and really only) way to start a loop without locking the UI thread is to start up a Thread. There are various helper classes you can use for this, such as AsyncTask (which may or may not be appropriate for your needs), but I'd argue that you really don't need a loop here; all you need is to update your countdown timer text, which you're doing, and to have an event occur when the countdown finishes (which you're doing).

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Mr Newsman posted:

Why does the UI thread lock if there's a while loop going on that consists of a bunch of different UI changes?

A thread is basically the computer executing code line by line, one after the other. Updating the UI and responding to touches and so on, they're all bits of code that the thread needs to execute, ideally as quickly as possible so the user can see an immediate response.

But if you're doing some long while loop in that thread, that's code that the thread needs to finish before it can move on to handling view updates and touch handling. The thread is busy running the loop, so all the UI stuff is delayed. (And if it's deferred for too long, you'll get an Application Not Responding popup, which you really don't want people seeing)

So the answer is to do as little as possible on the UI thread, so it's free to deal with the stuff it really needs to handle. You can get away with minor things, but anything that's likely to cause noticeable delays should be done on another thread. This other thread executes its code separately, so while that's busy with all the code it needs to get through, your UI thread has very little to do, so it's always ready to handle its business.

If you like you can think of the UI thread as being like a secretary - if you give them a lot of extra tasks to do, they might not be able to answer the phone or deal with visitors promptly. If you bring in someone else to handle those tasks, they can just get on with them and let the secretary have the results when they're ready



AsyncTask is probably your best bet, I think - for ease of use anyway, since it handles a lot of stuff automatically. Here's the example from the docs:

Java code:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }
Java code:
new DownloadFilesTask().execute(url1, url2, url3);
It basically works like this
  • You create your task class as above - the types in the angle brackets <URL, Integer, Long> are the types that will be passed into each of the task methods. All will become clear!
  • UI thread creates a new instance of your task class by calling that second bit of code, passing in a bunch of parameters which are all the same type (the first type in the angle brackets, URL in this case).
  • The task, which is still running on the UI thread, creates a whole new thread which runs the doInBackground() method, taking in those parameters you passed. The UI thread is now done with the task, and carries on merrily doing its usual stuff
  • Meanwhile the new thread is busy running doInBackground(). Any code you call in here is running on this separate thread. This is the key thing to understand - if the UI thread calls butt.fart() that code will be executed on the UI thread. If this worker thread calls butt.fart() it will be executed on the worker thread. They're entirely separate, and could even happen simultaneously (which is why multithreading has to be done carefully, if variables can be manipulated by several threads at once)
  • Also doInBackground() is calling publishProgress(), which tells the UI thread to execute the code in onProgressUpdate(). It's a way of getting the UI to display something partway through the task, instead of waiting until the whole task is complete. It takes one or more parameters of the second type in the angle brackets, an Integer here (this is a bit weird and restrictive, but you're passing data between threads here so it's how it works). You can use a Void (capital V) type if you don't actually want to pass anything, or use the publishProgress method at all
  • Once your code in doInBackground() is done, you return a result, of the 3rd type in the angle brackets (a Long in this case). This tells the UI thread to execute the code in onPostExecute(), taking the parameter returned by doInBackground(). This is where you finish up and hand the UI thread your results, or just let it know that some data structure or files or whatever you've been manipulating are ready to be accessed. It's basically a callback method, telling your UI thread what to do once the task is finished
  • The worker thread goes bye bye since the AsyncTask is complete

Hopefully you can work out how to shoehorn your business into that setup. You can roll your own implementations, with a bit more freedom, but this one handles a lot of the boilerplate and messaging issues. It's good for handing off some work that you know will hold up your UI thread

baka kaba fucked around with this message at 00:40 on Mar 24, 2015

Tunga
May 7, 2004

Grimey Drawer

Volmarias posted:

code:
public void onClick(View v) {
  int choice = 0;
  if (v == paperButton) { 
    choice = 1;
  } else if (v == scissorsButton) {
    choice = 2;
  } else if (v == rockButton) {
    choice = 3;
  }
  mGameplay.setChoice(choice);
  ...
You can set these "choice" values as a tag on the respective views (just hardcode in the XML in this case) and use them directly (except for parsing back to an int, obviously). No ugly if else else else needed.

I'd also personally use an enum to store the values for Rock etc. so you don't get them mixed up somewhere and end up with a silly bug.

Tunga fucked around with this message at 00:53 on Mar 24, 2015

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...

Tunga posted:

You can set these "choice" values as a tag on the respective views (just hardcode in the XML in this case) and use them directly (except for parsing back to an int, obviously). No ugly if else else else needed.

I'd also personally use an enum to store the values for Rock etc. so you don't get them mixed up somewhere and end up with a silly bug.

Absolutely true, and probably a better solution on both counts.

speng31b
May 8, 2010

baka kaba posted:

A thread is basically the computer executing code line by line, one after the other. Updating the UI and responding to touches and so on, they're all bits of code that the thread needs to execute, ideally as quickly as possible so the user can see an immediate response.

But if you're doing some long while loop in that thread, that's code that the thread needs to finish before it can move on to handling view updates and touch handling. The thread is busy running the loop, so all the UI stuff is delayed. (And if it's deferred for too long, you'll get an Application Not Responding popup, which you really don't want people seeing)

So the answer is to do as little as possible on the UI thread, so it's free to deal with the stuff it really needs to handle. You can get away with minor things, but anything that's likely to cause noticeable delays should be done on another thread. This other thread executes its code separately, so while that's busy with all the code it needs to get through, your UI thread has very little to do, so it's always ready to handle its business.

If you like you can think of the UI thread as being like a secretary - if you give them a lot of extra tasks to do, they might not be able to answer the phone or deal with visitors promptly. If you bring in someone else to handle those tasks, they can just get on with them and let the secretary have the results when they're ready



AsyncTask is probably your best bet, I think - for ease of use anyway, since it handles a lot of stuff automatically. Here's the example from the docs:

Java code:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }
Java code:
new DownloadFilesTask().execute(url1, url2, url3);
It basically works like this
  • You create your task class as above - the types in the angle brackets <URL, Integer, Long> are the types that will be passed into each of the task methods. All will become clear!
  • UI thread creates a new instance of your task class by calling that second bit of code, passing in a bunch of parameters which are all the same type (the first type in the angle brackets, URL in this case).
  • The task, which is still running on the UI thread, creates a whole new thread which runs the doInBackground() method, taking in those parameters you passed. The UI thread is now done with the task, and carries on merrily doing its usual stuff
  • Meanwhile the new thread is busy running doInBackground(). Any code you call in here is running on this separate thread. This is the key thing to understand - if the UI thread calls butt.fart() that code will be executed on the UI thread. If this worker thread calls butt.fart() it will be executed on the worker thread. They're entirely separate, and could even happen simultaneously (which is why multithreading has to be done carefully, if variables can be manipulated by several threads at once)
  • Also doInBackground() is calling publishProgress(), which tells the UI thread to execute the code in onProgressUpdate(). It's a way of getting the UI to display something partway through the task, instead of waiting until the whole task is complete. It takes one or more parameters of the second type in the angle brackets, an Integer here (this is a bit weird and restrictive, but you're passing data between threads here so it's how it works). You can use a Void (capital V) type if you don't actually want to pass anything, or use the publishProgress method at all
  • Once your code in doInBackground() is done, you return a result, of the 3rd type in the angle brackets (a Long in this case). This tells the UI thread to execute the code in onPostExecute(), taking the parameter returned by doInBackground(). This is where you finish up and hand the UI thread your results, or just let it know that some data structure or files or whatever you've been manipulating are ready to be accessed. It's basically a callback method, telling your UI thread what to do once the task is finished
  • The worker thread goes bye bye since the AsyncTask is complete

Hopefully you can work out how to shoehorn your business into that setup. You can roll your own implementations, with a bit more freedom, but this one handles a lot of the boilerplate and messaging issues. It's good for handing off some work that you know will hold up your UI thread

I'm not sure for a Java/Android beginner that I'd even go so far as to deal with AsyncTask, and it's also not the best choice for this application. AsyncTask is pretty dumb to be honest. There's some weirdness going on like it being a triple-parameterized type (one of the only examples of a scary parameterized type that Android really forces you to use, and it's about the most convoluted example you can get - capital V Void is the worst!). Also it's only a really light abstraction around Java threads, so it's easy to shoot yourself in the foot by writing non-thread-safe code in an AsyncTask if you try to modify the boilerplate without full understanding and access something that didn't come through your parameters in doInBackground and create an unpredictable thready bug that a newbie wouldn't understand (and really shouldn't have to, at that point in their learning). I get Android candidates sending in code all the time with the most egregious AsyncTask threading mistakes because AsyncTask provides the illusion that it's a safe alternative to threading when it's not that at all, it's just a small wrapper. If you don't understand threads and/or don't know where the wrapping happens it's a disaster.

Honestly I'd just make a UI thread handler post a runnable that keeps posting itself til it's done. This keeps all your logic on the UI thread. No foot-shooting, period. Also the UI thread is plenty fast enough for the purpose we're talking about here and there's no advantage to using a thread since you're not doing heavy processing that needs to run in a tight loop and you're not calling blocking IO on sockets like networking or whatever, you really just want to check a condition every tick. What we're talking about here is not actually the use case for an AsyncTask at all. A simpler approach would look something like:

code:
final Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
	@Override public void run() {
		// Do something here every tick on the UI thread
		if (stillRunning) {
			handler.post(this);
		}
	}
});
You could also just override onDraw for some custom view and run all your logic in ticks to that callback. This is the best choice if you need custom-drawn UI anyhow, and has all the benefits of being able to directly touch anything on the UI thread without posting cross-thread callbacks just to communicate with views.

Oh, and check out the source code for AsyncTask sometime - particularly how its threading model works under the hood - how many times that model has changed over different Android versions and how silly it is even now. If you do make heavy use of AsyncTask for all your background stuff, you should definitely be providing your own Executor, profiling thread pool sizes, etc. The default implementation isn't much more than a toy, it doesn't scale.

speng31b fucked around with this message at 06:55 on Mar 24, 2015

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

I can't say I'm an expert on this at all, so I'll definitely defer to you on that one :shobon: I literally wrote a threaded task not long after that, where the main thread just keeps an eye on a status flag on every frame, I just thought AsyncTask might be the best general option as an introduction since it Generally Works for most 'get that off the UI thread' tasks a newbie might run into, like doing IO. But yeah, if that's real bad advice then call me out, I'm still feeling my way around this area too

So your version there is basically throwing the same runnable back into the message queue until it's run out of tasks to do, right? Do one thing and then send it back? That's a nice (maybe embarrassingly entry-level) technique I'll have to remember

Mr Newsman
Nov 8, 2006
Did somebody say news?
Awesome. I implemented the handler and included handler.postdelayed and it works like a charm. I have a bug where if you lose or let the timer run out the handler will still post one more game and then stop even though my condition is that the loss clause has to equal 0. I think it's because I have my countdown timer and the postdelayed function of my handler sharing the same variable so the post delayed function is firing before the countdown timer hits 0 and updates the losses variable.
e: hurr post delayed means it's posted to run delayed from then.


Other than that bug though the framework is all laid out. If I have time to kill at work today I'll work on debugging it and implementing a better solution. As well as cleaner button detection, enums, and just general cleaning up of the code.

Thanks for the advice and the great writeups. Sometimes reading the documentation is a bit overwhelming when you're just getting started.


e: Got the code working the way I needed it to. Looks like everything works fine, now it's just to rewrite everything to be more clean / concise.
code:
 public void startButtonClick(View view) {
        losses = 0;
        wins=0;
        cdTimer = 5000;

        updateTextView();
        handler.post(new Runnable() {
            @Override
            public void run() {
                gameStart();

                if (losses == 0) {
                    handler.postDelayed(this, cdTimer);
                    if (cdTimer < 3000) {
                        cdTimer = 2000;
                    } else {
                        cdTimer = cdTimer - 1000;
                    }


                } else {
                    handler.removeCallbacksAndMessages(null);

                    updateTextView();

                }

            }
        });

Mr Newsman fucked around with this message at 17:26 on Mar 24, 2015

speng31b
May 8, 2010

baka kaba posted:

I can't say I'm an expert on this at all, so I'll definitely defer to you on that one :shobon: I literally wrote a threaded task not long after that, where the main thread just keeps an eye on a status flag on every frame,

This is why you have to be careful with threaded stuff like AsyncTask. Did you remember to make the flag volatile or use AtomicBoolean or synchronize around access to the flag? If not, it'll probably "mostly" work, but there's a subtle bug.

baka kaba posted:

I just thought AsyncTask might be the best general option as an introduction since it Generally Works for most 'get that off the UI thread' tasks a newbie might run into, like doing IO. But yeah, if that's real bad advice then call me out, I'm still feeling my way around this area too

So your version there is basically throwing the same runnable back into the message queue until it's run out of tasks to do, right? Do one thing and then send it back? That's a nice (maybe embarrassingly entry-level) technique I'll have to remember

AsyncTask or threading in general is only necessary if a single chunk of operations you perform atomically would be enough to slow down the UI thread. Usually that's only the case with heavyweight operations like image processing or blocking I/O in networking, file system access, database access, etc. Never touch disk or network on the UI thread is a pretty good rule of thumb - it's the reason it's an unchecked exception to try this unless you disable the check - but it's also a pretty good rule of thumb that you should be using someone else's well-tested and robust library to do any of those things rather than spinning up AsyncTasks and manually looping over byte streams (unless your actual project is to create a library for one of these things, in which case, you shouldn't need any of this advice because you know it all already).

speng31b fucked around with this message at 19:51 on Mar 24, 2015

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

speng31b posted:

This is why you have to be careful with threaded stuff like AsyncTask. Did you remember to make the flag volatile or use AtomicBoolean or synchronize around access to the flag? If not, it'll probably "mostly" work, but there's a subtle bug.

Right now there's a state check, when the main thread hits a certain state it creates a thread with a runnable that performs some heavy lifting. Then the main thread keeps checking a 'done' flag, which the runnable sets at the end of its code. I haven't set anything as volatile or synchronized yet, what's the bug? Something to do with out of order execution, or a long delay in the main thread seeing the new value?

speng31b posted:

AsyncTask or threading in general is only necessary if a single chunk of operations you perform atomically would be enough to slow down the UI thread. Usually that's only the case with heavyweight operations like image processing or blocking I/O in networking, file system access, database access, etc. Never touch disk or network on the UI thread is a pretty good rule of thumb - it's the reason it's an unchecked exception to try this unless you disable the check - but it's also a pretty good rule of thumb that you should be using someone else's well-tested and robust library to do any of those things rather than spinning up AsyncTasks and manually looping over byte streams (unless your actual project is to create a library for one of these things, in which case, you shouldn't need any of this advice because you know it all already).

Haha well, I thought AsyncTask was someone's well-tested and robust library since it's part of the framework and they recommend it as a way to offload work without worrying about Handlers and the like. I mean this isn't exactly new, the docs don't exactly feel... cohesive, sometimes the information you're looking for is spread over multiple pages in multiple sections, and it doesn't always feel like it's pushing the same concepts.

What do you mean about looping over byte streams though? I thought the whole idea of AsyncTask (whether it's the actual reality or not) was to provide a simple way to box up and offload work to another thread, let the main thread know when it's done, and take care of all the multithreading issues for you? This is assuming your worker task isn't interacting with things the main thread is interacting with of course. I realise this sounds incredibly naive - I've read through the SMP primer page but I still haven't fully absorbed it and all the options available.

Actually while we're on this and there's some action in the thread, I have a question! Say you're polling and analysing some sensor data, with a bunch of processing, and another thread needs to read the most recent data values - how would you coordinate that? Would you keep a set of public variables somewhere, and perform synchronized groups of read and write operations on them? Or would you have the sensor thread keep all the values private, and have some kind of messaging setup where the other thread sends update requests and receives a set of data back? (Stop me if any of this sounds stupid, I'm really new to having to worry about any of this)

Tunga
May 7, 2004

Grimey Drawer

baka kaba posted:

Haha well, I thought AsyncTask was someone's well-tested and robust library since it's part of the framework and they recommend it as a way to offload work without worrying about Handlers and the like.
I have to say that I've never really run into any problems with AsyncTasks but I've only really used them for fairly trivial stuff. Partly because...

baka kaba posted:

What do you mean about looping over byte streams though?
I think that post was just saying that you should use a library to do this stuff for you because someone else has done a better job that you're going to do. Tools like Retrofit / Volley can take away a lot of the headaches of retrieving and parsing a web service (and they also make it a lot quicker to write the code as a bonus), for example.

baka kaba posted:

Actually while we're on this and there's some action in the thread, I have a question! Say you're polling and analysing some sensor data, with a bunch of processing, and another thread needs to read the most recent data values - how would you coordinate that?
I've never done much with sensors but I would probably run the sensor monitoring code as a service and then have the app bind to it when it needs to retrieve data. This makes it easy to have the sensor stuff always running while you're switching activities (or apps, if that is needed) and provides an easy way to do the cross-thread communication. The exact way you store the data isn't too important, if you're only ever returning the latest sensor value then just throw it in a private field and put a getData() on the service to return that value.

If you need to store a lot of historic data and provide arbitrary access to that then I'd probably look at throwing it all into a SQLite or something and having other threads read from that directly. As long as the Service writes and everything else reads you shouldn't hit any disasters. I may not have put enough thought into this though.

Tunga fucked around with this message at 11:45 on Mar 25, 2015

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...
If you haven't yet, read the Oracle java tutorials. The ones about multi threading will help answer a lot of your questions.

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

^^^ I have and they're excellent, but I didn't read the multithreading stuff too closely at the time. I'll definitely get back to those

Tunga posted:

I have to say that I've never really run into any problems with AsyncTasks but I've only really used them for fairly trivial stuff. Partly because...

I think that post was just saying that you should use a library to do this stuff for you because someone else has done a better job that you're going to do. Tools like Retrofit / Volley can take away a lot of the headaches of retrieving and parsing a web service (and they also make it a lot quicker to write the code as a bonus), for example.

Oh yeah, I was just wondering if speng was talking about a specific use case instead of running some arbitrary code off the main thread.

I'm actually terrible about not using libraries, I think I need to do a mini project where I cobble something together using them as much as possible, just to get used to the idea of plugging in functionality instead of writing it myself.

(Speaking of which, have you seen that Snackbar alert/dialog in Material Design? It's a standardised popup, except there's no API for it, they just say 'make it look like this' and you're supposed to code it yourself. I hate to ask but is this... normal with Android? Cripes)

Tunga posted:

I've never done much with sensors but I would probably run the sensor monitoring code as a service and then have the app bind to it when it needs to retrieve data. This makes it easy to have the sensor stuff always running while you're switching activities (or apps, if that is needed) and provides an easy way to do the cross-thread communication. The exact way you store the data isn't too important, if you're only ever returning the latest sensor value then just throw it in a private field and put a getData() on the service to return that value.

If you need to store a lot of historic data and provide arbitrary access to that then I'd probably look at throwing it all into a SQLite or something and having other threads read from that directly. As long as the Service writes and everything else reads you shouldn't hit any disasters. I may not have put enough thought into this though.

The sensor stuff is receiving events and calculating constantly, but it only runs while the app is visible (while a surfaceview is rendering actually), and the reader is getting updates every frame, which is why I'm not sure if a service is the best fit? Does it create a lot of overhead? Right now I've just got the processor's onSensorChanged method doing the calculations and writing to a public field, and the reader just looks at them to get the lastest numbers, which is really half-assed but it seems to work ok for now. (There's no historic data, just a bunch of ints and doubles holding the last calculated state)

I'm just worried it'll create an issue somewhere, and ideally I'd like to update atomically so the reader isn't getting some old and some new values if it reads at the wrong time. I was thinking of making a synchronized read/write method but I'm not exactly sure it's the right way to go

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Libraries are one of the best parts about programming! Implement cool, well-tested functionality without all the work of doing it yourself.

Go forth and use all the libraries.

(replace work of implementing functionality with work of finding appropriate library)

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Yeah I finally looked at web dev again for a thing I need to do, since my days of handcrafting artisanal HML and CSS files in notepad, and holy moly :eyepop:

I wonder if the murderous AI that will eventually kill us all will build itself from GitHub repositories

speng31b
May 8, 2010

baka kaba posted:

Right now there's a state check, when the main thread hits a certain state it creates a thread with a runnable that performs some heavy lifting. Then the main thread keeps checking a 'done' flag, which the runnable sets at the end of its code. I haven't set anything as volatile or synchronized yet, what's the bug? Something to do with out of order execution, or a long delay in the main thread seeing the new value?

It's only an issue if one or more threads are checking the state of a non-volatile, non-synchronized value that is updated by another thread over the course of its execution. For instance if one thread "owns" a variable and it updates that variable and other threads "watch" that variable without synchronization or some other explicit thread safety technique, it's a bug. Read over the Oracle docs on threading again as another poster suggested and you'll see what I mean, this is literally the prototype scenario for "what not to do with Java threads" so there's lots of info on it.

baka kaba posted:

Haha well, I thought AsyncTask was someone's well-tested and robust library since it's part of the framework and they recommend it as a way to offload work without worrying about Handlers and the like. I mean this isn't exactly new, the docs don't exactly feel... cohesive, sometimes the information you're looking for is spread over multiple pages in multiple sections, and it doesn't always feel like it's pushing the same concepts.

Yeah based on the docs that is a problematic misconception. It's not really about being well-tested and robust or not - AsyncTask is as well-tested and robust as Java threads are, it just shouldn't be used in situations when you don't just want a slightly more convenient syntax for spinning up a raw thread. In any Java app, Android or otherwise, it would be poor style to spin up unabstracted raw threads for most core tasks. AsyncTasks are still fine for spinning off one-off operations that you couldn't solve with a more centralized solution. For example, in one app I've been working on, we need to generate barcodes from raw QR/barcode data that comes back from a web service. We don't want to generate images on the main thread, but it's also silly to introduce a dependency for something as simple and one-off as generating a scannable Bitmap to stick in an ImageView. So we spin off an AsyncTask for it. That makes sense. Writing your own networking layer held together with the Java equivalent of duct tape and Elmer's glue probably doesn't make sense, though. And that leads to...

baka kaba posted:

What do you mean about looping over byte streams though? I thought the whole idea of AsyncTask (whether it's the actual reality or not) was to provide a simple way to box up and offload work to another thread, let the main thread know when it's done, and take care of all the multithreading issues for you? This is assuming your worker task isn't interacting with things the main thread is interacting with of course. I realise this sounds incredibly naive - I've read through the SMP primer page but I still haven't fully absorbed it and all the options available.

The "looping over byte arrays" comment is more of a benchmark for when it's a good idea to use a library than a hard and fast rule. Generally speaking if you find yourself reading raw bytes streams in an AsyncTask, you should stop and ask yourself if there's a well-known, well-documented, well-tested dependency that will do this for you. The answer is probably yes and it's probably something in one of Square's repos. There's nothing fundamentally wrong with reading byte streams in a thread, but it's just the sort of task a library is well-suited to accomplish because that broader base of usage can account for a lot of issues that you probably wouldn't find yourself until something started failing in production in some weirdly specific range of devices (I'm looking at you, LG devices running 4.1.x).

baka kaba posted:

Actually while we're on this and there's some action in the thread, I have a question! Say you're polling and analysing some sensor data, with a bunch of processing, and another thread needs to read the most recent data values - how would you coordinate that? Would you keep a set of public variables somewhere, and perform synchronized groups of read and write operations on them? Or would you have the sensor thread keep all the values private, and have some kind of messaging setup where the other thread sends update requests and receives a set of data back? (Stop me if any of this sounds stupid, I'm really new to having to worry about any of this)

Depends on how complex the data you need to monitor is. If it's just a boolean or an int or something, and only one thread is allowed to update the data but others are allowed to monitor it, the volatile keyword works well. AtomcXXX classes in java.util.concurrent.atomic package work well. Synchronized getters/setters work well. If you need something a little more robust and are looking for a wholesale solution to eventing tailored for Android I'd recommend looking at Otto from Square (http://square.github.io/otto/), which supports both broadcasting general events and receivers that pull the latest state on demand when they register. Android also provides tons of built-ins for this sort of thing, like Services, though I do think there is a tendency to overuse services for things that there are simpler solutions to. This is a pretty broad problem so there are lots of good answers.

speng31b fucked around with this message at 16:15 on Mar 25, 2015

Tunga
May 7, 2004

Grimey Drawer

baka kaba posted:

I'm just worried it'll create an issue somewhere, and ideally I'd like to update atomically so the reader isn't getting some old and some new values if it reads at the wrong time. I was thinking of making a synchronized read/write method but I'm not exactly sure it's the right way to go
I was about to post about how you should probably use an event bus of some kind so that your activity can register to receive value changes rather than polling for them. But the post above covered all of that perfectly.

I've not had an opportunity to use Otto yet but various developer friends have recommended it to me and everything else that I've used from Square has been excellent.

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

speng31b posted:

It's only an issue if one or more threads are checking the state of a non-volatile, non-synchronized value that is updated by another thread over the course of its execution. For instance if one thread "owns" a variable and it updates that variable and other threads "watch" that variable without synchronization or some other explicit thread safety technique, it's a bug. Read over the Oracle docs on threading again as another poster suggested and you'll see what I mean, this is literally the prototype scenario for "what not to do with Java threads" so there's lots of info on it.

It's more of a lazy technique - thread A sets flag to false and spins off thread B. Then every frame thread A checks the flag. Thread B sets it to true when it's done, eventually thread A sees it and runs the followup code. Intuitively it feels like it would work fine and there might just be a couple of frames' delay before thread A sees the updated flag - is that generally true on Android, or are there weird potential out-of-order issues that could set the flag too early or have thread A see it incredibly late, or even never, without some judicious keyword usage?

I'm not saying this is a good idea, or arguing so I can keep doing it (I'm reading up on the Oracle docs now), just trying to get a feel for it if you don't mind :shobon:

speng31b posted:

The "looping over byte arrays" comment is more of a benchmark for when it's a good idea to use a library than a hard and fast rule. Generally speaking if you find yourself reading raw bytes streams in an AsyncTask, you should stop and ask yourself if there's a well-known, well-documented, well-tested dependency that will do this for you. The answer is probably yes and it's probably something in one of Square's repos. There's nothing fundamentally wrong with reading byte streams in a thread, but it's just the sort of task a library is well-suited to accomplish because that broader base of usage can account for a lot of issues that you probably wouldn't find yourself until something started failing in production in some weirdly specific range of devices (I'm looking at you, LG devices running 4.1.x).

That makes sense, and one of the few places I'm using an AsyncTask is doing... yeah let's just say I've got some byte streams. I need to make that more robust anyway so I'll definitely be looking into some libraries

speng31b posted:

Depends on how complex the data you need to monitor is. If it's just a boolean or an int or something, and only one thread is allowed to update the data but others are allowed to monitor it, the volatile keyword works well. AtomcXXX classes in java.util.concurrent.atomic package work well. Synchronized getters/setters work well. If you need something a little more robust and are looking for a wholesale solution to eventing tailored for Android I'd recommend looking at Otto from Square (http://square.github.io/otto/), which supports both broadcasting general events and receivers that pull the latest state on demand when they register. Android also provides tons of built-ins for this sort of thing, like Services, though I do think there is a tendency to overuse services for things that there are simpler solutions to. This is a pretty broad problem so there are lots of good answers.

Haha this has always been my problem, so many options, and it's not always obvious why you'd prefer one AsyncTask over the other. I guess I'll look at the docs and work out a simple solution to introduce a bit of safety, and then look at the more involved structures to see if there's anything I need. Thanks guys!

The MUMPSorceress
Jan 6, 2012


^SHTPSTS

Gary’s Answer

baka kaba posted:

It's more of a lazy technique - thread A sets flag to false and spins off thread B. Then every frame thread A checks the flag. Thread B sets it to true when it's done, eventually thread A sees it and runs the followup code. Intuitively it feels like it would work fine and there might just be a couple of frames' delay before thread A sees the updated flag - is that generally true on Android, or are there weird potential out-of-order issues that could set the flag too early or have thread A see it incredibly late, or even never, without some judicious keyword usage?

I'm not saying this is a good idea, or arguing so I can keep doing it (I'm reading up on the Oracle docs now), just trying to get a feel for it if you don't mind :shobon:

What you're talking about is called a Condition Variable. I'm not super familiar with Android, but most platforms that allow concurrency also have some type of CV structure that supports signalling waiting threads. You shouldn't see much of a delay at all between your worker thread completing and your primary thread being signaled if you're using the platform's support for it.

fake edit: What do you know, Android is kind enough to name their implementation in a non-stupid way: http://developer.android.com/reference/android/os/ConditionVariable.html

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Actually in this case, I think that's the opposite of what I need! I added the threading to avoid blocking a renderer thread during some initialisation work, so it's just keeping an eye on the progress while it does its thing. Definitely good to know though, thanks - I already did some while loop spinning before I settled on something else, and I can see this being useful in other places too

speng31b
May 8, 2010

baka kaba posted:

It's more of a lazy technique - thread A sets flag to false and spins off thread B. Then every frame thread A checks the flag. Thread B sets it to true when it's done, eventually thread A sees it and runs the followup code. Intuitively it feels like it would work fine and there might just be a couple of frames' delay before thread A sees the updated flag - is that generally true on Android, or are there weird potential out-of-order issues that could set the flag too early or have thread A see it incredibly late, or even never, without some judicious keyword usage?

No this is the exact antipattern I'm talking about. Don't do this, you're right about the errors it might cause. Not to be too harsh but if I saw an interview candidate provide code that did this I'd move on.

To summarize, a thread modifying a variable is not required to publish the state of that variable to other threads except when synchronization or the volatile keyword are used.

Implementations vary, but you can think of each thread as having its own memory space (this is not exactly true, but it's a good way to conceptualize it). It costs resources to publish that memory space to other threads, so when resources are not available, some environments will have threads keeping their updates "secret" unless explicitly flushed. Take a look at this stack overflow answer for a bit more detail:

http://stackoverflow.com/questions/2787094/how-to-demonstrate-java-multithreading-visibility-problems

Like many threading mistakes, this sort of thing will only manifest as a noticeable bug under specific conditions in specific environments. This is why you don't typically use raw threads if there's a nicer solution available (or raw AsyncTasks, which aren't as far abstracted from threads as some people believe). Java threading is a trap for complacent programmers to make silly mistakes that are very difficult to diagnose even if you're very experienced.

Long story short, read the book Java concurrency in practice. You'll be happy you did.

speng31b fucked around with this message at 05:36 on Mar 27, 2015

kitten smoothie
Dec 29, 2001

Trying to grok rxjava by incorporating it into a side project I'm building here. I'm putting together a streaming radio player. I've got a JSON backend I'm hitting with Retrofit that pulls down information about what's "now playing."

The main activity for the app should be getting this info periodically (let's say every 60 seconds), so if you've got the app foregrounded you're seeing a rough approximation of what's on the air. If you're backgrounded and playing music, I want to have the info appear in the notification (presented by a player service) and be updated periodically as well.

I'm seeing an example or two that define a singleton class that sets up a BehaviorSubject and periodically post updates at it. Then the individual consumers (i.e. my player service and my activity) can subscribe on this. Since the BehaviorSubject emits the latest-seen item observed, subscribing means you get the last known "now playing" value right away. Is that the best/right way to accomplish what I'm trying to do here?

ButtaKnife
Mar 12, 2007

"I WILL DEVOUR 100 GENERATIONS OF YOUR FAMILY!"

baka kaba posted:

(Speaking of which, have you seen that Snackbar alert/dialog in Material Design? It's a standardised popup, except there's no API for it, they just say 'make it look like this' and you're supposed to code it yourself. I hate to ask but is this... normal with Android? Cripes)

Well, err, it... :sigh: yes. Though, I think Google is getting better about it. An upcoming release of AppCompat will finally have some kind of NavigationDrawerView to actually provide a full nav drawer implementation. As for the snackbar, though, GitHub has you covered.

Speaking of AppCompat, I ran into https://code.google.com/p/android/issues/detail?id=78377 while finally getting our project at work over to Android Studio and the support libraries. :argh: Samsung!

kitten smoothie posted:

I'm seeing an example or two that define a singleton class that sets up a BehaviorSubject and periodically post updates at it. Then the individual consumers (i.e. my player service and my activity) can subscribe on this. Since the BehaviorSubject emits the latest-seen item observed, subscribing means you get the last known "now playing" value right away. Is that the best/right way to accomplish what I'm trying to do here?

To me it sounds like a nicer design would use Otto and its producer functionality which can dispense the "now playing" when any object subscribes. Your objects are more decoupled, then, because they don't need to know about a singleton. They merely subscribe to receive the appropriate object types. I used Guava's EventBus in a project recently and the decoupling was absolutely magical. "Object X needs to receive updates... subscribe! Done." And Otto is even better because of that producer capability, so I highly recommend trying it.

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Yeah I noticed a few people had made snackbar libraries, I just thought it was hilarious that you've got this big ~Material Design~ push with all these features to make it easier to have a dynamic, material app, and soooo many new APIs in Lollipop and then... this standardised system dialog, described in the design pages, is effectively a bunch of rules about padding. Don't provide an xml file or anything!

I love the first reply on that AppCompat thread

speng31b posted:

No this is the exact antipattern I'm talking about. Don't do this, you're right about the errors it might cause. Not to be too harsh but if I saw an interview candidate provide code that did this I'd move on.

No no, harsh away - I wouldn't be asking all these questions if I thought it was safe and the right way to do it. I like to know I'm structuring things properly, so I need to know at least the basics of where the pitfalls are and make sure I'm addressing them somehow. Anyway I'm convinced, this is the next thing I'm fixing and it's about time I got a handle on it, cheers!

PiCroft
Jun 11, 2010

I'm sorry, did I break all your shit? I didn't know it was yours

This is largely for my own sanity, but I'm curious about something. We want to gather touch data for an app and write the type of touch to a database. While we can get the touch type easily enough, I noticed there was a very handy looking function called actionToString() in MotionEvent that translates the touch type directly to a sensible string. For somer reason, any attempt to use it failed; intellisense didn't detect it, manually calling it results in unrecognized error and I can confirm it was indeed there in the source code (its build-in Android stuff).

On researching it, it turns out this call is hidden on earlier version of Android SDK (pre 19 I think), despite the fact that literally all it does is perform a switch statement and returns a string with the action type.

Does anyone know why the hell this is hidden?

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...

PiCroft posted:

This is largely for my own sanity, but I'm curious about something. We want to gather touch data for an app and write the type of touch to a database. While we can get the touch type easily enough, I noticed there was a very handy looking function called actionToString() in MotionEvent that translates the touch type directly to a sensible string. For somer reason, any attempt to use it failed; intellisense didn't detect it, manually calling it results in unrecognized error and I can confirm it was indeed there in the source code (its build-in Android stuff).

On researching it, it turns out this call is hidden on earlier version of Android SDK (pre 19 I think), despite the fact that literally all it does is perform a switch statement and returns a string with the action type.

Does anyone know why the hell this is hidden?

If it's not publicly available, you CANNOT rely on an OEM not loving it up. This has bitten me in the past.

If it's public now, you can always git blame the reason from AOSP.

Tunga
May 7, 2004

Grimey Drawer
I have no idea why it was hidden, maybe it wasn't (thought to be) finished?

The code for it is fairly trivial anyway, it is mostly just returning the enum name. It's also static, so just copy that code to a helper method and you should be good.

PiCroft
Jun 11, 2010

I'm sorry, did I break all your shit? I didn't know it was yours

Tunga posted:

I have no idea why it was hidden, maybe it wasn't (thought to be) finished?

The code for it is fairly trivial anyway, it is mostly just returning the enum name. It's also static, so just copy that code to a helper method and you should be good.

This is what I did anyway, I was just mystified why such a trivial bit of code was hidden at all. Maybe the action enums changed at some point or was due to change?

Anyway, mini-rant over.

Sereri
Sep 30, 2008

awwwrigami

Any idea what would cause emojis to be displayed like this:


Might as well be a forum problem I guess.

Adbot
ADBOT LOVES YOU

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Kinda looks like a stride problem with a bitmap stream, or something? Are they the monochrome emojis?

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply