How to update Android textviews efficiently? - android

I am working on an Android app which encounters performance issues.
My goal is to receive strings from an AsyncTask and display them in a TextView. The TextView is initially empty and each time the other process sends a string concatenates it to the current content of the textview.
I currently use a StringBuilder to store the main string and each time I receive a new string, I append it to the StringBuilder and call
myTextView.setText(myStringBuilder.toString())
The problem is that the background process can send up to 100 strings per second, and my method is not efficient enough.
Redrawing the whole TextView everytime is obviously a bad idea (time complexity O(N²)), but I'm not seeing another solution...
Do you know of an alternative to TextView which could do these concatenations in O(N) ?

As long as there is a newline between the strings, you could use a ListView to append the strings and hold the strings themselves in an ArrayList or LinkedList to which you append as the AsyncTask receives the strings.
You might also consider simply invalidating the TextField less frequently; say 10 times a second. This would certainly improve responsiveness. Something like the following could work:
static long lastTimeUpdated = 0;
if( receivedString.size() > 0 )
{
myStringBuilder.append( receivedString );
}
if( (System.currentTimeMillis() - lastTimeUpdated) > 100 )
{
myTextView.setText( myStringBuilder.getChars( 0, myStringBuilder.length() );
}
If the strings come in bursts -- such that you have a delay between bursts greater than, say, a second -- then reset a timer every update that will trigger this code to run again to pick up the trailing portion of the last burst.

I finally found an answer with the help of havexz and Greyson here, and some code here.
As the strings were coming in bursts, I chose to update the UI every 100ms.
For the record, here's what my code looks like:
private static boolean output_upToDate = true;
/* Handles the refresh */
private Handler outputUpdater = new Handler();
/* Adjust this value for your purpose */
public static final long REFRESH_INTERVAL = 100; // in milliseconds
/* This object is used as a lock to avoid data loss in the last refresh */
private static final Object lock = new Object();
private Runnable outputUpdaterTask = new Runnable() {
public void run() {
// takes the lock
synchronized(lock){
if(!output_upToDate){
// updates the outview
outView.setText(new_text);
// notifies that the output is up-to-date
output_upToDate = true;
}
}
outputUpdater.postDelayed(this, REFRESH_INTERVAL);
}
};
and I put this in my onCreate() method:
outputUpdater.post(outputUpdaterTask);
Some explanations: when my app calls its onCreate() method, my outputUpdater Handler receives one request to refresh. But this task (outputUpdaterTask) puts itself a refresh request 100ms later. The lock is shared with the process which send the new strings and sets output_upToDate to false.

Try throttling the update. So instead of updating 100 times per sec as that is the rate of generation. Keep the 100 strings in string builder and then update once per sec.
Code should like:
StringBuilder completeStr = new StringBuilder();
StringBuilder new100Str = new StringBuilder();
int counter = 0;
if(counter < 100) {
new100Str.append(newString);
counter++;
} else {
counter = 0;
completeStr.append(new100Str);
new100Str = new StringBuilder();
myTextView.setText(completeStr.toString());
}
NOTE: Code above is just for illustration so you might have to alter it as per your needs.

Related

Get 64bit timestamps from a 32bit timer

On my stm32wb55, I am using the 32bit-timer "tim2" for reading the time from 32bit-register "CNT" since system startup. With prescaling, I display the time in microseconds on my putty-console and it works very well. But now, I need to memory higher values. So I want to memory the time in a 64bit integer.
Does anyone know a simple way for doing that?
The tim2 timer is a 32bit resolution timer, you want a 64bit resolution. There are two ways to emulate a 64bit counter, to keep track of your uptime.
One would be incrementing a variable each time you reach the unit of time that you want to keep track of. But that would be extremely inefficient giving that the microcontroller would be doing a lot of constant context switching.
The second way would be to extend the timer with a 32bit variable. Then incrementing such variable on an overflow.
MSB LSB
+--------------+ +--------------+
| 32bit uint | | 32bit timer |
+--------------+ +--------------+
The way this works is that after the timer reaches 0xffffffff which is the maximum for a 32bit unsigned counter, the timer will overflow and start back at 0. If there was another bit after that 32'th bit, it will flip on(which is the same as incrementing). What you can do is emulate this exact behavior by incrementing a variable.
First, set up your timer.
static TIM_HandleTypeDef s_TimerInstance = {
.Instance = TIM2
};
void setup_timer()
{
__TIM2_CLK_ENABLE();
s_TimerInstance.Init.Prescaler = ##; //Chose the correct value that fits your needs
s_TimerInstance.Init.CounterMode = TIM_COUNTERMODE_UP;
s_TimerInstance.Init.Period = 0xffffffff; //Chose the correct value that fits your needs
s_TimerInstance.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; //Also choose this value
s_TimerInstance.Init.RepetitionCounter = 0;
HAL_TIM_Base_Init(&s_TimerInstance);
HAL_TIM_Base_Start(&s_TimerInstance);
}
Your handler, this has to be called each time your timer reaches 0xffffffff
extern void TIM2_IRQHandler();
void TIM2_IRQHandler()
{
HAL_TIM_IRQHandler(&s_TimerInstance);
}
uint32_t extension;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
extension++; //Increment
}
Combine the extension variable and the timer value. Use this function each time you want to get the extender counter value. You can make it inline to avoid extra calls, or as a macro.
uint64_t get_time()
{
return (extension << 32) & (__HAL_TIM_GET_COUNTER(&s_TimerInstance));
}
Now glue everything together
int main(void)
{
HAL_Init(); //Initialize HAL library
InitializeTimer(); //Initialize timer
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
while(1);
}
Note, that now tim2 will be used until it overflows. It should not be changed, or the following code will not work. Also, setup the divider, so the timer increment each microsecond as you stated earlier.
Also, you can use the timer to count seconds and then calculate the microsecond instead. If you count seconds instead you can count up to 2^32 seconds which is 4294967296. A year has about 31536000 seconds. With a 32bit counter (4294967296/31536000) you can count up to 136.19252 years of uptime. Then get the microseconds by dividing the uptime with 1000000 (uptime/1000000). I don't know what are you planning to do with the microcontroller, but counting seconds sounds more sensical for me.
If you really want precision, you can still do it by counting seconds, you can add the timer counter value to the microsecond count, which you can get by diving the seconds down into microseconds, that way you offset microseconds that haven't been added to the second count.
If you only access this from a non-ISR [non interrupt service] context, it's pretty simple.
If you have an ISR, the base level needs to lock/unlock interrupt handling. The ISR does not have to be related to the timer interrrupt. It could be for any ISR (e.g. tty, disk, SPI, video/audio, whatever).
Here's some representative code for a simple semi-baremetal implementation [this is similar to what I've done in some R/T commercial products, notably in a microblaze inside a Xilinx FPGA]:
typedef unsigned int u32;
typedef unsigned long long u64;
volatile int in_isr; // 1=inside an ISR
volatile u32 oldlo; // old LSW timer value
volatile u32 oldhi; // MSW of 64 bit timer
// clear and enable the CPU interrupt flag
void cli(void);
void sti(void);
// tmr32 -- get 32 bit timer/counter
u32 tmr32(void);
// tmrget -- get 64 bit timer value
u64
tmrget(void)
{
u32 curlo;
u32 curhi;
u64 tmr64;
// base level must prevent interrupts from occurring ...
if (! in_isr)
cli();
// get the 32 bit counter/timer value
curlo = tmr32();
// get the upper 32 bits of the 64 bit counter/timer
curhi = oldhi;
// detect rollover
if (curlo < oldlo)
curhi += 1;
oldhi = curhi;
oldlo = curlo;
// reenable interrupts
if (! in_isr)
sti();
tmr64 = curhi;
tmr64 <<= 32;
tmr64 |= curlo;
return tmr64;
}
// isr -- interrupt service routine
void
isr(void)
{
// say we're in an ISR ...
in_isr += 1;
u64 tmr = tmrget();
// do stuff ...
// leaving the ISR ...
in_isr -= 1;
}
// baselevel -- normal non-interrupt context
void
baselevel(void)
{
while (1) {
u64 tmr = tmrget();
// do stuff ...
}
}
This works fine if tmrget is called frequently enough that it catches each rollover of the 32 bit timer value.

