passing and setting TextView from another class - java

I have a text view in my android activity, and I want to pass it to a function in another java class and modify its text. But it throws me an exception. I read that I need to run it on a UI thread or send to context variable, but I'm a bit confused and I couldn't manage to do it. That's my code:
Java timer class
public class CountdownTimer {
static int duration;
static Timer timer;
public static void startTimer(final TextView TVtime) {
duration = 10;
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
TVtime.setText(setDuration());
}
}, 1000, 1000);
}
private static String setDuration(){
if(duration == 1)
timer.cancel();
return String.valueOf(--duration);
}
}
Android activity:
TVtime = (TextView) findViewById(R.id.textView_displayTime);
CountdownTimer.startTimer(TVtime);

You cannot update the UI from a non-UI Thread. Pass the activity Context to the startTimer() method.
public static void startTimer(final TextView TVtime,final Context activityContext) {
duration = 10;
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
((Activity) activityContext).runOnUiThread(new Runnable() {
public void run()
{
TVtime.setText(setDuration());
}
});
..........................
.......................
Android activity:
TVtime = (TextView) findViewById(R.id.textView_displayTime);
CountdownTimer.startTimer(TVtime, YourActivity.this);

You can use android.os.Handler for that :
public static void startTimer(final TextView TVtime) {
duration = 10;
final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
TVtime.setText((String) msg.obj);
}
};
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
Message msg = new Message();
msg.obj = setDuration();
handler.sendMessage(msg);
}
}, 1000, 1000);
}

Related

Splash screen leaking memory how to fix it?

My Splash screen leaking memory can anyone tell me how to fix that issue ?
public class SplashActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
new InnerClass(SplashActivity.this).loadNext();
}
private static class InnerClass {
private final WeakReference<Activity> weakReference;
private InnerClass(Activity activity) {
this.weakReference = new WeakReference<>(activity);
}
private void loadNext() {
Activity context = weakReference.get();
if (context != null) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
context.startActivity(new Intent(context, NavigationActivity.class));
context.finish();
}
}, 2000);
}
}
}
}
Here is the leak canary library report showing your activity leaking memory
Move the weakReference.get() method inside the run() method. Please try below:
private void loadNext() {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
Activity context = weakReference.get();
if (context != null) {
context.startActivity(new Intent(context, NavigationActivity.class));
context.finish();
}
}
}, 2000);
}

I am trying to display a CountDownTimer on screen and I get "Only one looper can be created per thread" in my logcat

