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);
}
});
Related
I have a service type class which starts a timertask in onCreate method and I need to stop the timer from MainActivity when user press the button. I know I have to keep the reference to the timer in my service, but I cannot figure out how to do that and need some help, please!
please take a look at my code
package com.example.timertest;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = findViewById(R.id.button);
button.setOnClickListener(this);
startService(new Intent(this, TimeService.class));
}
#Override
public void onClick(View v) {
if(v.getId() == R.id.button){
// i need here to call mTimer.cancel() in TimeService.class
//
}
}
}
// and here is the TimeService.java
package com.example.timertest;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.widget.Toast;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class TimeService extends Service {
public Timer mTimer;
private Handler mHandler = new Handler();
long NOTIFY_INTERVAL = 60 * 1000 * 1; // 1 min
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
if (mTimer != null) {
mTimer.cancel();
} else {
mTimer = new Timer();
}
mTimer.scheduleAtFixedRate(new RefreshDataTimerTask(), 0, NOTIFY_INTERVAL);
}
class RefreshDataTimerTask extends TimerTask {
#Override
public void run() {
mHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), getDateTime(), Toast.LENGTH_LONG).show();
}
});
}
private String getDateTime() {
SimpleDateFormat sdf = new SimpleDateFormat("[yyyy/MM/dd - HH:mm:ss]");
return sdf.format(new Date());
}
}
}
//and service registered in manifest
<service android:name=".TimeService"/>
I have tried to call the mTimer.cancel(), but got a null reference, because seems I have created a new instance of the service class.
This example shows a Toast with date and time each minute, i want when for example 15 seconds have past and i press the button, the timer to be canceled and to start counting 60 seconds again from the beginning. Inside this service i have many other things like notifications,channels, shared preferences and so on, so it will be good if i can operate only with the timer object.
Take a look on this API documentaion and this. There is example of how to bind service to activity after what you can get direct access to service methods.
After successful binding you can add method inside your service to stop the timer:
public void stopMyTimer() {
mTimer.cancel();
}
And call this method from Activity
This might not be best practice, but you can access public values by directly referring to the class:
TimeService.mTimer.cancel()
Which should work because Services function similarly to Singletons, in that each call of startService should be calling the same instance.
When I run my code below everything works fine. When I want to go back to the previous activity (using the emulator) I get a black screen and then the app shuts down. I also get a black screen when I exit the application and try to resume it.
The code:
package com.example.bono.as3;
import android.app.Activity;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;
import java.io.InputStream;
public class Main extends Activity {
DrawView drawView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
drawView = new DrawView(this);
setContentView(drawView);
}
#Override public void onResume(){
super.onResume();
drawView.resume();
}
#Override public void onPause(){
super.onPause();
drawView.pause();
}
public class DrawView extends SurfaceView implements Runnable{
Thread gameloop = new Thread();
SurfaceHolder surface;
volatile boolean running = false;
AssetManager assets = null;
BitmapFactory.Options options = null;
Bitmap incect[];
int frame = 0;
public DrawView(Context context){
super(context);
surface = getHolder();
assets = context.getAssets();
options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
incect = new Bitmap[2];
try {
for (int n = 0; n < incect.length; n++){
String filename = "incect"+Integer.toString(n+1)+".png";
InputStream istream = assets.open(filename);
incect[n] = BitmapFactory.decodeStream(istream,null,options);
istream.close();
}
} catch (IOException e){
e.printStackTrace();
}
}
public void resume(){
running = true;
gameloop = new Thread(this);
gameloop.start();
}
public void pause(){
running = false;
while (true){
try {
gameloop.join();
}
catch (InterruptedException e){}
}
}
#Override public void run (){
while (running){
if (!surface.getSurface().isValid())
continue;
Canvas canvas = surface.lockCanvas();
canvas.drawColor(Color.rgb(85, 107, 47));
canvas.drawBitmap(incect[frame], 0, 0, null);
surface.unlockCanvasAndPost(canvas);
frame++;
if (frame > 1) frame = 0;
try {
Thread.sleep(500);
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
}
I dont get any error message in the log, what I do get is about 13 messages saying "suspending all threads took: X ms" so it has something to do with my gameloop Thread I think. Unfortunately I don't see what the problem is in my code...
If you need a context, use getApplicationContext() or Activity.this. (seems less buggy with my code)
While going back to a previously used activity, onCreate() is not called, only onResume(), so it might help if you move the following lines to there.
drawView = new DrawView(this);
setContentView(drawView);
Why use inner class at all? Activity is a class already. If you want to use the code multiple times, make it a class on its own.
This is what i use to navigate back. Maybe this is usefull for you 2!
Button backpressed = (Button) findViewById(R.id.btBack);
backpressed.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
onBackPressed();
}
});
The onBackPressed() is just a method that you can call if you want to return to the last page.
What it looks like for me:
I code a program which I expected to perform follwing action sequentially onclick the button:
1.Display the text(eg: "abc") in textview.
2.sleep for sometime(eg:2000).
3.finally it has to change the text(eg: "xyz") in textview.
for that i try the below code. when I run this, first it sleep for 2000 millisecond and display "xyz", It doesnot displaying "abc"...
(* I noticed that sleep will excecuting first inside the setOnclickListner()function then only rest of the code are excecuting *)
please help me to perform the action in sequence...
If my question is silly please excuse as I was new to this....
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
Button b1;
TextView tv;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv =(TextView)findViewById(R.id.textView1);
b1=(Button)findViewById(R.id.button1);
b1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
tv.setText("abc");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
tv.setText("xyz");
}
});
}}}
Use Handler.postDelayed instead of Thread.sleep which freeze main UI Thread for 2000. Do same using Handler as:
Create Runnable :
private Runnable runnable = new Runnable() {
public void run() {
tv.setText("xyz");
mHandler.removeCallbacks(runnable);
}
};
call Handler.postDelayed on Button click :
mHandler = new Handler();
b1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
tv.setText("abc");
mHandler.postDelayed(runnable, 2000);
}
});
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.
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.