How to give pause or gap between words in TTS in android

I have given a text in mytts.speak("hi hello hi",parameter,parameter...);
But the words are continuously said without any gap or pause, I want to provide some time gap between words for more clarity.
How could I achieve this ?
If I understand your question correctly, this thread has the answer (by rushi).
Simply add a delay into the TTS queue by splitting the string and loop over the snippets via a for loop:
mytts.speak(snippet, QUEUE_ADD, null);
mytts.playSilentUtterance(2000, QUEUE_ADD, null);
Simply add a comma everywhere you want there to be pauses inserted.
For example: If you want the following web address to be said slower, enter it as a, t, t, r, s.gov
I realize this may not be suitable for some applications, but it definitely works.
This is how I put a longer pause between each word:
//initialize and declare TextToSpeech as tts
//"line" is the String you are trying to speak
char ch = '';
String temp = "";
for(int counter = 0; counter < line.length; counter++)
{
ch = charAt(counter);
temp = temp + ch;
if(ch == ' ' || counter == (line.length() - 1))
{
tts.speak(temp, TextToSpeech.QUE_ADD, null, null);
tts.playSilentUtterance(1000, TextToSpeech.QUEUE_ADD,null);
temp = "";
}
}
Try adding '/ / / / /' to your text. It should give you it some breathing room. If you want a longer pause, try adding more.
You can split you sentence in words and speak them in a for loop in a new thread. Splitting the phrase will give you a little delay, but if you want a longer one you could work on thread and make them wait.
It would be something like this:
final Handler h = new Handler();
String[] words = text.split(" ");
for (final CharSequence word : words) {
Runnable t = new Thread() {
#Override
public void run() {
m_TTS.speak(word, TextToSpeech.QUEUE_ADD, null, "TTS_ID");
}
};
h.postDelayed(t, 1000);
}

