I need to fire an event when a user holds down a button, and fire another event, when the user releases it in my app. The events are short Asyc Tasks, which run in background.
The problem is, I know how to make this happen with the OnTouchListener(), but it seems like when you hold down the button, it runs an infinite loop on the onTouch() method, stopping when the user releases it. Although since my Tasks are launched only once, It runs over and over empty, doing nothing.
I'm not sure if there is any other way possible to achieve this, which fires my back events and stops with the loop. It would be beneficial, as a lot of resources in the form of side threads are already being consumed, and I would like to save some useless running of a method. Here is my implementation, if something is wrong with it:
private OnTouchListener down = new OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
// TODO Auto-generated method stub
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
//Async Task
} else if (action == MotionEvent.ACTION_UP) {
//Async Task
}
return false;
}
};
In my app I am using TTS. I have 20 different activities which are changed when the user swipe left or right. According the activity, a text is spoken. I am executing tts with separate thread and activity selection is done with main thread. But the problem is very slow, the UI feels slugish. When I swipe left or right, once tts is finished speaking the text, the activity changes which shouldn't happen because I am using separate thread for tts.
Here is the codE:
TTS class:
public class textToSpeech {
TextToSpeech tts=null;
public textToSpeech(Context con)
{
tts = new TextToSpeech(con,new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if(status != TextToSpeech.ERROR) // initialization me error to nae ha
{
tts.setPitch(1.1f); // saw from internet
tts.setSpeechRate(0.4f); // f denotes float, it actually type casts 0.5 to float
tts.setLanguage(Locale.US);
}
}
});
}
public void SpeakText (String text)
{
tts.speak(text, TextToSpeech.QUEUE_FLUSH, null); // TextToSpeech.QUEUE_FLUSH forces the app to stop all the sounds that are currently playing before speaking this text
}
public void stopSpeak()
{
tts.stop();
}
Gesture Reader Class: (separate class)
public void decideAlphabet()
{
tts.stopSpeak();
threadForTTS.start();
switch (i)
{
case 0:
activities=null;
activities = new Intent(contxt,A.class);
contxt.startActivity(activities);
break;
case 1:
activities=null;
activities = new Intent(contxt,B.class);
contxt.startActivity(activities);
break;
....... 20 more case statements for selecting activities
}
decideActivity() method is called when it is checked, which swipe was made, swipe to right or left.
NOTE:
Before adding tts in this app, the UI was performing properly without lag or slowness. After I added TTS, the app became slow. How can I solve this problem
Regards
I had the same problem and was about to comment on seeing the following logcat error ...skipped x many frames. The application may be doing too much work on its main thread.
Of course I was sure TTS was being called from another thread which I checked using Thread.currentThread().getName() But it turns out however that OnInit was indeed still running on the main thread and it looks like setting the language is an expensive operation. A quick change to run contents of onInit in a new thread and the UI freezing/choreographer complaining stopped:
#Override
public void onInit(int status) {
new Thread(new Runnable() {
public void run() {
if(status != TextToSpeech.ERROR) // initialization me error to nae ha
{
tts.setPitch(1.1f); // saw from internet
tts.setSpeechRate(0.4f); // f denotes float, it actually type casts 0.5 to float
tts.setLanguage(Locale.US);
}
}
}
}).start()
I'm trying to get music to play on my app but I've hit a problem which I can't figure out. When I first load the program, it works fine and the music loads and plays. If I let the phone idle and then come back to it, the app works again. But the third time I let it idle and return, the mediaplayer will return a null and crash the app on resuming. Here is the code for the mediaplayer:
public void startMusic(Context context)
{
if (music != null){
if (music.isPlaying()){
music.stop();
}
music.release();
music = null;
}
music = MediaPlayer.create(context, R.raw.song);
music.setLooping(true);
musicPlaying = true;
}
The app will crash when it hits the music.setLooping(true); line of code, saying that music is null.
Any ideas?
It turns out I was releasing the music in the wrong place. I was doing it in the view, when I should have been doing it in the activity.
i want to if the user press home button my service will be stop , this is my code but it's not working for me, please help me:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_HOME) {
stopService(new Intent(this, MyService.class));
return true;
}
return super.onKeyDown(keyCode, event);
}
Thanks
If you're trying to make sure the service only runs when the related activity is visible, a better solution would be to stop the service in the onPause() method of whatever activity the user is running. That way, the event is handled when the user presses "back" and when the user presses "home".
Likewise, you can bind your service to the activity (or activities). The bound service will be destroyed when all activities bound to it stop.
public static final int KEYCODE_HOME
This key is handled by the
framework and is never delivered to applications.
Source
Make a root activity and add this,
#Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
// Get called every-time when application went to background.
System.exit(0);
}
}
extend each activity with rootActivity, it will shutdown service on home/menu button press
On pressing the back button, I'd like my application to go into the stopped state, rather than the destroyed state.
In the Android docs it states:
...not all activities have the behavior that they are destroyed when BACK is pressed. When the user starts playing music in the Music application and then presses BACK, the application overrides the normal back behavior, preventing the player activity from being destroyed, and continues playing music, even though its activity is no longer visible
How do I replicate this functionality in my own application?
I think there must be three possibilities...
Capture the back button press (as below) and then call whatever method(s) the home button calls.
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK)) {
Log.d(this.getClass().getName(), "back button pressed");
}
return super.onKeyDown(keyCode, event);
}
Capture the back button press and then spoof a home button press.
Capture the back button press, then start an Activity of the home screen, effectively putting my application's Activity into the stopped state.
Edit:
I know about services and am using one in the application to which this problem is related. This question is specifically about putting the Activity into the stopped state rather than the destroyed state on pressing the back button.
Most of the time you need to create a Service to perform something in the background, and your visible Activity simply controls this Service. (I'm sure the Music player works in the same way, so the example in the docs seems a bit misleading.) If that's the case, then your Activity can finish as usual and the Service will still be running.
A simpler approach is to capture the Back button press and call moveTaskToBack(true) as follows:
// 2.0 and above
#Override
public void onBackPressed() {
moveTaskToBack(true);
}
// Before 2.0
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
moveTaskToBack(true);
return true;
}
return super.onKeyDown(keyCode, event);
}
I think the preferred option should be for an Activity to finish normally and be able to recreate itself e.g. reading the current state from a Service if needed. But moveTaskToBack can be used as a quick alternative on occasion.
NOTE: as pointed out by Dave below Android 2.0 introduced a new onBackPressed method, and these recommendations on how to handle the Back button.
Use the following code:
public void onBackPressed() {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
}
If you want to catch the Back Button have a look at this post on the Android Developer Blog. It covers the easier way to do this in Android 2.0 and the best way to do this for an application that runs on 1.x and 2.0.
However, if your Activity is Stopped it still may be killed depending on memory availability on the device. If you want a process to run with no UI you should create a Service. The documentation says the following about Services:
A service doesn't have a visual user interface, but rather runs in the background for an indefinite period of time. For example, a service might play background music as the user attends to other matters, or it might fetch data over the network or calculate something and provide the result to activities that need it.
These seems appropriate for your requirements.
try to override void onBackPressed() defined in android.app.Activity class.
if it helps someone else, I had an activity with 2 layouts that I toggled on and off for visibilty, trying to emulate a kind of page1 > page2 structure. if they were on page 2 and pressed the back button I wanted them to go back to page 1, if they pressed the back button on page 1 it should still work as normal. Its pretty basic but it works
#Override
public void onBackPressed() {
// check if page 2 is open
RelativeLayout page2layout = (RelativeLayout)findViewById(R.id.page2layout);
if(page2layout.getVisibility() == View.VISIBLE){
togglePageLayout(); // my method to toggle the views
return;
}else{
super.onBackPressed(); // allows standard use of backbutton for page 1
}
}
hope it helps someone,
cheers
Working example..
Make sure don't call super.onBackPressed();
#Override
public void onBackPressed() {
Log.d("CDA", "onBackPressed Called");
Intent setIntent = new Intent(Intent.ACTION_MAIN);
setIntent.addCategory(Intent.CATEGORY_HOME);
setIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(setIntent);
}
In this way your Back Button act like Home button . It doesn't finishes your activity but take it to background
Second way is to call moveTaskToBack(true); in onBackPressed and be sure to remove super.onBackPressed
Even better, how about OnPause():
Called as part of the activity lifecycle when an activity is going into the background, but has not (yet) been killed. The counterpart to onResume().
When activity B is launched in front of activity A, this callback will be invoked on A. B will not be created until A's onPause() returns, so be sure toenter code here not do anything lengthy here.
This callback is mostly used for saving any persistent state the activity is editing and making sure nothing is lost if there are not enough resources to start the new activity without first killing this one.
This is also a good place to do things like stop animations and other things that consume a noticeable amount of CPU in order to make the switch to the next activity as fast as possible, or to close resources that are exclusive access such as the camera.
Override onBackPressed() after android 2.0.
Such as
#Override
public void onBackPressed() {
moveTaskToBack(true);
}
I have use #Mirko N. answser using made the new Custom EditText
public class EditViewCustom extends EditText {
Button cancelBtn;
RelativeLayout titleReleLayout;
public EditViewCustom(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public EditViewCustom(Context context, AttributeSet attrs) {
super(context, attrs);
}
public EditViewCustom(Context context) {
super(context);
}
public void setViews(Button cancelBtn,RelativeLayout titleReleLayout){
this.cancelBtn = cancelBtn;
this.titleReleLayout = titleReleLayout;
}
#Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
Log.d("KEYCODE_BACK","KEYCODE_BACK");
cancelBtn.setVisibility(View.GONE);
this.setFocusableInTouchMode(false);
this.setFocusable(false);
titleReleLayout.setVisibility(View.VISIBLE);
return super.onKeyPreIme(keyCode, event);
}
return super.onKeyPreIme(keyCode, event);
}
}
Then set data from your activity
searchEditView.setViews(cancelBtn, titleRelativeLayout);
Thank you.
I've tried all the above solutions, but none of them worked for me. The following code helped me, when trying to return to MainActivity in a way that onCreate gets called:
Intent.FLAG_ACTIVITY_CLEAR_TOP is the key.
#Override
public void onBackPressed() {
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}