I'm a beginner in Android programming. I'm trying to display a timer for an upgrade in my game to show how long the upgrade will be activated for. In my collision flag I call Looper.prepare and start my thread class as the logcat suggested I do. How would I get this to run on one looper?
Here is the snippet that starts the thread.
BigGapUpgrade.java
public boolean playerCollectUpgrade(Player player){
if(Rect.intersects(rectangle, player.getRectangle())){
Looper.prepare();
bigGapUpgradeHandler.start();
}
return Rect.intersects(rectangle, player.getRectangle());
}
And here is my thread class
BigGapUpgradeHandler.java
public class BigGapUpgradeHandler extends Thread {
TimerTask scanTask;
Timer timer = new Timer();
#Override
public void run() {
Looper.prepare();
scanTask = new TimerTask() {
public void run() {
}
};
timer.schedule(scanTask, 0, 4000);
CountDownTimer countDownTimer = new CountDownTimer(4000, 100) {
#Override
public void onTick(long l) {
Log.i(TAG, "onTick: ");
}
#Override
public void onFinish() {
timer.cancel();
Log.i(TAG, "onFinish: ");
}
}.start();
Looper.loop();
}
}
After running it I get this error
W/System.err: java.lang.RuntimeException: Only one Looper may be created per thread
--Edit
Here is the solution I came up with.
-- Solution
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
CountDownTimer countDownTimer = new CountDownTimer(5000,100) {
#Override
public void onTick(long millisUntilFinished) {
millis = millisUntilFinished/100;
}
#Override
public void onFinish() {
}
}.start();
}
});
OK, So what you can do is just use a TimerTask. That creates it's own background thread for you do stuff:
// This TimerTask Updates the UI so it needs a reference to the Activity.
static class PowerUpTimerTask extends TimerTask
{
WeakReference<AppCompatActivity> mActivity;
long mInterval;
long mPeriod;
public PowerUpTimerTask(AppCompatActivity activity, long period, long interval)
{
mActivity = new WeakReference<>(activity);
mInterval = interval;
mPeriod = period;
}
#Override
public void run()
{
AppCompatActivity activity = mActivity.get();
if (activity != null)
{
final TextView timerTextView = activity.findViewById(R.id.timerTextView);
mPeriod -= mInterval;
if (mPeriod > 0)
{
// Set time remaining
activity.runOnUiThread(new Runnable()
{
#Override
public void run()
{
timerTextView.setText(String.valueOf(mPeriod));
}
});
}
else
{
// Out of time...clear the Text and stop the timer task.
activity.runOnUiThread(new Runnable()
{
#Override
public void run()
{
timerTextView.setText("");
}
});
Log.d(TAG, "Timer done. Canceling.");
cancel();
}
}
else
{
// Cancel this timer task since we don't have a reference to
// the Activity any more.
Log.d(TAG, "Lost reference to Activity. Canceling.");
cancel();
}
}
}
Then you can start your Timer task like so:
...
// Will count down from 10 by 1s.
mPowerUpTimerTask = new PowerUpTimerTask(this, powerUpTime, 1);
// Schedule for every second.
Timer t = new Timer();
t.scheduleAtFixedRate(mPowerUpTimerTask, 1000, 1000);
...
Here is a link to this running sample:
https://github.com/didiergarcia/TimerTaskExample
I think you have to use LocalBroadcastManager for the timing to continuously in loop. Please check below code for for that :-
private void startTimer() {
countDownTimer = new CountDownTimer(Constant.getInstance().ANSWER_TIME_IN_SECOND * 1000, 1000) {
public void onTick(long millisUntilFinished) {
remaininTimeInMillies = millisUntilFinished;
tvTimer.setText(getTime(Integer.parseInt(String.valueOf(millisUntilFinished))));
}
public void onFinish() {
Intent intent = new Intent(Constant.getInstance().TIMER_RECEIVER);
LocalBroadcastManager.getInstance(PatientDetailActivity.this).sendBroadcast(intent);
}
};
countDownTimer.start();
}
private String getTime(int milliSec) {
int minut = 0, second = 0;
minut = milliSec / 60000;
second = (milliSec - (minut * 60000)) / 1000;
String strMinute = "", strSecond = "";
if (minut < 10) {
strMinute = "0" + String.valueOf(minut);
} else {
strMinute = String.valueOf(minut);
}
if (second < 10) {
strSecond = "0" + String.valueOf(second);
} else {
strSecond = String.valueOf(second);
}
return strMinute + ":" + strSecond;
}
#Override
protected void onResume() {
LocalBroadcastManager.getInstance(this).registerReceiver(timerBroadcast, new IntentFilter(Constant.getInstance().TIMER_RECEIVER));
super.onResume();
}
#Override
protected void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(timerBroadcast);
super.onDestroy();
}
Thanks and Hope that will help you

Timer.schedule runs once even with period

I'm a student trying to create an app for my miniproject for one of my modules and I'm trying to create an app that grabs data from a server every few seconds so it's updated. I tried using java timer and timerTask to run the code repeatedly but the program only run once and the get-button doesn't work as intended (suppose to grab data instantly) after implementing the timer. Android Emulator
public class MainActivity extends AppCompatActivity implements OnClickListener{
private Button speed;
private TextView result;
Timer timer;
TimerTask timerTask;
private TextView sSpeed;
final StringBuilder builder = new StringBuilder();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
result = (TextView) findViewById(R.id.result);
sSpeed = (TextView) findViewById(R.id.sSpeed);
speed = (Button) findViewById(R.id.get_button);
speed.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
getWebsite();
}
});
View aboutButton = this.findViewById(R.id.about_button);
aboutButton.setOnClickListener(this);
View exitButton = this.findViewById(R.id.exit_button);
exitButton.setOnClickListener(this);
}
public void onClick(View v) {
switch (v.getId()){
case R.id.get_button:
getWebsite();
break;
case R.id.about_button:
Intent i = new Intent(this, About.class);
startActivity(i);
break;
case R.id.exit_button:
finish();
break;
}
}
private void getWebsite(){
new Thread(new Runnable() {
#Override
public void run() {
try{
Document doc = Jsoup.connect("http://10.0.2.2:8080/Start_Stop_buttons_UTF8.html").get();
// Elements element = doc.getElementsByTag("p");
Elements element = doc.select("p");
//String title = doc.title();
builder.append(title).append("\n");
for (Element tag : element){
builder.append("\n\n").append(tag.text());
}
}catch(IOException e){
//e.printStackTrace();
builder.append("Error : ").append(e.getMessage()).append("\n");
}
runOnUiThread(new Runnable() {
#Override
public void run() {
String a = builder.toString(); // parse data from html into new string
a = a.substring(a.indexOf(":")+1, a.indexOf("Control")).trim();//trim string content
String b = builder.toString();
b = b.substring(11,b.indexOf(":")+1).trim();
double speed = Double.parseDouble(a);//convert string into double
if (speed<1000)
Log.i("HTML text","too slow");
else if((speed> 1500))Log.i("HTML text","too fast!");
result.setText(a);
sSpeed.setText(b);
}
});
}
}).start();
}
protected void onResume() {
super.onResume();
startTimer();
}
public void startTimer(){
timer = new Timer();
timerTask = new TimerTask() {
#Override
public void run() {
getWebsite();
}
};
timer.schedule(timerTask,1500,3000);
}
public void stopTimer(){
if(timer != null){
timer.cancel();
timer.purge();
}
}
}
Am I implementing the timer correctly to run getwebsite() repeatedly and able to get an instant update when get-button is clicked like it should have? Or is there a better way to implement these features using different method?
You are never calling the startTimer method in your ClickListener. You make one call to getWebsite. Change your call to startTimer.
speed.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
startTimer();
}
});
You also might want to check if the timer is already running before you start a new one. To do that assign a null value on your stopTimer method e.g.
public void stopTimer(){
if(timer != null){
timer.cancel();
timer.purge();
timer = null;
}
}
And your startTimer would look like this
public void startTimer(){
if(timer != null) return; // don't start multiple timers
timer = new Timer();
timerTask = new TimerTask() {
#Override
public void run() {
getWebsite();
}
};
timer.schedule(timerTask,1500,3000);
}

