I am making a simple Android program that runs mnemonics or math exercises for training purposes.
I have a "new exercise" button that changes question and answer. I want to implement a "text to speech" mode, where the software reads the question and the answer. After they are spoken, it should calculate a new question and start again.
I am using OnUtteranceCompleted to determine if the speech has ended. My problem is that I can’t access my "new exercise" button from the callback.
I am using this:
private TextToSpeech.OnUtteranceCompletedListener onUtteranceCompleted = new TextToSpeech.OnUtteranceCompletedListener()
{
#Override
public void onUtteranceCompleted(String utteranceId)
{
if(0 == utteranceId.compareToIgnoreCase(END_OF_SPEECH))
{
Log.i("TTS","Completed");
if (TTSMode == TTS_MODE_ON) {
//Start new
Log.i("TTS","TTS mode is on: start new exercize");
NewExercize();
btnNewEx.performClick();
}
}
}
};
I got the following error:
$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
I am able to generate the new question/answer, but I can’t use the button to change the fields with the new question or answer, wich are used by the TTS engine.
Any ideas?
You need to use runOnUiThread:
context.runOnUiThread( new Runnable() {
public void run() {
btnNewEx.performClick();
}
});
(you can omit "context." if "this" is an Activity or Service subclass)
Related
I am trying to make an android app that captures photos after every 5 seconds. Currently the technique i'm using, uses the phone's camera app to capture the photo. It requires the user to capture the photo and then to press ok and only after that the control returns back to the android app. I found some codes to do the same without human interaction, but since i'm new to android, i'm not able to understand codes them because most of them are incomplete and divided into multiple activities. Can this be done using just one activity?
EDIT :
The codes mentioned above can be found here
I suggest to you to use this library (here documentation) instead the official Camera Api of Android that could be really tricky to use for beginners
Then your code could be like this
private final Handler handler = new Handler(); //This should be declared before OnCreate
private Runnable photoRunnable; //This also
CameraView camera = findViewById(R.id.camera);
camera.addCameraListener(new CameraListener() {
public void onPictureTaken(PictureResult result) {
//Handle result here!
}
});
photoRunnable = new Runnable() {
#Override
public void run() {
try {
camera.takePicture(); //The result will be in onPictureTaken
}
catch (Exception e) {
e.printStackTrace();
//Handle Exception!
}
finally{
//also call the same runnable to call it at regular interval
handler.postDelayed(this, 10*1000); //10*1000 is your interval (in this case 10 seconds)
}
}
};
//runnable must be execute once
handler.post(photoRunnable);
Remember to manage the lifecycle of handler
I'm creating an app that will also use NFC to read specific tags. I have a parent activity class where I would like to put function like:
public String scanTagId(){...}
I'm able to get actually tagID from tag the problem is it only occurs onNewIntent so actually first it will finish scanTagId() function and then invoke onNewIntent actually. So the question is how to write scanTagId() to actually wait for reading Tag ID from NFC tag and return string with this tag ID.
Maybe I need to approach this somehow differently or it's not possible - but right now I have a headache from trying to solve this :)
Normally NFC is handled via onNewIntentas you already said. It works like this: everytime a new NFC-Tag (that matches your filters) is detected by the phone the TAG gets connected and your app gets a reference to the TAG via the onNewIntent. Therefore you don't need an extra function scanTagId() since the device is already scaning for TAGs all the time.
If you want to disable that your app gets notified you can do it like this:
if (mNfcAdapter != null) {
mNfcAdapter.disableForegroundDispatch(this);
}
If you want to (re-)enable the notification about new TAG via onNewIntent you can use this code:
if (mNfcAdapter != null) {
mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, mFilters, mTechLists);
}
If you still have to have a function like you mentioned, I'd store the TAG-Id in an instance-variable and implement the function like this:
protected String mLastTagId = "";
protected synchronized void setLastTagId(String id) {
mLastTagId = id;
}
public synchronized String scanTagId(){
return mLastTagId;
}
Please notice, that this function will not wait for a TAG to be connected, but will just return the ID of the last TAG that was found in the past.
Update
Another approach would be to synchronize onNewIntent and your scanTagId-function with wait() and notifyAll(). I assume you want to invoke your function from main-thread. In combination with synchronization this is a very dangerous thing to do and therefore I strictly advice against it. It will put your main-thread to sleep which is going to cause android to notify the user ("App is not responding") or even quit your app. At least your app won't be responding to UI-events.
You could avoid these effects if you'd use an AsyncTask. But I'd really advice to rethink your design and prepare it for async-events.
What are you trying to achieve in first place?
Update2
If you want to quit your Activity after a specific time has elapsed without a TAG being found, you can use a Timer:
protected String tag = null;
protected Timer timer = new Timer();
And in your onCreate-method activate the timer:
timer.schedule(new TimerTask() {
public void run() {
AlertDialog.Builder b = new AlertDialog.Builder(MyActivity.this);
b.setTitle("Timeout").setMessage("Nothing found");
b.setPositiveButton("OK", new OnClickListener() {
MyActivity.finish();
});
b.setCancelable(false);
b.create().show();
}, 10000);
This code hasn't been tested.
I am developing an application that uses a third party tts, named flite. I am doing something like as the tts speaks a sentence. I want to highlight each word as it is spoken. For this, I have managed to get the word-level callbacks from the tts.
the workflow is like this--"speak text" button pressed.It starts the tt
s service and then it sends the text to the flite tts which is in C language and has been combined with the app.
Now, from C code, after every word I make two callbacks to two different java activities:
one to the tts service to speak the word
second to my test java activity to highlight the word.
I am successfully getting the word-level callbacks in my test activity but after that I am not able to do any UI work.
Following is the code that I execute when I get the callback:
this is the function that gets called from the C code.
private void WordCallback(int isword) {// from
// callback
if (isword == -1) {
Log.d(LOG_TAG, "its not a word");
} else if (isword == -2) {
Log.d(LOG_TAG, "yeah..its the end");
} else {
Log.d(LOG_TAG, "its word no " + isword);
int word = isword;
Log.d(LOG_TAG, "highlightwords");
highlightwords(isword);
if (isword == 4) {
Log.d(LOG_TAG, "in if");
new Thread(new Runnable() {
#Override
public void run() {
Log.d(LOG_TAG, "thread started");
try {
Flitetest.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Log.d(LOG_TAG, "run on ui");
textview.setText("#" + isword);
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
}
FliteTest is the name of the activity.
the Log prints till "Thread started" but the code inside runonuithread() is never executed and there is no error also.
Also, If write textview.settext("something") without the thread and runonuithread(), it gives the error:
fatal signal 11(sigsegv) at 0x6fc64e87(code=1), thread 20292(SynthThread).
What is the reason for that behaviour?
On Android ICS (4.0+), if you have android:anyDensity=false in your AndroidManifest.xml, AND you have forced GPU rendering enabled on your ICS phone. This is a problem for native Android apps as well.
Your options are to either not use the android:anyDensity=false options, or to disable forced GPU rendering on the phone. Since you can't really control the latter on other people's phones, the former seems like the best solution. Remember to use the 'dp' suffix on all your dimensions then.
I am trying to prevent my application calling the same method twice in the event of a double-click, or if the user presses different buttons quickly, almost at the same time.
I have clickable Views, acting as buttons, that call the same method but passing different parameters. This is the call:
startTheSearch(context, getState(), what, where);
Inside this method I'm creating a new Thread, because it queries a web server for the result:
new Thread(new Runnable() {
public void run() {
progDiag = ProgressDialog.show(ctx, null, "Searching", true);
getServerXML(context, what, where, searchIsCustom, mOffset);
handler.sendEmptyMessage(0);
}
}).start();
The problem is that upon two quick clicks, the method is fired twice, two threads are created, and consequently two new activities are created. That makes my app crash.
When the methods are done, and we have the result from the server, we call the handler:
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
try {
Intent i = new Intent(Golf.this, Result.class);
Bundle b = new Bundle();
b.putString("what", mWhat);
b.putString("where", mWhere);
b.putInt("offset", mOffset);
b.putBoolean("searchIsCustom", searchIsCustom);
i.putExtras(b);
startActivityForResult(i, Activity.RESULT_OK);
progDiag.dismiss();
} catch (Exception e) {
Alerts.generalDialogAlert("Error", "settings", ctx);
}
}
};
I tried to have a global boolean variable called "blocked" initially set to false, creating a condition like:
if(!blocked){
blocked = true;
new Thread(new Runnable() {
public void run() {
But this only seems to work on slower phones like the G1, I tried on Nexus and before it set blocked = true, the second request has was granted. So is there any way I can block the method being called if it's already running, or if the thread has started so it wont create a new one?
In the book Hello Android the author Ed Burnette gives a very nice solution for this problem.
To leave your app snappy and responsive you should create a second thread to do the web request.
Instead of creating a new thread for every request you can use a SingleThreadExecutor. If you start a second thread you can check if you are waiting for the result of another thread and block until this thread is ready, or cancel the old thread and start a new one if you think that the user now wants to do some other thing.
You can find the source code from the book on this page. Look for the Translate folder inside the source. It is a nice example on how to react to user commands and how to prevent too many web requests because of a user touching a lot on the gui.
Instead of using the "blocked" Boolean, you might investigate using a mutex. They're designed for this kind of problem.
I tried on Nexus and before it set
blocked = true, the second request has
was granted
That is impossible. Android UIs are single-threaded. There is no way that two onClick() methods of OnClickListeners will be called at the same time.
I'm running an Wikitude application which shows the point if Interest
(POIs). When the application starts, I click a button to launch ARView
(AUgmented Reality) and there I could see the POI images superimposed
on the Live Camera images.
Now I want to change those images at frequent intervals.
I'm using :
// Need handler for callbacks to the UI thread
final Handler mHandler = new Handler();
// Create runnable for posting
final Runnable mUpdateResults = new Runnable() {
public void run() {
updateResultsInUi();
}
};
protected void startLongRunningOperation() {
// Fire off a thread to do some work
Thread t = new Thread() {
public void run() {
Pi.computePi(800).toString(); //Do something for a while
mHandler.post(mUpdateResults); //then update image
}
};
t.start();
}
But nothing is working. I'm sure I'm doing some mistake...
Thanking you all in advance.
When you say you are running a "Wikitude application", do you mean you are building an app using their publicly available on-device Android API (http://www.wikitude.org/developers)? If so, then dynamically changing the POI marker images is not supported. The AR view is an activity within the Wikitude app itself, launched via your intent. You have no further POI control (apart from callback intents) after the camera view is launched.
We can add our customized icons for a Point of Interest. Have you gone through the sample code provided by Wikitude?. There you can find a method startARViewWithIcons(). Just go through it once, Let me know if there is anything else.... Thanks & Regards, Raghavendra K