Switching Views inside a TimerTask - Android - java

I have the following code that responds to a button click, changes the view and then after 5 seconds switches the view back:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.menu);
Button test = (Button)findViewById(R.id.browseLocation);
test.setOnClickListener(testListener);
}
private TimerTask revert = new TimerTask(){
#Override
public void run() {
setContentView(R.layout.menu);
}
};
private OnClickListener testListener = new OnClickListener() {
public void onClick(View v) {
setContentView(R.layout.test);
Timer tim = new Timer();
tim.schedule(revert, 5000);
}
};
However this code does not work. The run method of the timetask is hit but setContentView fails. I assume it has something to do with scope inside the timetask.
How can I achieve the desired result?

Try yourActivityName.this.setContentView(). Do you know if revert is being called at all (i.e. using Logging)?

Found on another post that setContentView cannot be called from a non-UI thread.
Can achieve the desired affect using runOnUiThread, but not recommended.

Related

Cancel a CountDownTimer in another activity

I have a CountDownTimer in one activity that I need to cancel in a different activity. The problem I'm having is that the CountDownTimer is not getting cancelled even when I make a call to the endTestTimer() method in another activity. Here is the code for the CountDownTimer:
private long testMillisLeft, questionMillisLeft;
private static CountDownTimer testTimer;
private void startTestTimer()
{
long startTime = DataHolder.getTestTime()*1000; //getTestTime() is the seconds
testTimer = new CountDownTimer(startTime, 1000) {
#Override
public void onTick(long millisUntilFinished) {
testMillisLeft = millisUntilFinished;
updateTestTimeLeft();
}
#Override
public void onFinish() {
Intent intent = new Intent(MainActivity4.this, MainActivity5.class);
startActivity(intent);
}
}.start();
}
public static void endTestTimer()
{
if(testTimer != null)
{
testTimer.cancel();
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main4);
testTimeLeft = (TextView) findViewById(R.id.testTimerTextView);
mathProblem = (TextView) findViewById(R.id.mathProblemTextView);
testTimer = null;
startTestTimer();
}
And here is how I am trying to cancel the same timer in another activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainActivity4.endTestTimer();
}
A comment on this related post says that the static CountDownTimer creates memory leak. If that's the case, how can I call the endTestTimer() method in another activity and have it cancel the timer? Alternatively, how can I access the testTimer CountDownTimer directly and call .cancel() on it in another activity if it can't be static?
Looking into Android lifecycles led me to this post and this post, both of which I found very helpful. To my understanding, when the user hits the back button, the onDestroy() method is called for the currently-displayed activity, and then the onCreate() method is called for the activity to be displayed. So, to cancel the timers on MainActivity4 (the current activity in my case), I added this code to its class file:
#Override
protected void onDestroy() {
testTimer.cancel();
questionTimer.cancel();
super.onDestroy();
}
Now, when the user backs out of MainActivity4 (regardless of what other activity that takes them to) and onDestroy() is called automatically, both timers are cancelled and then MainActivity4 is destroyed. This seems to work fine for me, but I'm not sure if there are any downsides to doing it this way, so please let me know if there are.

Display a Shuffle of button text and backgrounds

I have a button in xml. On button press I wish to rapidly change the background and Text on that button.
I normally would use a code like this for the final result:
String rndm[] = {"A","B","C","D"};
{rnd = rndm[(int) (Math.random() * rndm.length)];}
{Button btn = (Button) findViewById(R.id.button1);
btn.setText(String.valueOf(rnd));
btn.setTextColor(Color.parseColor("#000000"));}
Before that is called though I would like perhaps a second or two of a "shuffling" effect.
I have tried using java.util.timer like this:
#Override
public void onClick(View v) {
new java.util.Timer().schedule(
new java.util.TimerTask() {
#Override
public void run() {
String rndm[] = {"A","B","C","D"};
{rnd = rndm[(int) (Math.random() * rndm.length)];}
{Button btn = (Button) findViewById(R.id.button1);
btn.setText(String.valueOf(rnd));
btn.setTextColor(Color.parseColor("#000000"));}
}}}, 100 );
Then making a few of these with different backgrounds to fire one after the other. I just can't seem to get the hang of it.
I may need a whole new method to do what I want to do, but I am not sure what the best wat to accomplish what I need is.
You should use Handler and make sure that the code that you want to run is in the runnable method :-)
Try something like this from your Activity
Handler handler = new Handler();
....
#Override
public void onClick(View v) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
// set your button color here, no need to use runOnUiThread()
// as this run() method is executed on Main thread
}
}, 100);
}

