Android (Java) - What am I doing wrong?

Soldato
Joined
25 Sep 2003
Posts
3,725
Location
Manchester
I've stripped out the code I'm having issues with. Below I have the updateView which is static and below that I have a method
(spawnNotification) which takes a context (I've replaced the context I had with just the text CONTEXT). I sort of know what I need to do but after spending hours messing about with it, I've got nowhere. :o

Is there somewhere obvious I'm messing up?

TeaTimerMain.class

Code:
	public static void updateView(long millisUntilFinished) {
		if (millisUntilFinished == 0) {
			textViewShowSeek.setText("Finished!");


			TeaTimerMain.spawnNotification( CONTEXT );

			
		} 
	}

	
	@SuppressWarnings("deprecation")
	public static void spawnNotification(Context thisContext){
		NotificationManager nm = (NotificationManager) thisContext.getSystemService(Context.NOTIFICATION_SERVICE);
		@SuppressWarnings("deprecation")
		Notification notify = new Notification(android.R.drawable.stat_notify_more, "Finished", System.currentTimeMillis());
		Context context = thisContext;
		CharSequence title = "Title";
		CharSequence details = "details";
		Intent intent = new Intent(context, TeaTimerMain.class);
		PendingIntent pending = PendingIntent.getActivity(context, 0, intent, 0);
		notify.setLatestEventInfo(context, title, details, pending);
		nm.notify(0, notify);
	}
 
Last edited:
Why is updateView static and referencing textViewShowSeek (which one assumes isn't static)

UpdateView is static because the timer I'm using I could only get to work by having that as static.

I'm guessing the way I'm doing the timer is wrong.

Here's the timer code:

Code:
import android.os.CountDownTimer;

// countdowntimer is an abstract class, so extend it and fill in methods
public class MyCount extends CountDownTimer {

	public MyCount(long millisInFuture, long countDownInterval) {
		super(millisInFuture, countDownInterval);
	}

	@Override
	public void onFinish() {
		System.out.println("FINISHED!");
		 TeaTimerMain.updateView(0);
	}

	@Override
	public void onTick(long millisUntilFinished) {
		TeaTimerMain.updateView(millisUntilFinished);
		System.out.println("TICK!");
	}


}
 
If I remove static from the timer I get this :(

javaerror.jpg
 
@GeX: I've seen that example before but I didn't follow it as I think it's outdated.

@nex20: Yup, that line is pointless actually, oops.

@Scougar: See, this is where I'm getting unstuck. My main is in TeaTimerMain so that runs at the start of course. Would I then make a TeaTimerMain object to work with but then that seems confusing because I have TeaTimerMain running already.

Here's all my code:

TeaTimerMain
Code:
package com.henleyb.teatimer;

import java.util.concurrent.TimeUnit;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle;
import android.os.Vibrator;
import android.util.Log;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;

public class TeaTimerMain extends Activity implements OnSeekBarChangeListener {

	private static TextView textViewShowSeek;
	private static SeekBar seekBarTimerSet;
	public static MediaPlayer playWhistle;
	private static long userTime;
	private MyCount newTimer;
	private ToggleButton brewButton;
	static Vibrator mVibrate;
	public static TeaReadyAlert bob;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main_tea_timer);
		brewButton = (ToggleButton) findViewById(R.id.butGo);
		seekBarTimerSet = (SeekBar) findViewById(R.id.seekBarTimerSet);
		textViewShowSeek = (TextView) findViewById(R.id.tvShowSeek);
		// playWhistle = MediaPlayer.create(this, R.raw.whistle1 );
		seekBarTimerSet.setOnSeekBarChangeListener(this);

//		playWhistle.setDataSource(R.raw.whistle1);
//		playWhistle.setOnPreparedListener(this);
//		playWhistle.prepareAsync();

		// Set up and get the users preference for brew time.
		SharedPreferences userDetails = this.getSharedPreferences(
				"userdetails", MODE_PRIVATE);
		userTime = userDetails.getLong("userTime", 2000);
		updateView(userTime);

		// Set up the vibration
		mVibrate = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
		bob = new TeaReadyAlert(getApplicationContext());

		// Set up Toggle Button listener and logic
		brewButton.setOnCheckedChangeListener(new OnCheckedChangeListener() {

			public void onCheckedChanged(CompoundButton buttonView,
					boolean isChecked) {
				if (isChecked) {
					// Toggle light is off

					Log.d("ToggleCheck", "Toggle off");
					newTimer.cancel();
					mVibrate.cancel();
				} else {
					// Toggle light is on
					Log.d("ToggleCheck", "Toggle on");
					timerInit(userTime);

				}
			}

		});

		// Fire up the timer for the first launch.
		timerInit(userTime);

	}

	@Override
	public void onPause() {
		super.onPause(); // Always call the superclass method first

	}

	@Override
	public boolean onCreateOptionsMenu(android.view.Menu menu) {
		super.onCreateOptionsMenu(menu);
		MenuInflater blowUp = getMenuInflater();
		blowUp.inflate(R.menu.tea_settings_menu, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.aboutUs:
			Intent i = new Intent("com.henleyb.teatimer.ABOUT");
			startActivity(i);
			break;
		case R.id.savePrefs:
			TeaTimerMain.setDefaults(this);
			break;
		}
		return false;
	}

	@SuppressLint("DefaultLocale")
	@Override
	public void onProgressChanged(SeekBar seekBar, int progress,
			boolean fromUser) {
		if (fromUser == true) {
			userTime = progress;
			updateView(progress);
			System.out.println("Progress Changed, userTime: " + userTime);

		}

	}

	@Override
	public void onStartTrackingTouch(SeekBar seekBar) {
		if (newTimer != null) {

			newTimer.cancel();
			brewButton.setChecked(true);
		}



	}

	@Override
	public void onStopTrackingTouch(SeekBar seekBar) {
		newTimer = new MyCount(userTime, 1000);

	}

	public void timerInit(Long mSeekBarAmount) {
		if (newTimer != null && brewButton.isChecked()) {
			newTimer.cancel();
		} else {
			newTimer = new MyCount(mSeekBarAmount, 1000);
			newTimer.start();
		}
	}

	public static void setDefaults(Context userPrefs) {
		// fired by button on the Main View

		SharedPreferences userDetails = userPrefs.getSharedPreferences(
				"userdetails", MODE_PRIVATE);
		Editor edit = userDetails.edit();
		edit.clear();
		edit.putLong("userTime", userTime);
		// edit.putString("password", txtPass.getText().toString().trim());
		edit.commit();
		Toast.makeText(
				userPrefs,
				"Your ideal brew time of " + textViewTime(userTime)
						+ " has been saved.", Toast.LENGTH_LONG).show();
	}

	// converts milliseconds to time for display
	@SuppressLint("DefaultLocale")
	static String textViewTime(long convertVar) {
		String formattedVar;
		formattedVar = String.format(
				"%d min %d sec",
				TimeUnit.MILLISECONDS.toMinutes(convertVar),
				TimeUnit.MILLISECONDS.toSeconds(convertVar)
						- TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS
								.toMinutes(convertVar)));
		return formattedVar;
	}

	public void onPrepared(MediaPlayer player) {
		playWhistle.start();
	}

	public void updateView(long millisUntilFinished) {
		if (millisUntilFinished == 0) {
			textViewShowSeek.setText("Finished!");

			shaker();

			// Pop up box to be implemented
			// bob.show(this, "test");


			alertbox("Hello", "hello");

			
		} else {
			if (mVibrate != null) {
				mVibrate.cancel();
			}

			textViewShowSeek.setText(String
					.valueOf(textViewTime(millisUntilFinished)));
			seekBarTimerSet.setProgress((int) millisUntilFinished);
		}
	}

	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
	public static void shaker() {

		if (mVibrate.hasVibrator()) {
			System.out.println("has vibrator");
			mVibrate.vibrate(new long[] { 0, 500, 1000, 1000, 1000 }, 0);
		}

	}
	
	@SuppressWarnings("deprecation")
	
		protected void alertbox(String title, String mymessage)
		   {
		   new AlertDialog.Builder(this)
		      .setMessage(mymessage)
		      .setTitle(title)
		      .setCancelable(true)
		      .setNeutralButton(android.R.string.cancel,
		         new DialogInterface.OnClickListener() {
		         public void onClick(DialogInterface dialog, int whichButton){}
		         })
		      .show();
		   }
		// see http://androidsnippets.com/display-an-alert-box
	
}