what does the three dots in "doInBackground(URL... urls)" mean?

what does the "..." in each function mean? and why in the last function, there is no "..."?
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");
}
}
As Morrison said, the ... syntax is for a variable length list of arguments (urls holds more than one URL).
This is typically used to allow users of the AsyncTask to do things like (in your case) pass in more than one URL to be fetched in the background. If you only have one URL, you would use your DownloadFilesTask like this:
DownloadFilesTask worker = new DownloadFilesTask();
worker.execute(new URL("http://google.com"));
or with multiple URLs, do this:
worker.execute(new URL[]{ new URL("http://google.com"),
new URL("http://stackoverflow.com") });
The onProgressUpdate() is used to let the background task communicate progress to the UI. Since the background task might involve multiple jobs (one for each URL parameter), it may make sense to publish separate progress values (e.g. 0 to 100% complete) for each task. You don't have to. Your background task could certainly choose to calculate a total progress value, and pass that single value to onProgressUpdate().
The onPostExecute() method is a little different. It processes a single result, from the set of operations that were done in doInBackground(). For example, if you download multiple URLs, then you might return a failure code if any of them failed. The input parameter to onPostExecute() will be whatever value you return from doInBackground(). That's why, in this case, they are both Long values.
If doInBackground() returns totalSize, then that value will be passed on onPostExecute(), where it can be used to inform the user what happened, or whatever other post-processing you like.
If you really need to communicate multiple results as a result of your background task, you can certainly change the Long generic parameter to something other than a Long (e.g. some kind of collection).
In Java its called Varargs which allow for a variable number of parameters.
http://docs.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
The three dots are ... are used to indicate ellipsis, In our case in Java Language these are used to indicate varangs (variable no. of arguments).
Let me explain a little bit about varangs:
The varangs allows the method to accept zero or muliple
arguments.If we don't know how many argument we will have to pass in
the method, varargs is the better approach.
Syntax of varargs:
The varargs uses ellipsis i.e. three dots after the data type. Syntax is as follows:
return_type method_name(data_type... variableName){}
Simple Example of Varargs in java:
class VarargsExample1{
static void display(String... values){
System.out.println("display method invoked ");
}
public static void main(String args[]){
display();//zero argument
display("my","name","is","varargs");//four arguments
}
}
Rules for varargs:
While using the varargs, you must follow some rules otherwise program
code won't compile. The rules are as follows:
There can be only one variable argument in the method. Variable
argument (varargs) must be the last argument.
Very short (and basic) answer:
That represents a variable number of items "converted" to an array and it should be the last argument.
Example:
test("string", false, 20, 75, 31);
void test(String string, boolean bool, int... integers) {
// string = "string"
// bool = false
// integers[0] = 20
// integers[1] = 75
// integers[2] = 31
}
But you can also call
test("text", true, 15);
or
test("wow", true, 1, 2, 3, 4, 5, 6, 7, 8, 9, 100, 123, 345, 9123);