setText within Fragment not updating

I am currently attempting to clear the sensor values in a fragment, that are constantly being updated, however the clear button that I have set does nothing, even when I have paused the sensors.
Have I correctly setup the onViewCreated?
I have also attempted to setup the textviews in onCreateView to no success.
I get no errors whatsoever when I press the clear button, the values just don't clear.
Any pointers would be greatly appreciated!
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mPitchView = (TextView)view.findViewById(R.id.textView4);
mRollView = (TextView)view.findViewById(R.id.textView5);
mAzimuthView = (TextView)view.findViewById(R.id.textView6);
mRadioGroup = (RadioGroup) view.findViewById(R.id.radioGroup);
mRadioGroup.setOnCheckedChangeListener(this);
view.findViewById(R.id.button_clear).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onClear();
}
});
}
public void onClear(){
mPitchView.setText("");
mRollView.setText("");
mAzimuthView.setText("");
}
Also I have two other buttons start and stop which work perfectly fine.
I think the issue is the textview not updating.
use Handler
Handler txtsettext = new Handler(Looper.getMainLooper());
txtsettext.post(new Runnable() {
public void run() {
mPitchView.setText("");
mRollView.setText("");
mAzimuthView.setText("");
}
});

android - set intent extra from inside runnable

I'm still new to android development. I've been at this problem for some time but am still unable to figure out what to do on my own. In an Activity I set up a series of Runnables containing CountDownTimers. One executes after the next, but depending on which CountDownTimer is active, I need to pass a different Intent.extra to a fragment. I've tried setting my extra from inside Runnable, inside Run, and inside of the CountDownTimer onTick, and onFinish.
I fear I have way too much going on in my original Activity to post it, but here is the problem in essence.
public class MatchUpActivity extends Activity implements OpponentFragment.OnFragmentInteractionListener{
List mTotalDrafts;
Bundle mBundle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_match_up);
mBundle = new Bundle();
mDraftUsernames = extras.getStringArrayList("DRAFT_LIST");
for (int i = 0; i < totalDrafts; i++) {
Handler delayhandler = new Handler();
delayhandler.postDelayed(new Runnable() {
//bundle.put("extra", totalDrafts.get(0))
public void run() {
//bundle.put("extra", totalDrafts.get(0))
getTimer();
}
}, mTodaysDraftTime + (i * singleDraftDuration) - Calendar.getInstance().getTimeInMillis());
}
}
CountDownTimer
private void getTimer() {
new CountDownTimer(singleDraftDuration, 1000) {
public void onTick(long millisUntilFinished) {
//bundle.put("extra", totalDrafts.get(0))
}
public void onFinish() {
//bundle.put("extra", totalDrafts.get(0))
list.remove(0)
}
}.start();
}
}
I am able to remove items from my list in onFinish, but after I do so I need to send the next element in the list as an extra.
I hope this is enough code to get my question across. I tried to change some things from my original code for simplicity. If there is something I am missing or a better way to do this, please, anybody let me know.
Define the Bundle as global variable in your Activity and not in a Method implementation.

The method onClick(View) from the type new Thread(){} is never used locally