Timer in android java

I have 2 activity in activity2 i have a timer when activity create timer is started in activity on_Destroy i put timer_task.cancel(); but When opened the activity2 for the second time is create new timer task and not Canceled or destroyed the last timer and 2 timer is while be run in one activity
my code
private TimerTask mTimerTask;
private void doTimerTask(){
nCounter = 4;
qtimer.setMax(20);
if(mTimerTask!=null) {
mTimerTask.cancel();
}
mTimerTask = new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
Log.d("Timerrrr",nCounter+"");
if(nCounter<1){
Finished();
}else {
qtimer.setProgress(nCounter);
nCounter--;
}
}
});
}};
// public void schedule (TimerTask task, long delay, long period)
t.schedule(mTimerTask, 0, 1000); //
}
private void stopTask() {
if (mTimerTask != null) {
Log.d("nCounter canceled",nCounter+"");
mTimerTask.cancel();
}
}
#Override
protected void onDestroy() {
super.onDestroy();
mTimerTask.cancel();
MainActivity.this.finish();
}
Try This...
public void stopTimerTask(View v) {
//stop the timer, if it's not already null
if (mTimerTask != null) {
mTimerTask.cancel();
mTimerTask = null;
}
}
And Where do u call your stopTask() method?
And I suggest don't put mTimerTask.cancel(); in onDestroy(), but put it in onStop().
I hope this helps you.

Set running timer in TextView from a background Service with Pause and Resume options

I have created a Timer through Stopwatch class and implement it successfully in activity.
But i want to continue the timer after closing the application, so i used Service and put the method inside this. Something like below:
MyService.java:
Stopwatch stopwatch = Stopwatch.createStarted();
String workingTime1 = "";
void startThreadUpdateTimer() {
final DecimalFormat format = new DecimalFormat("00");
Timer T = new Timer();
T.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
workingTime1 = "Your effort is "
+ format.format(Double.valueOf(stopwatch
.elapsed(TimeUnit.HOURS)))
+ ":"
+ format.format(Double.valueOf(stopwatch
.elapsed(TimeUnit.MINUTES)))
+ ":"
+ format.format(Double.valueOf(stopwatch
.elapsed(TimeUnit.SECONDS)))
+ " till now for the day";
SwipePage.efforttimer.setText(workingTime1);
}
});
}
}, 1000, 1000);
}
void runOnUiThread(Runnable runnable) {
handler.post(runnable);
}
efforttimer is the TextView in which I want to show my effort time. I think binding service or broadcastreceiver will help here. Implement many ways but not succeed yet.
All helps and suggestions are mostly appreciable.
Thanks
LocalBroadcastManager will be the simplest solution in your case.
In your MyService you'll need this code:
public class MyService extends Service {
public static final String ACTION_UPDATE = "MyServiceACTION_UPDATE";
...
private void updateEmitterMethod() {
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(ACTION_UPDATE));
}
}
While in your Activity you'll have:
private BroadcastReceiver mMyServiceUpdateReciever;
...
#Override
public void onResume() {
super.onResume();
mMyServiceUpdateReciever = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
onUpdateMethod();
}
};
LocalBroadcastManager.getInstance(this).registerReceiver(mMyServiceUpdateReciever, new IntentFilter(MyService.ACTION_UPDATE));
}
#Override
public void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMyServiceUpdateReciever);
}

Categories