Code:
package com.henleyb.teatimer;

import android.os.CountDownTimer;

// countdowntimer is an abstract class, so extend it and fill in methods
public class MyCount extends CountDownTimer {

	public MyCount(long millisInFuture, long countDownInterval) {
		super(millisInFuture, countDownInterval);
	}

	@Override
	public void onFinish() {
		System.out.println("FINISHED!");
		 TeaTimerMain.updateView(0);
	}

	@Override
	public void onTick(long millisUntilFinished) {
		TeaTimerMain.updateView(millisUntilFinished);
		System.out.println("TICK!");
	}


}

Thinking out loud; I guess maybe I should have main to set things up but then have another class for my updating. I guess it would then follow having an MVC type layout which would make sense more, leaving the TeaTimerMain to be the place where it creates the timer object and also an update view object? Would I then need handlers though? Aaargh!
 
Last edited:
After going away and having a breather from this I'm coming back to have another go. :D

I'm trying to figure out, using an Object orientated approach, how I should really be putting my Tea Timer together?

I have a timer object but should I also have a TeaTimerMain object that creates itself on the onCreate method? The TeaTimerMain object could then interact with the timer as neither would then be static? I'm struggling with the top down view of how it should be laid out and if my TeaTimerMain object should interrogate the timer (a while loop??) or if the timer should tell my main object when it's done (through onTick and onFinish etc)? What's the correct way that objects talk to each other and how to know if an object even exists for another one to talk too? :confused:

Thanks for the help so far, I don't think i'm a million miles off from being able to get this done but at the moment I've got a bit of a confusing mental block.
 
Last edited:
Thanks guys, I missed that there were replies here. I learnt a lot with this app and it's called "Cuppa - Tea Timer" on Play if you wanted to see its final form! :) (https://play.google.com/store/apps/...51bGwsMSwyLDEsImNvbS5oZW5sZXliLnRlYXRpbWVyIl0.)

I agree that I should have gone about it differently. I sort of bumbled through that. I've learnt a lot more about objects now and how to use them better. I'm still confused by a lot of things, just waiting for something to click in my head but getting there!

I thought trying out lists would be a simple next step, turns out I find those damn confusing too! :mad:

I've bought the head first java book which seems pretty good. I'll stick with that and try to learn as much as I can using that and lynda.com as well as treehouse.com.
 
Last edited:
Back
Top Bottom