ORMLite's createOrUpdate seems slow - what is normal speed?

Calling the ORMLite RuntimeExceptionDao's createOrUpdate(...) method in my app is very slow.
I have a very simple object (Item) with a 2 ints (one is the generatedId), a String and a double. I test the time it takes (roughly) to update the object in the database (a 100 times) with the code below. The log statement logs:
time to update 1 row 100 times: 3069
Why does it take 3 seconds to update an object 100 times, in a table with only 1 row. Is this the normal ORMLite speed? If not, what might be the problem?
RuntimeExceptionDao<Item, Integer> dao =
DatabaseManager.getInstance().getHelper().getReadingStateDao();
Item item = new Item();
long start = System.currentTimeMillis();
for (int i = 0; i < 100; i++) {
item.setViewMode(i);
dao.createOrUpdate(item);
}
long update = System.currentTimeMillis();
Log.v(TAG, "time to update 1 row 100 times: " + (update - start));
If I create 100 new rows then the speed is even slower.
Note: I am already using ormlite_config.txt. It logs "Loaded configuration for class ...Item" so this is not the problem.
Thanks.
This may be the "expected" speed unfortunately. Make sure you are using ORMLite version 4.39 or higher. createOrUpdate(...) was using a more expensive method to test for existing of the object in the database beforehand. But I suspect this is going to be a minimal speed improvement.
If I create 100 new rows then the speed is even slower.
By default Sqlite is in auto-commit mode. One thing to try is to wrap your inserts (or your createOrUpdates) using the the ORMLite Dao.callBatchTasks(...) method.
In by BulkInsertsTest android unit test, the following doInserts(...) method inserts 1000 items. When I just call it:
doInserts(dao);
It takes 7.3 seconds in my emulator. If I call using the callBatchTasks(...) method which wraps a transactions around the call in Android Sqlite:
dao.callBatchTasks(new Callable<Void>() {
public Void call() throws Exception {
doInserts(dao);
return null;
}
});
It takes 1.6 seconds. The same performance can be had by using the dao.setSavePoint(...) method. This starts a transaction but is not as good as the callBachTasks(...) method because you have to make sure you close your own transaction:
DatabaseConnection conn = dao.startThreadConnection();
Savepoint savePoint = null;
try {
savePoint = conn.setSavePoint(null);
doInserts(dao);
} finally {
// commit at the end
conn.commit(savePoint);
dao.endThreadConnection(conn);
}
This also takes ~1.7 seconds.

Android - converting string to long value

I am creating a fairly simple android application which is basically a timer, I am trying to make it so that you can set the timer length in the settings and then using preferences retrieve the value and set it as the timer length. I can retrieve the value from the preferences and simply display it.
But when I try to convert the string value (i.e. 1) to a long value using either Long.parseLong(string) or Long.valueOf(String) and Long.valueOf(Int), I don't receive any errors in the code but when I try and start the application, it force closes and the error log says it is caused by NumberFormatException, Here is the the section of code I am using, also if I remove the line that says Long.ParseLong... everything else works fine.
private long interval = 1000 ;
private long startTime = 30000;
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_countdown_timer);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
StringBuilder builder = new StringBuilder();
builder.append("\n"+ prefs.getString("timerLength","NULL"));
startTime = Long.parseLong(builder.toString());
TextView view = (TextView)findViewById(R.id.showTimer);
view.setText(builder.toString());
Pls remove "\n"
StringBuilder builder = new StringBuilder();
builder.append(prefs.getString("timerLength","NULL"));
startTime = Long.parseLong(builder.toString());
The problem is the '\n' character. The string should only contain a long as a String for it to be successfully parsed.

Categories

Resources