I'm fairly new to Android programming.
Simple Explanation for my problem:
I have an async task to collect JSON based data after every 20 seconds based on this runnable:
Handler handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
mTask = new JSONParse();
mTask.execute();
handler.postDelayed(this, 20000);
}
};
How do I stop it when I want to?
Detailed Explanation for my Problem:
Within this Async Task, I check if the data is available, and if not available, I go back to the mainscreen by first invoking
mTask.cancel(true);
and then in the onCancelled() method as follows:
protected void onCancelled() {
// TODO Auto-generated method stub
super.onCancelled();
mTask.cancel(false);
pDialog.dismiss();
displayWrongPhoneToast();
}
where displayWrongPhoneToast() is a simple function as follows:
public void displayWrongPhoneToast() {
Toast.makeText(getApplicationContext(),
"Sorry! Enter at least one field to continue.",
Toast.LENGTH_SHORT).show();
Intent intent = new Intent(TabActivity.this, MainActivity.class);
startActivity(intent);
}
The problem I have is, the handler is causing the runnable to execute in the background, which is making the application request data over and over again and causing the displayWrongPhoneToast() to execute over and over again.
I tried some methods I found online to stop the runnable, but it refuses to. Any help is appreciated. Thanks :)
You have to call
handler.removeCallbacks(r).
Related
So i am new to android and java, and i understand that i should move between activities with intents.
Intent randomintent = new Intent(profile.this, loggedactivity.class);
randomintent .putString("name", namestring);
startActivity(randomintent);
The thing is, that i also have a function that i want it to be executed just before this intent takes the user to another activity. So my code looks something like this.
btnUpload.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
uploadImage();
//this uploads the image, it works without the intent i added
infosendstuff();
//this should be executed after the image is uploaded and stores the image link to a database (also works)
Intent randomintent = new Intent(profile.this, loggedactivity.class);
randomintent .putString("name", namestring);
startActivity(randomintent);
}
});
The problem seems to be the intent, when used, it ignores the other two functions above it, that upload the picture and store the link for that picture.
The goal is to upload the picture, once done, get the link, send the link to another activity though the intent (with the bundle) and thats about it.
it's better to use AsynkTask.
create a class, it should extend from AsynkTask. in doInBackground, upload your photos, process the response and send the link. and in onPostExecute method, go to the other activity.
update 1
class myClass extends AsyncTask<Void,Void,Void>{
#Override
protected Void doInBackground(Void... params) {
String result = uploadPhotos();
proccess result;
send links;
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
Intent randomintent = new Intent(profile.this, loggedactivity.class);
randomintent .putString("name", namestring);
startActivity(randomintent);
}
}
now you can use it like this:
new myClass().execute();
but before coding, i think you need to study more about web Connection process in android.
It seems that uploadImage() Method does some stuff on the network and since the network request and response is done in another thread the code continue to execute and loggedactivity will show before the uploadImage() method is done.
So one way is that you force main thread to wait for network thread and after the network thread is done main thread continue to work but it cause the UI thread to freeze.
another way is that you should use callbacks that when the uploadImage() method is done some method will invoke and in that method you start your new activity. something like code below :
uploadImage(new ResponeListener() {
#override
public void onDataReady(String nameString) {
Intent randomintent = new Intent(profile.this,loggedactivity.class);
Bundle b = new Bundle();
b.putString("name", namestring);
startActivity(randomintent);
}
}
I am trying to call my takepicture() method after every 1 minute. So, I tried using the handler class and then tried calling my method within its run function. However, when I tried doing a step wise debugging, it never enters the run method at all. Can anyone please suggest me what I am doing wrong? I am trying to call it from my fragment.
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mFile = new File(getActivity().getExternalFilesDir(null), "pic.jpg");
final Handler handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
Log.d("HandlerThread","This is from the HandlerThread");
takePicture();
handler.postDelayed(this, 60000);
}
};
}
Try this:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mFile = new File(getActivity().getExternalFilesDir(null), "pic.jpg");
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
Log.d("HandlerThread","This is from the HandlerThread");
takePicture();
}
}, 60000);
}
Rather than defining the handler.postDelayed within run method.I have just changed the call within your main thread itself.
Kindly mark it as answer if it solves your problem.
You never call any method that would run the Runnable. You only specified its behavior inside the run() function.
In order to start the Runnable, call something like handler.postDelayed(r, 0);
Just an info: please note that your Handler is still tied to the main Thread. See this answer and this one if you want to run it on a separate thread.
You should make an initial call to start the handler functionality.
ie , handler.post(r);
I've a following problem. I have MediaPlayer and I use Handler to send messages about MediaPlayer's progress during it plays. And I want to be able change Handler's callback in runtime. When i change the playing file in MediaPlayer i use the following code:
player.setDataSource(filename);
player.prepare();
final int duration = player.getDuration();
player.start();
// removing previous callback
durationHandler.removeCallbacksAndMessages(null);
// setting new callback
durationHandler.postDelayed(
new Runnable() {
#Override
public void run() {
int progress = player.getCurrentPosition();
demonstrator.setProgress(progress, duration);
durationHandler.postDelayed(this, REPEAT_TIME);
}
}, 400);
I expect the old callback will be replaced by new one. But it doesn't work! Both of callbacks are running! Why? And how can i avoid it?
I'm trying to build an Android app which will repeatedly run some process every 10 mins.
As I found out Handlers are more reliable than timers or scheduling. So I'm going to develop my app using the Handlers using the given below codes.
I'm little bit concerned that the below codes will create separate Handlers at each time I start the app and keep them running parallel, may be since I'm creating the Handler on onCreate.
So what is the best way to keep only a single Handler runs in background at a time?
private Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new Handler(); // new handler
handler.postDelayed(runnable, 1000*60*10); // 10 mins int.
setContentView(R.layout.activity_pro__sms);
}
private Runnable runnable = new Runnable() {
#Override
public void run() {
/* my set of codes for repeated work */
foobar();
handler.postDelayed(this, 1000*60*10); // reschedule the handler
}
};
You can extend Application class and do your work in it.
public class App extends Application {
private Handler handler;
#Override
protected void onCreate() {
super.onCreate();
handler = new Handler(); // new handler
handler.postDelayed(runnable, 1000*60*10); // 10 mins int.
setContentView(R.layout.activity_pro__sms);
}
private Runnable runnable = new Runnable() {
#Override
public void run() {
/* my set of codes for repeated work */
foobar();
handler.postDelayed(this, 1000*60*10); // reschedule the handler
}
};
}
And declare your class in manifest:
<application android:name=".App">
Edited
But it will work only if your app is running, otherwise you can use AlarmManager.
I decided to answer my own question since I've found out how to do it right way. The Android way. First of all what I was trying to do and posted in the question is a wrong approach to my requirement. Now I'm posting this so someone else will not do it wrong way but the following way.
Android has few options for timing.
Timer-task -> runs while application is alive. best for short term timing. Resource usage is higher.
Handler -> runs while application is alive. But not suitable to used as a scheduler. (this is what I've asked and it's not the correct way to do that). Handlers are the best way to do something repeatedly till the app is killed.
Alarm-manager -> The best way to schedule something to happen in future even if the app is killed. (this is what I should apply for my app).
This is what I figured out. Correct me if I'm wrong.
first define an utility class
public abstract class HandlerPeriodRunnable implements Runnable {
private Handler periodHandler;
private int msPeriod;
public HandlerPeriodRunnable(Handler periodHandler, int msPeriod) {
this.periodHandler = periodHandler;
this.msPeriod = msPeriod;
}
#Override
public void run() {
periodRun();
if (msPeriod > 0) {
periodHandler.postDelayed(this, msPeriod);
}
}
abstract public void periodRun();
}
then use it
final Handler mUIHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mUIHandler.postDelayed(new HandlerPeriodRunnable(mUIHandler, 1000) {
#Override
public void periodRun() {
}
}, 2000);
}
I have followed this tutorial to launch a url on android through jni call. It runs successfully.
In the same way I want to display a toast message from my cocos2dx layer like this:
public static void openURL(String url) {
Toast.makeText(me,url,Toast.LENGTH_LONG).show();
}
But its crashing with error: Can't create handler with thread. Do you know how can I display it correctly?
Try below code this will definately work for you.
First Create one Runnable interface in your class file like this,
Runnable runnable = new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "Your url string...",Toast.LENGTH_SHORT).show();
}};
Then create one Handler object and call that runnable interface like below,
Create Handler object like,
Handler handler;
initialize it like,
onCreate(){
.................
handler = new Handler();
.................
}
then call runnable whenever you want like,
handler.post(runnable);
You can't run UI stuffs on a background thread.
You should use an AsyncTask and put that code in the on pre/post execute or if your just displaying a toast you can run it on the UI thread
runOnUiThread(new Runnable() {
}
So this was from 2012.
I guess not a lot people use cocos2d-x.
Ok this how you do this on cocos2d-x.
Edit the AppActivity.java
public class AppActivity extends Cocos2dxActivity
{
private Activity activity;
#Override
protected void onCreate(Bundle savedInstanceState)
{
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.activity = this;
showToast();
}
public void showToast()
{
activity.runOnUiThread(new Runnable()
{
#Override
public void run()
{
// TODO Auto-generated method stub
Toast.makeText(activity, "Hello :D", 10).show();
}
});
}
}
This works very nice in cocos2d-x version 3.x
I test it. Of course JNI just will call the method and this must work.