I would like to use the same button to start and stop playing some sounds with a for loop inside function play().
I thought to use lock variable to do this, but button after click remains pressed till the function play end is execution.
Can you suggest some solution?
I have a situation like this:
public class MainActivity extends Activity {
private static SoundPool sound;
static int lock=1;
int s;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
sound=new SoundPool(20, AudioManager.STREAM_MUSIC, 100);
s=sound.load(this,R.raw.bipsound, 0);
Button button = (Button) findViewById(R.id.button);
}
public void onClick(View v) {
switch(lock) {
case 0:
lock=1;
break;
case 1:
lock=0;
play();
break;
}
}
public void play(){
for(int i=0;i<10;i++){
sound.play(s,1.0f, 1.0f, 1, 0, 1);
if(lock==1)
return;
try {Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
This is a problem try {Thread.sleep(1000); inside play(). You are telling the main Thread to sleep which is almost always a bad idea. The Button becomes pressed and remains in that state until the sleep() time has finished.
Remove that line. And I'm not sure what you are trying to accomplish there but you can run it in a separate Thread with things like TimerTask, use a handler or other such features. If you need more help then please explain what you are trying to do with that.
That's normal because you're using try {Thread.sleep(1000); and it stop the main thread during 1 seconde.
You've to use an AsyncTask to do that :)
Here's an example.
private void goToMainActivity() {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
Intent intent = new Intent(fa, Main.class);
startActivity(intent);
}
}.execute();
}
Related
I am trying to create a splash screen that should show a rotating image while the next activity is being loaded.
Therefore I have two activities. The problem is that the rotation does not start, unless I add Thread.sleep before the Intent is created.
This is the first activity, where the animation should run while the second one loads.
import com.silencedut.taskscheduler.Task;
import com.silencedut.taskscheduler.TaskScheduler;
public class LaunchActivity extends AppCompatActivity {
private Task<Intent> loader;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launcher);
loader = new LoadingTask();
TaskScheduler.execute(loader);
}
#Override
protected void onDestroy() {
super.onDestroy();
TaskScheduler.cancelTask(loader);
}
private class LoadingTask extends Task<Intent>
{
LoadingTask() {
ImageView imageLoader = findViewById(R.id.imageViewLoader);
RotateAnimation rotate = new RotateAnimation(
0,360, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF,0.5f);
rotate.setRepeatCount(Animation.INFINITE);
rotate.setRepeatMode(Animation.RESTART);
rotate.setDuration(5000);
rotate.setInterpolator(new LinearInterpolator());
imageNeedle.startAnimation(rotate);
}
#Override
public Intent doInBackground() {
DemoApplication app = (DemoApplication) getApplicationContext();
return new Intent(app, MainActivity.class);
return null;
}
#Override
public void onSuccess(Intent result) {
if (result != null) {
startActivity(result);
}
finish();
}
#Override
public void onFail(Throwable throwable) {
super.onFail(throwable);
}
#Override
public void onCancel() {
super.onCancel();
}
}
}
This class uses the TaskScheduler library, and the Task class is based on Runnable.
Inside the second class I add a Thread.Sleep to make the loading last more time.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try { Thread.sleep(5000); }
catch (InterruptedException ex) { android.util.Log.d("Exception", ex.toString()); }
...
}
...
}
My problem is that during these 5 seconds while MainActivity is loading, the animated image does not show or rotate. If I copy the same Thread.sleep block inside doInBackground (LoadingTask), then I can see the animation:
#Override
public Intent doInBackground() {
DemoApplication app = (DemoApplication) getApplicationContext();
// this makes the animation run
try { Thread.sleep(5000); }
catch (InterruptedException ex) { android.util.Log.d("Exception", ex.toString()); }
return new Intent(app, MainActivity.class);
return null;
}
So, how do I make it that the animation runs without using an unnecessary Thread.sleep inside doInBackground? I understand that if the second activity loads quickly, the animation won't show, but it doesn't work even when making it take more time.
You can do this Broadcast Receiver.
You don't need to use thread.
Simply start both the activity simultaneously.
In Splash Activity, register for broadcast reciver.and is Second activity send broadcast when all the data loaded. And then finish your splash activity.
If you didn't understand then I can give you an example.
Let me know.
I'm having some trouble with an AsyncTask subclass.
I have a main activity as below that displays a button and a number that counts up on the screen. Clicking the button launches an Edit activity where a number can be entered.
The number displayed on the Main activity should update with the timer which it does but the trouble I'm having is that I can't stop the timer. It should stop when entering the Edit activity and returning from it as well, as well as restart with the a new value too but it doesn't, the timer is always running with the first entered value, it never stops, even when I leave the program and return to the home screen.
I've looked at posts here such as Can't cancel Async task in android but they all just mention checking for isCancelled() which I'm doing. Can anyone see/explain why I can't stop this AsyncTask ?
public class MainActivity extends Activity {
#Override
UpdateTimer ut;
TextView tvn;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public void onResume() {
super.onResume();
tvn = (TextView) findViewById(R.id.numDisplay);
if(ut != null )//&& ut.getStatus() == AsyncTask.Status.RUNNING) {
ut.cancel(true);
ut.cancelled = true;
Log.d("-----M_r","called cancel: "+ut.isCancelled()+" "+cancelled);
}
if (updateRequired) {
ut = new UpdateTimer();
ut.execute(number);
updateRequired = false;
}
}
public void onEditButtonPressed(View caller) {
// kill any running timer
if(ut != null )
{
ut.cancel(true);
ut.cancelled = true;
}
// start the edit screen
Intent e_intent = new Intent(this, EditActivity.class);
startActivity(e_intent);
}
private void updateScreen(long number) {
// update screen with current values
tvn.setText("" + number);
}
private class UpdateTimer extends AsyncTask<Long, Long, Integer> {
long number;
public boolean cancelled;
#Override
protected Integer doInBackground(Long... params) {
number = params[0];
cancelled = false;
while(true) {
number += 1;
//sleep for 1 second
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// tell this AsyncTask to update the time on screen
publishProgress(number);
// check if timer needs to stop
if (isCancelled()) break;
if(cancelled) break;
}
return null;
}
protected void onProgressUpdate(Long... progress) {
Log.d("-----M_ut","updated: "+number+" "+this.isCancelled()+" "+cancelled);
updateScreen(progress[0]);
}
protected void onCancelled(Integer result) {
cancelled = true;
Log.d("-----M_ut","-- cancelled called: "+this.isCancelled());
}
}
protected void onStop()
{
super.onStop();
// kill any running timer
if(ut != null) {
ut.cancel(true);
}
}
}
Try this...
remove the variable..cancelled and change to this..
#Override
protected void onCancelled() {
super.onCancelled();
}
call the super.onCancelled instead..
And in the doInBackground check
if (isCancelled()) {
break;
}
Try calling from your activity ut.cancel(true);
Hope it works:)
private YourAsyncTask ut;
declare your asyncTask in your activity.
ut = new YourAsyncTask().execute();
instantiate it like this.
ut.cancel(true);
kill/cancel it like this.
I'm having some problems displaying a ProgressDialog. I have a method that scrapes information from a website, and I want to show the user some kind of "Loading" window instead of the app just looking like it is hanging for a second or two when it is working.
Everything works fine when I don't implement a ProgressDialog & Thread, but as soon as I try to implement a Thread to do the heavy lifting, the AboutMe View window is empty.
I have a MainActivity with a TextView that registers a OnClickListener.
A Click on the TextView does a:
startActivity(new Intent(getBaseContext(), AboutMe.class));
This is most of the AboutMe.class Activity:
public class AboutMe extends Activity {
private ProgressDialog aboutMeProgressDialog;
private String htmlAboutMe = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
getAboutMe(); // Get information from Internet
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFeatureDrawableResource(Window.FEATURE_NO_TITLE, android.R.drawable.ic_dialog_alert);
setContentView(R.layout.abutme);
TextView tvAbout = (TextView) findViewById(R.id.aboutMe);
tvAbout.setText(Html.fromHtml(htmlAboutMe));
}
private void getAboutMe() {
try {
aboutMeProgressDialog = ProgressDialog.show(AboutMe.this, "", "Loading");
new Thread() {
#Override
public void run() {
try {
/** Code to scape webpage **/
}
catch (Exception exp) {
exp.printStackTrace();
}
handler.sendEmptyMessage(0);
}
}.start();
}
catch (Exception ex) {
ex.printStackTrace();
}
}
private final Handler handler = new Handler() {
#Override
public void handleMessage(final Message msg) {
aboutMeProgressDialog.dismiss();
}
};
I'm clearly missing out on something trivial, but I've tried to Google just about everything I can think of, but still can't get a Thread together with ProgressDialog to work for me.
please use run on ui thread method
instead of handler.sendEmptyMessage(0); use this code and remove handle message
runOnUiThread(new Runnable() {
#Override
public void run() {
aboutMeProgressDialog.dismiss();
}
});
dude let me know if this was successful,it works most of times
please call getAboutMe() method after calling super.onCreate(savedInstanceState);
in my app in android, i need change background image in image view on 10 seconds once. so that i call a Async Task within a run method. when I execute the app it crashes.
It gives the Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() Exception to me.
I know I have to use Thread, but I do not know how to do so properly. Please help me.
This is my code sample:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
.................
new Thread()
{
public void run()
{
while(true){
try
{
Thread.sleep(5000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
count = count + 1;
new ImageChange().execute();
}
}
}.start();
} // OnCreate End
class ImageChange extends AsyncTask<Void, Void, Void>
{
protected void onPreExecute() {
}
protected void onPostExecute(Void unused) {
iv1.setImageBitmap(b1);
iv2.setImageBitmap(b2);
}
protected Void doInBackground(Void... arg0) {
switch(count){
case 1:
b1 = BitmapFactory.decodeFile(f1.getAbsolutePath());
b2 = BitmapFactory.decodeFile(f2.getAbsolutePath());
break;
case 2:
b1 = BitmapFactory.decodeFile(f2.getAbsolutePath());
b2 = BitmapFactory.decodeFile(f1.getAbsolutePath());
break;
default :
count = 0;
b1 = BitmapFactory.decodeFile(f1.getAbsolutePath());
b2 = BitmapFactory.decodeFile(f2.getAbsolutePath());
break;
}
return null;
}
}
You're calling the AsyncTask from a worker Thread. This way it has no access to the UI thread. You probably should consider using a Handler.
Probably, the problem is that you must execute the ImageChange.doInBackground() method in the UI thread. Try to change your code like this:
class ImageChange extends AsyncTask<Void, Void, Void> {
Activity act;
public ImageChange(Activity act) {
this.act = act;
}
protected void onPostExecute(Void unused) {
iv1.setImageBitmap(b1);
iv2.setImageBitmap(b2);
}
protected Void doInBackground(Void... arg0) {
switch(count) {
case 1:
helperMethod(f1.getAbsolutePath(), f2.getAbsolutePath());
break;
case 2:
helperMethod(f2.getAbsolutePath(), f1.getAbsolutePath());
break;
default :
count = 0;
helperMethod(f1.getAbsolutePath(), f2.getAbsolutePath());
break;
}
return null;
}
private void helperMethod(String a, String b) {
act.runOnUIThread(new Runable() {
public void run() {
b1 = BitmapFactory.decodeFile(a);
b2 = BitmapFactory.decodeFile(b);
}
});
}
}
Note that you must pass an Activity to the ImageChange class constructor. It means that you have to call the asyncTask in this way:
new ImageChange(this).execute();
Also consider the possibility of using the class TimerTask
EDIT: Change the Activity part of your code with this:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
.................
new ImageChange().execute();
} // OnCreate End
And add the while(true) to the ImageChange class:
protected Void doInBackground(Void... arg0) {
while(true) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count = count + 1;
switch(count) {
...
}
}
return null;
}
EDIT2: You can solve the problem about onPostExecute inserting the code that must be execute after each iteration inside the while loop:
protected Void doInBackground(Void... arg0) {
while(true) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count = count + 1;
switch(count) {
...
}
act.runOnUIThread(new Runnable() {
public void run() {
iv1.setImageBitmap(b1);
iv2.setImageBitmap(b2);
}
});
}
return null;
}
The code you insert inside the while loop must run in the UI thread; in fact, every onPostExecute method of the AsyncTask class runs on UI thread.
i solved the problem by using Handler Thread.
All i want to do is display a text for 1000 milliseconds and get the next thing.. dialogs are slow to pop up so i used a textview..but its not working.. the code snippet is given..
What am I doing wrong?
Thread sleep_for_sometime = new Thread() {
public void run() {
try {
correct.setVisibility(TextView.VISIBLE);
sleep(1000);
correct.setVisibility(TextView.INVISIBLE);
} catch (InterruptedException e) {
e.printStackTrace();
}
finally {
get_question(questionset[i]);
}
}
};
//sleep_for_sometime.setDaemon(false);
sleep_for_sometime.start();
You should change visibility in UI thread. Read painless threading
AsyncTask is great, but overused in some ways I think. Just use post/postDelayed. You're not really doing background work, you just want to delay some UI-thread work. Definitely read Nikita's link, but I would do something like:
correct.setVisibility(View.VISIBLE);
correct.postDelayed(new Runnable() {
correct.setVisibility(View.INVISIBLE);
get_question(questionset[i]);
}, 1000);
Expanding Nikita's Answer , you could do something like this
private class SleepTask extends AsyncTask<Void,Integer,Void> {
#Override
protected Void doInBackground(Void... params) {
try {
publishProgress(0);
sleep(1000);
publishProgress(1);
}catch(Exception e){
//null
}
}
#Override
protected void onProgressUpdate(Integer... i){
if(i[0]==0){
correct.setVisibility(TextView.VISIBLE);
}else{
correct.setVisibility(TextView.INVISIBLE);
}
}
#Override
protected void onPostExecute(Void res) {
get_question(questionset[i]);
}
#Override
protected void onPreExecute() {
//do something before execution
}
}
to start the thread , do this
new SleepTask().execute();