I'm attempting to multithread my code, but when I put the OnClickListener in a new Thread, this error comes up in Eclipse:
The method onClick(View) from the type new Thread(){} is never used locally
My code of MainClass:
public class MainClass extends Activity implements OnClickListener {
public float goldCount;
Button minionClick;
Button storeClick;
Button storeDismiss;
TextView textGoldCount;
ImageView spinningBars;
String textTotal;
private SharedPreferences prefs;
PopupWindow pw;
#Override
public 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.mainlayout);
LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
PopupWindow pw = new PopupWindow(inflater.inflate(R.layout.storemenu, null, false));
storeDismiss = (Button) pw.getContentView().findViewById(R.id.menudismissid);
Animation rotation = AnimationUtils.loadAnimation(this, R.anim.spinningbarsanimation);
rotation.setRepeatCount(Animation.INFINITE);
spinningBars.startAnimation(rotation);
prefs = getSharedPreferences("LeagueClicker", Context.MODE_PRIVATE);
goldCount = prefs.getFloat("goldCount", 0.0f);
minionClick = (Button) findViewById(R.id.minioncentreid);
storeClick = (Button) findViewById(R.id.storeimageid);
textGoldCount = (TextView) findViewById(R.id.textviewtop);
spinningBars = (ImageView) findViewById(R.id.spinningbarsid);
textTotal = goldCount + " Gold";
textGoldCount.setText(textTotal);
textGoldCount.setGravity(Gravity.CENTER);
Typeface tf = Typeface.createFromAsset(getAssets(), "mechanical.ttf");
textGoldCount.setTypeface(tf);
textGoldCount.setTextSize(35);
minionClick.setOnClickListener(this);
storeClick.setOnClickListener(this);
storeDismiss.setOnClickListener(this);
}
#Override
public void onPause() {
super.onPause();
prefs.edit().putFloat("goldCount", goldCount).commit();
}
#Override
public void onResume() {
super.onResume();
goldCount = prefs.getFloat("goldCount", 0.0f);
t.start();
}
#Override
public void onStop() {
super.onStop();
prefs.edit().putFloat("goldCount", goldCount).commit();
Log.d(prefs.getFloat("goldCount", 0.0f) + "derprolw", "ejwfjbrea");
}
Thread t = new Thread() {
public void onClick(View v) {
switch (v.getId()) {
case R.id.minioncentreid:
goldCount += 1.0;
prefs.edit().putFloat("goldCount", goldCount).commit();
textTotal = goldCount + " Gold";
textGoldCount.setText(textTotal);
textGoldCount.setGravity(Gravity.CENTER);
break;
case R.id.storeimageid:
LayoutInflater inflater = (LayoutInflater) MainClass.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View popupview = inflater.inflate(R.layout.storemenu, null);
final PopupWindow pw = new PopupWindow(popupview, 300, 450);
pw.showAtLocation(v, Gravity.CENTER, 0, 0);
storeDismiss = (Button) pw.getContentView().findViewById(R.id.menudismissid);
storeDismiss.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
pw.dismiss();
}
});
pw.showAsDropDown(storeClick, 0, 0);
break;
}
};
};
#Override
public void onClick(View v) {
}
}
The Thread is at Thread t = new Thread(). Does anyone one know why this happens, and how to fix it?
When you define the click listener for a view via the XML it looks for the listener in your Activity, not any random threads you may have created. Your architecture needs changing so that the onClick is in the Activity, and then that method uses the thread instead
The problem is nothing calls the onClick method of your inner Thread, so Eclipse gives you this warning.
You currently have no way to assign t as the onClickListener to any of your views. Right now you've assigned this (meaning the existing instance of the Activity) to be the listener, and so the Activity's onClick method will be called, not the thread's onClick method. You could do either of these thigns:
Define an inner class that extends Thread and implements OnClickListener, create an instance of that, and then assign the instance as the onClickListener to those views.
Put the switch statement back into the Activity's onClick method. Inside of that, where you want to do work in a background thread, create and start the Thread there.
Even those still will not work because some of the things you are trying to do in the onClick callback are things which must be done on the UI thread, so moving them to another thread will actually cause errors in your app.
This is not the sort of thing you want to move to a background thread anyway. You should use background threads for long-running operations that actually can block the UI thread, like network operations and disk I/O. If you want to understand how, when, and why to use concurrency, perhaps you should look for some good reading material (such as Concurrency in Java).
When you set your OnClickListeners in your Activity MainClass like this:
minionClick.setOnClickListener(this);
storeClick.setOnClickListener(this);
storeDismiss.setOnClickListener(this);
Then you are setting the Activity as listener and not the thread. The method that will be called when a click happens is the one at the bottom of your Activity class:
#Override
public void onClick(View v) {
}
And not the one inside your Thread. I think the part that is confusing you is the following:
When you do something like this:
Thread thread = new Thread() {
};
Then you are actually creating a whole new class - called an anonymous class - which is a subclass from Thread. So if you define a method in their then it doesn't belong to the Activity, it is actually in a completely different class.
Another thing to consider is that what you are trying to do is not a good idea anyways. What you should do is start the thread in the OnClickListener and not handle the click in a separate Thread. Try something like this:
#Override
public void onClick(View v) {
Thread thread = new Thread() {
...
};
}
Anyway it looks like an AsyncTask would be much better suited than a Thread in this case. And from what I can see in your code threading shouldn't even be necessary in this portion. You don't actually perform any complex tasks which would require running them in a separate Thread and as such any threading would just be counterproductive. The code most likely runs a lot better and smoother without any threading.

Categories