Hur lyfter jag ut koden i en egen klass?

Diskussion i 'Frågor, support och diskussion' startad av xtreme, 10 feb 2012.

  1. xtreme

    xtreme Adult Droid Medlem

    Blev medlem:
    12 apr 2010
    Inlägg:
    516
    Mottagna gillanden:
    13

    MINA ENHETER

    Jag är ny på programmering och leker med sensor för Android nu. Skulle vilja flytta ut allt som har med sensorn att göra till en egen klass vilket jag förmodar är en bra idé för att inte ha så mycket i "huvudklassen" där "onCreate" finns. Dock får jag inte det att fungera. Allt som har med sensorn att göra (första koden nedan) skulle jag vilja ha i en klass som heter ex MySensor.java och sedan när man kör programmet anropas den från onCreate.

    All kod för sensorn som nu finns i en klass med en OnCreate

    Kod:
    import android.app.Activity;
    import android.content.Context;
    import android.hardware.Sensor;
    import android.hardware.SensorEvent;
    import android.hardware.SensorEventListener;
    import android.hardware.SensorManager;
    import android.os.Bundle;
    import android.widget.Toast;
    
    public class AlarmActivity extends Activity {
    	/* The connection to the hardware */
    	private SensorManager mySensorManager;
    
    	/* The SensorEventListener lets us wire up to the real hardware events */
    	private final SensorEventListener mySensorEventListener = new SensorEventListener() {
    
    		public void onSensorChanged(SensorEvent se) {
    			/* we will fill this one later */
    		}
    
    		public void onAccuracyChanged(Sensor sensor, int accuracy) {
    			/* can be ignored in this example */
    		}
    	};
    
    	/* Here we store the current values of acceleration, one for each axis */
    	private float xAccel;
    	private float yAccel;
    	private float zAccel;
    
    	/* And here the previous ones */
    	private float xPreviousAccel;
    	private float yPreviousAccel;
    	private float zPreviousAccel;
    
    	/* Used to suppress the first shaking */
    	private boolean firstUpdate = true;
    
    	/* What acceleration difference would we assume as a rapid movement? */
    	private final float shakeThreshold = 1.5f;
    
    	/* Has a shaking motion been started (one direction) */
    	private boolean shakeInitiated = false;
    
    	@Override
    	public void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.main);
    		mySensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); // (1)
    		mySensorManager.registerListener(mySensorEventListener,
    				mySensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
    				SensorManager.SENSOR_DELAY_NORMAL); // (2)
    	}
    
    	public void onSensorChanged(SensorEvent se) {
    		updateAccelParameters(se.values[0], se.values[1], se.values[2]); // (1)
    		if ((!shakeInitiated) && isAccelerationChanged()) { // (2)
    			shakeInitiated = true;
    		} else if ((shakeInitiated) && isAccelerationChanged()) { // (3)
    			executeShakeAction();
    		} else if ((shakeInitiated) && (!isAccelerationChanged())) { // (4)
    			shakeInitiated = false;
    		}
    	}
    
    	/* Store the acceleration values given by the sensor */
    	private void updateAccelParameters(float xNewAccel, float yNewAccel,
    			float zNewAccel) {
    		/*
    		 * we have to suppress the first change of acceleration, it results from
    		 * first values being initialized with 0
    		 */
    		if (firstUpdate) {
    			xPreviousAccel = xNewAccel;
    			yPreviousAccel = yNewAccel;
    			zPreviousAccel = zNewAccel;
    			firstUpdate = false;
    		} else {
    			xPreviousAccel = xAccel;
    			yPreviousAccel = yAccel;
    			zPreviousAccel = zAccel;
    		}
    		xAccel = xNewAccel;
    		yAccel = yNewAccel;
    		zAccel = zNewAccel;
    	}
    
    	/*
    	 * If the values of acceleration have changed on at least two axises, we are
    	 * probably in a shake motion
    	 */
    	private boolean isAccelerationChanged() {
    		float deltaX = Math.abs(xPreviousAccel - xAccel);
    		float deltaY = Math.abs(yPreviousAccel - yAccel);
    		float deltaZ = Math.abs(zPreviousAccel - zAccel);
    		return (deltaX > shakeThreshold && deltaY > shakeThreshold)
    				|| (deltaX > shakeThreshold && deltaZ > shakeThreshold)
    				|| (deltaY > shakeThreshold && deltaZ > shakeThreshold);
    	}
    
    	private void executeShakeAction() {
    		/*
    		 * Save the cheerleader, save the world or do something more sensible...
    		 */
    		
    		Toast.makeText(AlarmActivity.this,
    				"Aktiverat", Toast.LENGTH_SHORT).show();
    		
    	}
    
    }
    
    Exempel på hur jag skulle vilja ha det som inte fungerar:

    Mittprogram.java dvs startklassen med OnCreate som anropar klassen och metoden startListening för att köra sensorn i MySensor.java

    Kod:
    MySensor s = new MySensor();
    
    @Override
    	public void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.main);
    s.startListening(); //finns som metod i MySensor.java 
    	}
    
    MySensor.java
    Samma kod som överst men har flyttat koden som finns i onCreate till en ny i metod som heter startListening.

    Kod:
    public void startListening() {
    		 // (1)
    		mySensorManager.registerListener(mySensorEventListener,
    				mySensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
    				SensorManager.SENSOR_DELAY_NORMAL); // (2)
    		
    	} 
    

    Eclipse klagar på att "getSystemService" är odefinierad för typen MySensor i klassen MySensor.Java. Om jag ändrar klasshuvudet i MySensor.java till "public class MySensor extends Activity" får jag inga felmeddelande men då krachar mitt program direkt efter när det startar i emulatorn. Förmodar man inte får ha två "extends Activity".

    Hur gör jag?
     
  2. e7andy

    e7andy Professional Droid Hedersmedlem

    Blev medlem:
    14 okt 2009
    Inlägg:
    2 349
    Mottagna gillanden:
    835
    Telefon:
    Huawei P10 Plus

    MINA ENHETER

    Telefon:
    Huawei P10 Plus
    Telefon 2:
    Nexus 5
    Telefon 3:
    ADP1
    Övrigt:
    LG G Watch R, ChromeCast
    Ta först reda på från vilken klass getSystemService() kommer från. Eftersom den finns tillgänglig för att subklasser av Activity så börjar du kolla där: http://developer.android.com/reference/android/app/Activity.html
    Där ser du att den kommer från Context.

    För att din nya klass (MySensor) ska kunna anropa getSystemService() så behöver den tillgång till Context eller en subklass av den, t.ex. en Activity.

    Exakt hur din nya klass får tillgång till Context går att göra på många sätt. Frågan är vad som är vettigast: Skicka in din activity i konstruktorn eller skicka in aktuell Context, skicka in den i metodanropet, skapa en statisk metod som ger dig contexten...

    Det finns mängder med diskussioner om Context och hur man bäst accessar den:
    http://stackoverflow.com/questions/3572463/what-is-context-in-android
    http://stackoverflow.com/questions/2002288/static-way-to-get-context-on-android
    m.fl.

    Observera att det finns 2 Contexter. En Application Context och en current Context. Vilken du väljer beror på livscykeln för vad du vill uppnå. Läs mer här:
    http://developer.android.com/reference/android/content/ContextWrapper.html#getApplicationContext()

    Personligen hade jag nog skickat in en SensorManager i konstruktorn till MySensor, dvs. inte hållt på och grejat med Contexter och sånt. Det känns mest naturligt för mig. Din sensor får tillgång till den manager som den behöver för att göra sitt jobb.