Changing background image at certain time interval - java

I was trying to develop a android application in which the background changes every 5 seconds I wrote code something like this :
public class BgView extends Activity implements Runnable {
ImageView img;
int [] setImg = {R.drawable.one,R.drawable.two};
RelativeLayout layout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bg_view);
layout = (RelativeLayout) findViewById(R.id.first);
Thread t = new Thread(new BigView);
t.start();
}
#Override
public void run() {
for (int i = 0; i < 2; ++i) {
layout.setBackgroundResource(setImg[i]);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
It compiled fine but when i tried to run this in emulator it stopped after 5 seconds and in logcat i saw an exception which says that i cannot touch Activity class view from other function or something like that.
so i put the whole for loop inside the onCreate() method and now i don't get any exception but all i see is a blank screen for 5 seconds after that i get the last image
I know this question has been repeated but i just don't want to copy paste the code...i want to know why this happened and how can we make this working with least changes
edit :
i get following exception :
E/AndroidRuntime(904): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
And i want to know why putting whole for loop inside onCreate() method didn't work

Only UI thread can/should update the UI views, In your code you are trying to update the views directly from the new thread.
You should create a handler in your activity and then invoke that from your thread at required interval. Then handler should then update the UI. Try the code(I have not compiled the code, just typed it so ther might be typos/errors)
public class BgView extends Activity implements Runnable {
ImageView img;
final int [] setImg = {R.drawable.one,R.drawable.two};
RelativeLayout layout;
interface MyHandler {
void letMeKnow(int i);
}
private MyHandler handler = new MyHandler(){
#Override
void letMeKnow(int i){
layout.setBackgroundResource(setImg[i]);
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bg_view);
layout = (RelativeLayout) findViewById(R.id.first);
Thread t = new Thread(new BigView);
t.start();
}
#Override
public void run() {
for (int i = 0; i < 2; ++i) {
handler.letMeKnow(i);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} `

Put this line inside ui thread like that as you can't modify in the ui thread from another thread
runOnUiThread(new Runnable() {
#Override
public void run()
{
layout.setBackgroundResource(setImg[i]);
}
});
And I think that the right way to do it is using alarm . Refer to this link Android alarms
Hope this helps.

Your run method should be re-written like below:
public void run() {
for (int i = 0; i < 2; ++i) {
runOnUiThread(new Runnable() {
public void run()
{
layout.setBackgroundResource(setImg[i]);
}
});
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

Related

How to generate a TextView inside a thread inside a for loop in the main activity

Is it possible to generate a TextView inside a for loop in the main activity? I have to run a thread from another Java class "multithread." When this class runs, I will know how many clients connected to, I will run the insider thread to generate TextViews according to the number of the clients, and display the received messages in these TextViews.
But I am obtaining an error. If you know any better way to run a thread inside the main activity, please let me know, thanks.
Here is the method:
public void toggleButtonConnectToClientsFunction(View view) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
//Multithread here
multicastthreadRun.run();
for(int counter=0;counter<multicastthreadRun.ClientIpArrayList.size();counter++) {
TextView textView=new TextView(this);//i am obtaining error here
linearLayoutSecondaryTexts.addView(textView);
runOnUiThread(new Runnable() {
#Override
public void run() {
//in this case we can change the user interface
}
});
}//end of the for loop
}
});t.start();
new Runnable is an anonymous class and this is pointing to that anonymous class. To create a textview, you need to pass context (either activity or context) so in order to do that, use specific reference to class with className as
TextView textView=new TextView(YourContainerActivityClassName.this);
// e.g TextView textView=new TextView(MainActivity.this);
Note: since it's a click listener so seems like this is in an activity directly
and you cannot update the UI from worker threads so do it like
public void toggleButtonConnectToClientsFunction(View view) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
//Multithread here
multicastthreadRun.run();
for(int counter=0;counter<multicastthreadRun.ClientIpArrayList.size();counter++) {
// use proper context
TextView textView=new TextView(YourActivityNamethis);//i am obtaining error here
runOnUiThread(new Runnable() {
#Override
public void run() {
// Update UI
linearLayoutSecondaryTexts.addView(textView);
}
});
}//end of the for loop
}
});t.start();
}
TextView textView = new TextView(this);//i am obtaining error here
TextView textView = new TextView(getBaseContext());// textview expect context object NOT runnable object.
And instead of using loop you can just use Recursion.
public void toggleButtonConnectToClientsFunction(View view) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
//Multithread here
multicastthreadRun.run();
makeTextView ( 0,multicastthreadRun.ClientIpArrayList.size());
}
});
t.start();
}
private void makeTextView(final int count, final int max){
if (count>= max)
return; // end of Loop
TextView textView = new TextView(getBaseContext());// Use can you this here as it will refer to your activity object.
runOnUiThread(new Runnable() {
#Override
public void run() {
//in this case we can change the user interface
linearLayoutSecondaryTexts.addView(textView);
makeTextView(count+1, max);
}
});
}
In your code TextView(this) will not work because it is inside on Thread.
You have to specify the context exactly. Check below code:
TextView tv = new TextView(YOUR_ACTIVITY.this);
tv.setText("What to do");
Thanks :)

Google Glass Immersion - OnClick not working inside a separate thread

My problem is pretty simple. I am creating a card based on the result of a HTTP query performed inside a separate thread. The card also has an onclick method and is defined inside a runOnUiThread() located inside the separate thread. However, when the device is tapped, the onclick event isn't fired.
Here is my code:
private void login() {
Runnable r = new Runnable() {
#Override
public void run() {
// irrelevant code
runOnUiThread(new Runnable() {
#Override
public void run() {
setContentView(buildError(code));
}
}
}
Thread t = new Thread(r);
t.start();
}
private View buildError(String code) {
CardBuilder card = new CardBuilder(this, CardBuilder.Layout.ALERT);
card.setIcon(R.drawable.ic_warning_150);
if (code.equals("1"))
card.setText("Incorrect credientals");
else
card.setText("Unexpected error");
card.setFootnote("Tap to try again");
View cView = card.getView();
cView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("Event", "Clicked"); // This is what isn't triggering
}
});
cView.setFocusable(true);
cView.setFocusableInTouchMode(true);
return cView;
}
Even though the snippet of code contains an error (can't be compiled, missing ; at the Runnable statement), you were on the right track.
The View simply needs to request the focus in order to be clickable right away. Otherwise you'll have to move the focus manually.
cView.setFocusable(true);
cView.setFocusableInTouchMode(true);
cView.requestFocus();
Reference

Why my thread doesn't work?

I make an app that can count down. But it doesn't work and it just shows 100 in textview.
Here is my code:
public class MainActivity extends Activity {
private TextView textView;
private Button start;
Thread thread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView1);
start = (Button) findViewById(R.id.button1);
start.setOnClickListener(onStart);
thread = new Thread( //it's my thread
new Runnable() {
#Override
public void run() {
for (int i = 99; i > 0; i--) {
Log.i("Where am I?", "I'm in for loop .");
try {
textView.setText(String.valueOf(i));
} catch (Exception e) {
Log.e("Exception.getCause", String.valueOf(e.getCause()), e.getCause());
}
Log.i("INDEX", String.valueOf(i));
}
}
});
}
private View.OnClickListener onStart = new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("Where am I?", "I in View.OnClickListener .");
thread.start();
}
};
}
Update your TextView using runOnUiThread as below...
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(String.valueOf(i));
}
});
Update:
For delay in count you can use Handler as below. Create an object of Handler and create a Thread.
private Handler mTimerHandler = new Handler();
private Runnable mTimerExecutor = new Runnable() {
#Override
public void run() {
//add your code here which should execute after the specified delay
}
};
Then pass that thread inside postDelayed() method Handler with the time which should be delayed to execute the thread as below...
mTimerHandler.postDelayed(mTimerExecutor, 1000);
And if you want to cancel the thread to execute, use removeCallbacks() method as below...
mTimerHandler.removeCallbacks(mTimerExecutor);
Catching for Exception inside the Thread is kind of misleading. As matter of fact, textView.setText(String.valueOf(i)); executed in a Thread different from the UI Thread should make you app crashes for CalledFromTheWrongThreadException. You should use an Handler to execute that line in the UI Thread's context
textView.setText(String.valueOf(i));
has to be used in UI thread only.
textView.setText(String.valueOf(i));
This is UI action, You can handle UI action only in a main thread.
You can send a message to the handle of activity.
You cannot use Thread class to interact with UI you should use AsyncTask or Handler classes.
Sample tutorial: http://www.vogella.com/tutorials/AndroidBackgroundProcessing/article.html
Use AsyncTask instead.
Checkout:
http://www.vogella.com/tutorials/AndroidBackgroundProcessing/article.html

Start an Activity from Splash Screen, should I use run() or runOnUiThread()?

I have a Splash Screen (Logo Activity) to show the company name for 3 seconds before app starts. I start Main Activity from a thread, here is the code:
public class Logo extends Activity {
Thread t;
public boolean dead = false;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.logo);
t = new Thread() {
public void run() {
try {
Intent i = new Intent(Logo.this, Main.class);
Thread.sleep(3000);
if (!dead) {
startActivity(i);
}
finish();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t.start();
}
The Main Activity is called from a worked thread, is this correct? What are the differents with this code (using runOnUiThread)?
...
if (!dead) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Intent i = new Intent(Logo.this, Main.class);
startActivity(i);
}
});
}
...
I see no difference with this code in debug mode (The same threads, the same operation, etc.). Which is correct?
Starting an intent I think is not an UI operation. runOnUI thread runs UI operation on UI thread. So you can use either of thread (runOnUI or normal). May be normal thread will be good in this situation. But I would like to suggest you use timer instead.
To be honest, I don't like the Thread.sleep. PLease take a look at my solution:
new Timer().schedule(new TimerTask() {
#Override
public void run() {
// Do your work here like... startActivity...
}
}, SPLASH_DURATION); // SPLASH_DURATION IS IN MILLISECONDS LIKE 3000
Also you can block the user to prevent the back key like this:
#Override
public void onBackPressed() {
// do nothing! disable user interaction!
}
You should use AsyncTask in "doInBackground" background thread and than sleep your thread(this thread not UIThread) "PostExecute" run on UI Thread than start your new activity
private class mSplashViewer extends AsyncTask<Void,Void,Void>{
protected void doInBackground(Void params){
Thread.currentThread().sleep(3000);
return null;
}
protected void onPostExecute(){
startActivity(...);
}
}

Async Task with Media Player isn't Firing PublishProgress

I've written a AsyncTask:
public class AudioTransition extends AsyncTask <Void, Void, MediaPlayer>
{
private int goalID;
private int milliseconds;
private MediaPlayer tempPlayer;
AudioTransition(int ID, int Milliseconds)
{
goalID = ID;
milliseconds = (int)(((float)Milliseconds)/100);
}
#Override
protected void onPreExecute()
{
tempPlayer = MediaPlayer.create(context, goalID);
tempPlayer.setVolume(0, 0);
tempPlayer.setLooping(true);
tempPlayer.start();
}
#Override
protected MediaPlayer doInBackground(Void... arg0) {
for (int i = 0; i < 100; i++)
{
value = i;
publishProgress();
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (!player.isPlaying())
tempPlayer.pause();
}
return tempPlayer;
}
#Override
protected void onProgressUpdate(Void... v) {
super.onProgressUpdate(v);
player.setVolume(100-value, 100-value);
tempPlayer.setVolume(value, value);
}
#Override
protected void onPostExecute( MediaPlayer result ) {
super.onPostExecute(result);
player.reset();
player = tempPlayer;
player.setVolume(100,100);
transitioning = false;
}
}
But the volume doesn't fade out. It just starts both tracks, then stops. The MediaPlayers are not updated until doInBackground completes. How can I make the MediaPlayers get updated within this type of background worker? It seems like the publishProgress() thing should work.
Oh lord. Dont be sleeping threads inside of AsyncTask! You are completely misusing AsyncTask. You couldn't think of another way to do a timer type thing, so you're latching onto the idea of publishprogress from AsyncTask (which doesn't even work how I think you think it works) even though AsyncTask should be used for one thing and one thing only: doing heavy work off of the main (UI) thread.
If you just wanted to fade the volume out then use something like this: (this goes somewhere outside of any method).
private Runnable VolumeFadeRunnable = new Runnable() {
#Override
public void run() {
volume--;
player.setVolume(volume, volume);
if(volume>0)
handler.postDelayed(this, 1000);
else
handler.removeCallbacks(this);
}
};
just initialize your handler as a field inside of onCreate or whatever and make sure that and the counter variable are visible inside of that runnable.

Categories