Handler hnd = new Handler() {
#Override
public void handleMessage(Message msg) {
int id = sequence.get(msg.arg1);
if(msg.arg1 % 2 == 0) {
sq.get(id-1).setBackgroundResource(R.drawable.square_show);
} else {
sq.get(id-1).setBackgroundResource(R.drawable.square);
}
}
};
#Override
public void onResume() {
super.onResume();
Thread background = new Thread(new Runnable() {
public void run() {
try {
for(int i = 0; i < sequence.size()-1; i++) {
record_tv.setText(""+i);
Thread.sleep(200);
Message msg = hnd.obtainMessage();
msg.arg1 = i;
msg.sendToTarget();
}
} catch(Throwable t) {
}
}
});
background.start();
}
[CODE UPDATED] now it goes through the first loop and stops
do you have any idea why the code in the first runOnUiThread gets executed but it doesn't do what i want?
what i want is: change the image to "square", wait 2 seconds, change the image to "square_show", wait 2 secs and repeat the loop
i've been struggling for an hour now...
You can easily set image using following code.
sq.get(id-1).setImageResource(R.drawable.square_show);
sq.get(id-1).setImageResource(R.drawable.square);
public void show(int size) {
// CICLE THROUGH EACH SQUARE
for(int i = 0; i <= size-1; i++) {
Thread thrd = new Thread() {
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
sq.get(id-1).setImageResource(R.drawable.square_show);
// System.out.println("1st..........");
try {
sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sq.get(id-1).setImageResource(R.drawable.square);
// System.out.println("2nd..........");
try {
sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
};
thrd.start();
}
}
This is a wrong way to achieve it. This may help you.
http://developer.android.com/guide/topics/graphics/2d-graphics.html#tween-animation
I would suggest you to use a handler
int drawablebkg[] ={R.drawable.ic_launcher,R.drawable.icon};
Handler m_handler;
Runnable m_handlerTask ;
ImageView iv;
iv = (ImageView)findViewById(R.id.imageView1);
m_handler = new Handler();
m_handlerTask = new Runnable()
{
#Override
public void run() {
iv.setImageResource(android.R.color.transparent);
if(i<2)
{
ivsetBackgroundResource(drawablebkg[i]);
i++;
}
else
{
i=0;
}
m_handler.postDelayed(m_handlerTask, 2000);
}
};
m_handlerTask.run();
In onPause() of your activity
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
//_t.cancel();
m_handler.removeCallbacks(m_handlerTask);
}
Another way
iv= (ImageView)findViewById(R.id.imageView1);
AnimationDrawable animation = new AnimationDrawable();
animation.addFrame(getResources().getDrawable(R.drawable.ic_launcher), 2000);
iv.setImageResource(android.R.color.transparent);
animation.addFrame(getResources().getDrawable(R.drawable.icon), 2000);
animation.setOneShot(false);
iv.setBackgroundDrawable(animation);
//set setBackgroundDrawable(animation) is decprecreated i guess. not sure in which api
// start the animation!
animation.start();
Another way
Define background.xml in drawable folder
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="#drawable/ic_launcher" android:duration="2000" />
<item android:drawable="#drawable/icon" android:duration="2000" />
</animation-list>
I your activity onCreate();
ImageView iv = (ImageView)findViewById(R.id.imageView1);
iv.setBackgroundResource(R.drawable.background);
AnimationDrawable animation= (AnimationDrawable)loadingRaven.getBackground();
loadingRaven.setImageResource(android.R.color.transparent);
animation.start();
Note to stop the animation you need to call animation.stop()
Because the resource changes in the UI thread and you are sleeping your background thread. The UI thread is running normally.
Use handlers:
public class MainActivity extends Activity {
Button b;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b = (Button) findViewById(R.id.button1);
}
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (msg.arg1 % 2 == 0) {
b.setBackgroundResource(R.drawable.analytic_icon);
} else {
b.setBackgroundResource(R.drawable.ic_launcher);
}
}
};
#Override
public void onResume() {
super.onResume();
Thread background = new Thread(new Runnable() {
public void run() {
try {
for (int i = 0; i < 20; i++) {
Thread.sleep(2000);
Message msg = handler.obtainMessage();
msg.arg1 = i;
msg.sendToTarget();
}
} catch (Throwable t) {
// just end the background thread
}
}
});
background.start();
}
}
Try this,It will work:
public void show(final int size) {
Thread thrd = new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i <= size - 1; i++) {
id = (Integer) sequence.get(i);
runOnUiThread(new Runnable() {
#Override
public void run() {
sq.get(id - 1).setBackgroundResource(
R.drawable.square_show);
}
});
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
sq.get(id - 1).setBackgroundResource(
R.drawable.square);
}
});
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thrd.start();
}
Related
In my application i have timer for some works.
When my application running after some time my application freeze and not work any View !
In this timer every 500ms i emit socket.io
My Codes:
AsyncTask.execute(new Runnable() {
#Override
public void run() {
socketPingTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
if (isSendSocketPing) {
checkSocketPingTimer += startSocketPingTimer;
if (checkSocketPingTimer == sendSocketPingTimer) {
currentTimerForSocket = System.currentTimeMillis();
try {
detailSocketUtils.getSendRTTforPing(currentTimerForSocket + "");
} catch (Exception e) {
}
}
//Show ping (from search)
Constants.currentActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
if (isShownPing) {
detailToolbar_ping.setVisibility(View.VISIBLE);
if (checkSocketPingTimer > 500) {
detailToolbar_ping.setText(checkSocketPingTimer + "");
detailToolbar_ping.setTextColor(Color.RED);
} else {
detailToolbar_ping.setText(checkSocketPingTimer + "");
detailToolbar_ping.setTextColor(Color.GREEN);
}
} else {
detailToolbar_ping.setVisibility(View.GONE);
}
}
});
socketPing = checkSocketPingTimer;
}
}
}, 500, startSocketPingTimer);
}
});
How can i run this timers in another thread and not freeze my app ?
It should be something similar to this code:
class MyActivity extends Activity
{
private void executeLoop()
{
Handler myHandler = new Handler()
{
public void handleMessage(Message msg)
{
if (isShownPing)
{
detailToolbar_ping.setVisibility(View.VISIBLE);
if (checkSocketPingTimer > 500) {
detailToolbar_ping.setText(checkSocketPingTimer + "");
detailToolbar_ping.setTextColor(Color.RED);
} else {
detailToolbar_ping.setText(checkSocketPingTimer + "");
detailToolbar_ping.setTextColor(Color.GREEN);
}
} else
{
detailToolbar_ping.setVisibility(View.GONE);
}
}
}
socketPingTimer.scheduleAtFixedRate(new TimerTask()
{
#Override
public void run()
{
if (isSendSocketPing)
{
checkSocketPingTimer += startSocketPingTimer;
if (checkSocketPingTimer == sendSocketPingTimer) {
currentTimerForSocket = System.currentTimeMillis();
try {
detailSocketUtils.getSendRTTforPing(currentTimerForSocket + "");
} catch (Exception e) {
}
}
myHandler.sendEmptyMessage();
socketPing = checkSocketPingTimer;
}
}
}, 500, startSocketPingTimer);
}
}
private void startTimerAtFixRate() {
android.os.Handler handler = new android.os.Handler();
Runnable updateTimerThread = new Runnable() {
public void run() {
//write here whatever you want to repeat
// Like I called Log statement
// After every 1 second this below statement will be executed
Log.e("CALLED-->", "TRUE");
handler.postDelayed(this, 1000);
}
};
handler.postDelayed(updateTimerThread, 100);
}
I want to toast (or show a dialog) when progressbar ends. I tried to do this with if in run() method, but it causes the following error:
Can't create handler inside thread that has not called Looper.prepare()
how can I do that?
This is my code:
#Override
public void run() {
int myProgress = 0, Speed = 50;
ProgressBar myProgressBar = (ProgressBar) findViewById(R.id.progressbar);
while (myProgress<750){
try{
Thread.sleep(Speed);
myProgress++;
if (myProgressBar != null) {
myProgressBar.setProgress(myProgress);
}
}
catch(Throwable t){ }
}
}
runOnUiThread(new Runnable() {
public void run() {
//your code here
}
});
Change like this.
runOnUiThread(new Runnable() {
public void run() {
int myProgress = 0, Speed = 50;
ProgressBar myProgressBar = (ProgressBar) findViewById(R.id.progressbar);
while (myProgress<750){
try{
Thread.sleep(Speed);
myProgress++;
if (myProgressBar != null) {
myProgressBar.setProgress(myProgress);
}
}
catch(Throwable t){ }
}
}
});
Worker threads are meant for doing background tasks and you can't show anything on UI within a worker thread unless you call method like runOnUiThread. If you try to show anything on UI thread without calling runOnUiThread, there will be a java.lang.RuntimeException.
Tell me if you still face any problem.
I tried this and it works now:
public void run() {
int myProgress = 0, Speed = 50;
ProgressBar myProgressBar = (ProgressBar) findViewById(R.id.progressbar);
while (myProgress<750){
try{
Thread.sleep(Speed);
myProgress++;
if (myProgressBar != null) {
myProgressBar.setProgress(myProgress);
}
}
catch(Throwable t){ }
}
final int finalMyProgress = myProgress;
runOnUiThread(new Runnable() {
#Override
public void run() {
if (finalMyProgress == 750)
Toast.makeText(word_guess2.this, "hi", Toast.LENGTH_SHORT).show();
}
});
}
I have some working code, which takes a few buttons and when they are pressed, plays some audio files. However, this code seems uncessearily large and I feel it could be reduced down into smaller methods that could be called. I have, however, taken enough time and effort just to get this working so I can't see how to reduce it. Can you provide a cleaner / smaller and more resuable way of calling audio tracks as this code will only get larger as I intend to have around 30 tracks.
audioBtn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mediaPlayer != null && mediaPlayer.isPlaying())
{
mProgressStatus = 0;
mediaPlayer.stop();
try {
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
progressBar1.setProgress(mProgressStatus);
mHandler.removeCallbacks(runnable1);
t.interrupt();
audioBtn2.setEnabled(true);
audioBtn3.setEnabled(true);
} else {
mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.song1);
mediaPlayer.start();
t = new Thread(runnable1);
t.start();
mProgressStatus = 0;
progressBar1.setProgress(mProgressStatus);
audioBtn2.setEnabled(false);
audioBtn3.setEnabled(false);
}
}
});
audioBtn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mediaPlayer != null && mediaPlayer.isPlaying())
{
mProgressStatus = 0;
mediaPlayer.stop();
try {
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
progressBar2.setProgress(mProgressStatus);
mHandler.removeCallbacks(runnable2);
t.interrupt();
audioBtn1.setEnabled(true);
audioBtn3.setEnabled(true);
} else {
mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.song2);
mediaPlayer.start();
t = new Thread(runnable2);
t.start();
mProgressStatus = 0;
progressBar2.setProgress(mProgressStatus);
audioBtn1.setEnabled(false);
audioBtn3.setEnabled(false);
}
}
});
audioBtn3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mediaPlayer != null && mediaPlayer.isPlaying())
{
mProgressStatus = 0;
mediaPlayer.stop();
try {
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
progressBar3.setProgress(mProgressStatus);
mHandler.removeCallbacks(runnable3);
t.interrupt();
audioBtn1.setEnabled(true);
audioBtn2.setEnabled(true);
} else {
mediaPlayer = MediaPlayer.create(getApplicationContext(), R.song3);
mediaPlayer.start();
t = new Thread(runnable3);
t.start();
mProgressStatus = 0;
progressBar3.setProgress(mProgressStatus);
audioBtn1.setEnabled(false);
audioBtn2.setEnabled(false);
}
}
});
}
private Runnable runnable1 = new Runnable() {
public void run() {
try {
while (mProgressStatus < 30) {
mProgressStatus++;
mHandler.post(new Runnable() {
public void run() {
progressBar1.setProgress(mProgressStatus);
}
});
Thread.sleep(1000);
}
} catch (InterruptedException e) {
mProgressStatus = 0;
mHandler.removeCallbacks(runnable1);
}
}
};
private Runnable runnable2 = new Runnable() {
public void run() {
try {
while (mProgressStatus < 30) {
mProgressStatus++;
mHandler.post(new Runnable() {
public void run() {
progressBar2.setProgress(mProgressStatus);
}
});
Thread.sleep(1000);
}
} catch (InterruptedException e) {
mProgressStatus = 0;
mHandler.removeCallbacks(runnable2);
}
}
};
private Runnable runnable3 = new Runnable() {
public void run() {
try {
while (mProgressStatus < 30) {
mProgressStatus++;
mHandler.post(new Runnable() {
public void run() {
progressBar3.setProgress(mProgressStatus);
}
});
Thread.sleep(1000);
}
} catch (InterruptedException e) {
mProgressStatus = 0;
mHandler.removeCallbacks(runnable3);
}
}
};
One thing I've already looked at is moving the setting of buttons to enabled/disabled to a separate class, but that involves creating more large un-resuable scripts to handle calling the main thread (As I need to reset the buttons in the runnable threads after songs have finished)
I'm also not sure if it's possible to pass element ids as arguments to functions, in which case that would help reduce the code.
You can reduce duplicate codes by defining an abstract OnClickListener class and delegate the responsibility of the "different" parts to whoever extends it. You can of course define this as an Inner Class to access the parameters of the current class. this is called Template method pattern
first define MyClickListener:
public abstract class MyClickListener extends View.OnClickListener {
#Override
public void onClick(View v) {
if(mediaPlayer != null && mediaPlayer.isPlaying())
{
mProgressStatus = 0;
mediaPlayer.stop();
try {
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
setProgress(mProgressStatus);
mHandler.removeCallbacks(runnable1);
t.interrupt();
enableButtons(true);
} else {
mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.song1);
mediaPlayer.start();
t = getThread();
t.start();
mProgressStatus = 0;
setProgress(mProgressStatus);
enableButtons(false);
}
}
public abstract void setProgress(int progress);
public abstract void enableButtons(boolean enable);
public abstract Thread getThread();
}
then use it like this:
audioBtn1.setOnClickListener(new MyClickListener(){
public abstract void setProgress(int progress){
progressBar1.setProgress(progress);
}
public abstract void enableButtons(boolean enable){
audioBtn2.setEnabled(enable);
audioBtn3.setEnabled(enable);
}
public abstract Thread getThread(){
return new Thread(runnable1);;
}
})
And so on for other buttons.
You can apply this pattern for the runnables too!
And how should i solve it ?
This is my button click method that i call it from inside onCreate:
public void addListenerOnButton()
{
btnClick = (Button) findViewById(R.id.checkipbutton);
btnClick.setOnClickListener(new OnClickListener()
{
byte[] response = null;
#Override
public void onClick(View arg0)
{
text = (TextView) findViewById(R.id.textView2);
Thread t = new Thread(new Runnable()
{
#Override
public void run()
{
for (int i = 0; i < ipaddresses.length; i++)
{
try
{
response = Get(ipaddresses[i]);
if (response == null)
{
text.setText("Connection Failed: " + generateRunnablePrinter(i));
}
}
catch (Exception e)
{
String err = e.toString();
}
if (response != null)
{
try
{
final String a = new String(response, "UTF-8");
text.post(new Runnable()
{
#Override
public void run()
{
text.setText(a);
}
});
iptouse = ipaddresses[i].substring(0, 26);
connectedtoipsuccess = true;
Logger.getLogger("MainActivity(inside thread)").info(a);
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
Logger.getLogger("MainActivity(inside thread)").info("encoding exception");
}
Logger.getLogger("MainActivity(inside thread)").info("test1");
break;
}
else
{
}
}
}
});
t.start();
}
});
}
At this place in the method inside the FOR loop the variable 'i' should be final:
text.setText("Connection Failed: " + generateRunnablePrinter(i));
But since 'i' is also the variable of the FOR loop i can't make it final.
So i added the method : generateRunnablePrinter
private Runnable generateRunnablePrinter(final int value)
{
return new Runnable() {
public void run()
{
text.setText("Connection Failed: " + ipaddresses[value]);
}
};
}
But now using this method I'm getting the exception:
ViewRootImpl$CalledFromWrongThreadException
You can't change the UI "text of the TextView" from another thread so you can try AsyncTask to do the work in the background in doInBackground() method then change the UI in the method onPostExecute().
Check out the AsyncTask:
http://developer.android.com/reference/android/os/AsyncTask.html
Since you're adjusting your UI, you'll need to run it from the UI thread. I'd recommend this function:
runOnUiThread(new Runnable() {
#Override
public void run() {
// Your code here...
}
});
If you're calling it from anywhere else but an Activity, you'll need to either pass down the activity or get the activity using getActivity() (i.e. from a fragment), and then call the function from the activity, i.e. getActivity().runOnUiThread() { ... }
Handler hnd = new Handler() {
#Override
public void handleMessage(Message msg) {
int id = sequence.get(msg.arg1);
if(msg.arg1 % 2 == 0) {
sq.get(id-1).setBackgroundResource(R.drawable.square_show);
} else {
sq.get(id-1).setBackgroundResource(R.drawable.square);
}
}
};
#Override
public void onResume() {
super.onResume();
Thread background = new Thread(new Runnable() {
public void run() {
try {
for(int i = 0; i <= sequence.size()-1; i++) {
Thread.sleep(200);
Message msg = hnd.obtainMessage();
msg.arg1 = i;
msg.setTarget(hnd); // EDITED
msg.sendToTarget();
record_tv.setText(""+i);
}
} catch(Throwable t) {
}
}
});
background.start();
}
the code arrives to msg.sendToTarget(), does its things and then never came back
sendToTarget(); throws a null pointer exception it you have no set a receiver with setTarget(Handler).
Also, in your code I see
record_tv.setText(""+i);
this line, inside your thread will throw a
android.view.ViewRoot$CalledFromWrongThreadException