I am trying to change background every second and this is my code:
package com.example.splasher;
import java.lang.reflect.Field;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Typeface;
import android.util.Log;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
public class Views extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.view);
final ScrollTextView scrolltext=(ScrollTextView) findViewById(R.id.scrolltext);
if(MainActivity.bold.isChecked())
{
scrolltext.setTypeface(null, Typeface.BOLD);
};
if(MainActivity.italic.isChecked())
{
scrolltext.setTypeface(null, Typeface.ITALIC);
};
if((MainActivity.italic.isChecked())&&(MainActivity.bold.isChecked()))
{
scrolltext.setTypeface(null, Typeface.BOLD_ITALIC);
};
scrolltext.setTextSize(Integer.parseInt(MainActivity.tSize[MainActivity.Size.getSelectedItemPosition()]));
scrolltext.setText(MainActivity.text);
scrolltext.setTextColor(Integer.parseInt(MainActivity.colour[MainActivity.TextColour.getSelectedItemPosition()]));
scrolltext.startScroll();
scrolltext.setBackgroundColor(Integer.parseInt(MainActivity.colour[MainActivity.BackgroundColour.getSelectedItemPosition()]));
Thread thread = new Thread()
{
public void run()
{
if(MainActivity.random.isChecked())
{
int delay = 0; // delay for 5 sec.
int period = 1000; // repeat every sec.
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
int n=1;
public void run() {if (n==9)n=1;
scrolltext.setBackgroundColor(Integer.parseInt(MainActivity.colour[n]));
}
}, delay, period);
/*int n=1;
boolean constant=true;
while (constant==true){
if (n==10) n=1;
// int randInt = new Random().nextInt(2);
// scrolltext.setBackgroundColor(Integer.parseInt(MainActivity.colour[randInt]));
scrolltext.setBackgroundColor(Integer.parseInt(MainActivity.colour[n]));
n=n+1;
try
{
Thread.sleep(2000); // 1 second
} catch (Exception e)
{
e.printStackTrace();
}
}*/
}
}
};
thread.start();
// TextView textview=(TextView) findViewById (R.id.textView1);
// textview.setText(MainActivity.text);
// textview.setTextColor(Integer.parseInt(MainActivity.colour[MainActivity.TextColour.getSelectedItemPosition()]));
// textview.setBackgroundColor(Integer.parseInt(MainActivity.colour[MainActivity.BackgroundColour.getSelectedItemPosition()]));
// textview.setTextSize(Integer.parseInt(MainActivity.tSize[MainActivity.Size.getSelectedItemPosition()]));
// textview.setSelected(true);
}
}
But it force closes. Logcat shows: FATAL EXCEPTION: Timer-0; android.view.ViewRootŲcalledfromwrongThreadException: Only original threat that created a view hierarchy can touch its view.
What is wrong with this code?
You can not operate on the UI elements (like call scrolltext.setBackgroundColor()) in a thread separate from the so-called UI thread (which is basically the same thread onCreate() runs in.
To solve your issue, use a Handler. Create a class field:
Handler handler = new Handler();
And in your thread put all UI operations inside a Handler call:
handler.post(new Runnable() {
#Override
public void run () {
// All UI operations, like scrolltext.setBackgroundColor()
}
});
Your problem is
scrolltext.setBackgroundColor(Integer.parseInt(MainActivity.colour[n]));
You are updating UI from worker Thread(it not runs on UI Thread) and this is not allowed. Only Main(UI) Thread can manipulate with UI.
So you need to change it to runOnUiThread() or Handler.
Examples:
runOnUiThread(new Runnable(){
public void run() {
// do your stuff
}
});
Handler example.
Just trying to contribute here, but I have zero experience in android, so be cautions ;p
The exception message seems to suggest that the view can only be altered on the main thread. As you are running code which alters the view on a new thread, it doesn't like it.
Are you aware of a main Event-Dispatcher thread used in Android? Similar to how SWINGs GUI is updated on the EDT. If so, look for a way to tell the main drawing thread to do the final updates.
In swing, it would look something like:
EventQueue.invokeLater(new Runnable(){
public void run(){
}
}
Hope this has some meaning.
Related
I was trying to execute one activity after executing another,by using threads and using sleep method of thread class.
Here is the code,
package com.example.admin.myapplication;
import android.content.Intent;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layo);
Thread th=new Thread() {
public void run()
{
try
{
Thread.sleep(3000);
}
catch(InterruptedException i)
{
i.printStackTrace();
}
finally
{
Intent io=new Intent("com.example.admin.myapplication.NEWATTEMPT");
startActivity(io);
}
}
};
th.start();
}
Code for layo.xml is-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:background="#drawable/pic">
</LinearLayout>
and NewAttempt is another java class-
My question here is this-
In line no. 16 of MainActivity,I am setting the content to layo.xml,and after that I am creating an instance of thread class and starting it,
but,If I put setContentView(R.layout.layo) in the try block,then its showing an error,on starting the application.Why is it so??Can somebody explain why?
And can somebody please explain how an execution happens in android,i.e,order in which files are read?I am a beginner in Android and I doesn't have much idea how the control flows from one activity to another?
Whenever you want to modify your view inside Activity, you need to do it on your activity(ui) thread. UI thread is synchronized. Activity has a method that can handle your Runnable
runOnUiThread(new Runnable() {
#Override
public void run() {
//your method that modify view
}
});
In your case, you can put method above inside your thread
Thread th = new Thread() {
public void run()
{
try
{
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
//your method that modify view
MainActivity.this.setContentView(R.layout.layo);
}
});
Thread.sleep(3000);
}
catch(InterruptedException i)
{
i.printStackTrace();
}
finally
{
Intent io = new Intent("com.example.admin.myapplication.NEWATTEMPT");
startActivity(io);
}
}
};
th.start();
If you want to make a splash screen model activities, then try timer() class and schedule it.
try this code inside onCreate() method
eg:
Timer timer=new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
Intent intent=new Intent(MainActivity.this, NEWATTEMPT.class);
startActivity(intent);
}
},1000);
I am implementing a simple render view class for Android extending SurfaceView. My main activity class includes an infinite while loop for other operations.
However, the app shows a black screen when main activity is in the infinite loop. As far as I know, main activity and surface view classes have their own separate threads, so surface view class should keep rendering even when main activity class is busy. The app works just fine when I prevent infinite loop by setting 'running' boolean variable false in the code.
What might be the reason of that surface view class stops rendering when my main activity is in an infinite loop?
My main activity and surface view classes are as follows:
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
public class MainActivity extends Activity{
RenderSurfaceView renderView;
public boolean running = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate ( savedInstanceState );
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
renderView = new RenderSurfaceView(this);
setContentView(renderView);
loop();
}
public void loop(){
running = true;
while(running){
}
}
protected void onResume() {
super.onResume();
renderView.resume();
}
protected void onPause() {
super.onPause();
renderView.pause();
}
}
This my render class that extends SurfaceView:
import java.util.Random;
import android.content.Context;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class RenderSurfaceView extends SurfaceView implements Runnable{
Thread renderThread = null;
SurfaceHolder holder;
volatile boolean running = false;
Random r = new Random();
public RenderSurfaceView(Context context) {
super(context);
holder = getHolder();
}
public void resume() {
running = true;
renderThread = new Thread(this);
renderThread.start();
}
public void run() {
while(running) {
if(!holder.getSurface().isValid())
continue;
render();
}
}
private void render(){
Canvas canvas = holder.lockCanvas();
canvas.drawRGB(r.nextInt(255), r.nextInt(255), r.nextInt(255));
holder.unlockCanvasAndPost(canvas);
}
public void pause() {
running = false;
while(true) {
try {
renderThread.join();
} catch (InterruptedException e) {
// retry
}
}
}
}
This
renderView = new RenderSurfaceView(this);
setContentView(renderView);
does not show the view immediately. Instead it has to go through a layout traversal first, which doesn't happen immediately but asynchronously to the Activity lifecycle methods, and it happens on the main thread. So running an infinite loop at the end of onCreate() prevents the layout traversal of the view hierarchy, which means your SurfaceView will never be shown.
In theory you could experiment with starting your infinite loop delayed using a Handler, for experimental purposes maybe. In general infinite loops on the main thread are a super bad idea and I can't see a reason why you would want to do this, apart from experiments maybe.
My self-answer to this question Modifying views in AsyncTask doInBackground() does not (always) throw exception has a bit more detail on what's going on behind the scenes. The question is not directly related to what you're asking here, but the background is the same I believe.
This code is too add a timer on the code.. but i am having a problem with my code when it comes to the timer code...
How will i improve the code for the timer inside the for loop of my code..
Hopefully you understand the my code.. and have improved my code.. Thanks!!!!
package com.thesis.americansignlanguage;
import java.io.IOException;
import java.io.InputStream;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;
public class AlphabetCompareClass extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.alphabetcompare);
final String get;
Bundle gotWord = getIntent().getExtras();
get = gotWord.getString("key");
TextView Word = (TextView)findViewById(R.id.textView1);
final ImageView img = (ImageView)findViewById(R.id.image_alpha) ;
Word.setText(get);
for(int x = 0; x > gotWord.getString("key").length(); x++) {
final InputStream is;
Timer timer = new Timer();
TimerTask timertask = new TimerTask() {
#Override
public void run() {
try {
is = getResources().getAssets().open(get + ".png");
Bitmap bitmap = BitmapFactory.decodeStream(is);
img.setImageBitmap(bitmap);
} catch (IOException e) {
return;
}
}
};
}
};
}
Two problem found in current code:
First : Not using timer instance to schedule timerTask. do it as:
timer.schedule(timertask, 500, 3000);
Second : Updating UI from non- ui thread inside run method of TimerTask
Use runOnUiThread or Handler for updating Ui from run method of TimerTask
TimerTask runs on a different thread. Ui can be updated only from ui thread.
This img.setImageBitmap(bitmap); should be executed on the ui thread
Use runOnUiThread. You can also use a Handler. Also i do not understand the need for the for loop.
runOnUiThread(new Runnable() {
#Override
public void run() {
img.setImageBitmap(bitmap);
}
});
Here is an example application I wrote to reproduce the memory leak related issue i have met :
package a.b.mapleak;
import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MapLeak extends Activity
{
TextView callVoidText, getNewDataText, getDataStringText;
Button callVoidButton, getNewDataButton, getDataStringButton;
Handler callbackHandler;
MemoryLeak memleak;
private LoadAccountsTask mLoadAccountsTask = null;
private class LoadAccountsTask extends AsyncTask<Void, Void, Object[]> {
private int mCursor1;
private int mCursor2;
private Context context;
private UITask t = new UITask();
#Override
protected Object[] doInBackground(Void... params) {
runOnUiThread(t);
// Create the summaries cursor
mCursor1 = 1;
mCursor2 = 2;
return new Object[] { mCursor1, mCursor2};
};
private class UITask extends Thread {
#Override
public void run() {
int i = 2;
while (i>0) {
i--;
}
Thread.State state=t.getState();
Log.e(ALARM_SERVICE, "Thread state in run is " + state.toString());
}
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
getDataStringText = (TextView) findViewById(R.id.getDataString_text);
getDataStringButton = (Button) findViewById(R.id.getDataString_button);
getDataStringButton.setOnClickListener(new Button.OnClickListener() {
long i = 0;
public void onClick(View v) {
if (mLoadAccountsTask != null) mLoadAccountsTask.cancel(true);
mLoadAccountsTask = (LoadAccountsTask) new LoadAccountsTask(this).execute();
}
});
}
}
I found that the thread started in runOnUiThread has never been exited. For some unknown to me reason the task was running, but the output from
Log.e(ALARM_SERVICE, "Thread state in run is " + state.toString());
every time was "Thread state in run is NEW" e.g. ''The thread has been created, but has never been started.''. So the thread was running continuously preventing "LoadAccountsTask" class from being garbage collected. Thus, in this example, every time the button is pressed - the new "LoadAccountsTask" appeared in memory.
But, if to replace
private class UITask extends Thread
with
private class UITask implements Run
there was no memory leak, the thread exited successfully. Of course state=t.getState(); will not work in this case and should be commented.
Do anybody have an explanation why it is so?
Focusing on your immediate concern, runOnUiThread() takes a Runnable. While Thread does implement Runnable, runOnUiThread() will not treat it as a Thread. Please just pass a Runnable to runOnUiThread().
Second, never call runOnUiThread() from doInBackground(). Just perform the work from that Runnable in onPreExecute() or onPostExecute(), which are executed on the main application thread.
Third, if you ever do write a real Thread, don't busy-loop in it.
I have an example like this:
package android.uiexample;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ProgressBar;
import android.widget.RadioGroup;
import android.widget.Toast;
import android.widget.ToggleButton;
import android.widget.RadioGroup.OnCheckedChangeListener;
public class BasicViewsExampleActivity extends Activity
{
private static int progress = 0;
private ProgressBar progressBar;
private int progressStatus = 0;
private Handler handler = new Handler();
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.basic_views);
progressBar = (ProgressBar) findViewById(R.id.progressbar);
//---do some work in background thread---
new Thread(new Runnable()
{
public void run()
{
//---do some work here---
while (progressStatus < 10)
{
progressStatus = doSomeWork();
}
//---hides the progress bar---
handler.post(new Runnable()
{
public void run()
{
progressBar.setVisibility(View.GONE);
}
});
}
//---do some long lasting work here---
private int doSomeWork()
{
try {
//---simulate doing some work---
Thread.sleep(500);
} catch (InterruptedException e)
{
e.printStackTrace();
}
return ++progress;
}
}).start();
}
}
In this example, it use Handler to post a Runable to exc progressBar.setVisibility(View.GONE);. I don't know why i can't call progressBar.setVisibility(View.GONE); directly:
//---do some work here---
while (progressStatus < 10)
{
progressStatus = doSomeWork();
}
//---hides the progress bar---
progressBar.setVisibility(View.GONE);
Anybody can tell me why i can't?
The android UI framework (like pretty much every UI framework before it) only allows you to update the UI state from the main thread. You may want to look at AsyncTask which include the plumbing needed to route progress updates onto the main thread.
Take a look at the Handler class. It provides a simple way to enqueue Runnable callbacks to run on the UI event thread.
changing the progressBar visibility is a UI operation. All UI operations must be done on the UI thread.