# [ Android ] Activity ändern



## Maxim6394 (2. Mai 2012)

ich versuche seit tagen die verfluchte contentview bei meiner app zu ändern, im anderen thread hab ich schon geschrieben dass die neue contentview dann immer null als canvas hat, absolut keine ahnung wieso.
jetzt versuche ich die verdammte activity zu ändern, das klappt aber auch nicht, es gibt immer nullpointer exception.
im anhang ist ein screenshot.
ich rufe aus view die changeActivity funktion auf, es klappt einfach überhaupt nicht.
hat jemand eine idee?


----------



## schlingel (2. Mai 2012)

Das Problem ist, dass du dir das Activity-Objekt selbst erzeugst. Das solltest du nicht händisch machen, denn dann wird - wie in deinem Fall - leicht darauf vergessen ein bestimmtes Attribut zu setzen. Du erzeugst dir hier zwar eine Activity setzt aber deren Context-Objekt nicht.

Der arme Intent versucht jetzt aus dem Activity-Objekt a das Context-Objekt zu bekommen und fliegt böse auf die Schnauze weil dieses null ist.

Richtig instanzierst du so deinen Intent:

```
public void changeActivity() {
  Intent i = new Intent(this /* Application Context von aktiver/aktueller Activity */, Activity02.class);
  startActivityForResult(i, 0);
}
```

Dann erzeugt dir das System das Activity-Objekt oder holt ein bestehendes in den Vordergrund - je nachdem - und zeigt es dir an.

Wie gesagt, wer gegen das Framework kämpft anstatt sich darauf einzulassen, dass es etwas anders funktioniert als gewohnt bekommt man solche Fehler.


----------



## Maxim6394 (2. Mai 2012)

jetzt krieg ich nur

```
05-02 10:50:36.467: E/AndroidRuntime(2168): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{my.testproject/my.testproject.Activity02}: java.lang.IllegalAccessException: access to class not allowed
```

in die AndroidManifest.xml hab ichs übrigens auch eingetragen:
[XML]  <activity
            android:name=".Activity02">
                 </activity>[/XML]


----------



## schlingel (2. Mai 2012)

Activity02 muss eine public Klasse sein. 
Activity02 muss im AndroidManifest.xml eingetragen sein. _Check_

Also kann es nur die package sichtbare Activity02-Klasse sein. => Lager es in ein Activity02.java File aus und gut ist.


----------



## Maxim6394 (2. Mai 2012)

so scheint es endlich zu funktionieren, jedenfalls im testprojekt. dann muss ich wohl dutzende dateien für activities haben, eine pro level.

das zerstören der alten activity geht nicht so richtig. ich ruf nach dem wechsel 

```
((Activity) getContext()).finish();
```
 auf, aber der zurück button bringt mich nicht zum desktop.

edit: okay das geht jetzt auch. hab in der xml android:noHistory="true" gesetzt.


----------



## schlingel (2. Mai 2012)

Verwende:

```
finish();
```

Das reicht vollkommen. Wo kommst du denn hin wenn du mit finish alles zerstörst? Außerdem: Was genau möchtest du denn bauen? Vielleicht geht's einfacher als immer mit neuen Activites.


----------



## Maxim6394 (2. Mai 2012)

ich bin seit monaten an nem sidescroller dran, ich bereits eine level klasse erstellt wo die levels korrekt aus einer xml geladen werden und so, ich muss halt zwischen den levels wechseln.


----------



## Maxim6394 (2. Mai 2012)

ich hab jetzt versucht das mit den gameviews auf die app zu übertragen, es läuft trotzdem aus unerklärlichen gründen falsch.
ich hab für jedes level eine klasse die die klasse gameview extendet.
für jedes level hab ich dann eine activity die als contentview die jeweilige level klasse hat.
in der klasse gameview hab ich die methode für das wechseln:

```
public void changeActivity(Class c)
	{
		loop.running=false;
		 Intent i = new Intent(getContext(),	c);
		 getContext().startActivity(i);
		 context.finish();
		
	}
```

wenn ich dann vom hauptmenü, was auch gameview extendet, diese methode aufrufe, läd es das level und zeigt es kurz an, danach reagiert gar nichts mehr.
ich mach also "force close" und dann kommt nochmal das gleiche level, und da reagiert auf einmal alles.
das level wird irgendwie mehrmals geladen, weil ich auch mehrmals den sound höre der beim starten abgespielt wird.
hier die normale activity die zuerst gestartet wird:

```
public class Android01Activity extends Activity {
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(new MainMenu(this));
	}
}
```
und die andere die später aufgerufen wird:

```
public class Activity_Level01 extends Android01Activity { 
	  public void onCreate(Bundle savedInstanceState) {
	        super.onCreate(savedInstanceState);       
                 Level_01 l01=new Level_01(this);
	         setContentView(l01);
	    }
}
```

außerdem kommt noch die meldung:
05-02 12:30:53.777: WARN/ActivityManager(75): Launch timeout has expired, giving up wake lock!

hab jetzt rausgefunden dass scheinbar das verdammte level 3 mal geladen wird bevor es endlich angezeigt wurde, keine ahnung wieso. ich hab alles überprüft, eine instanz des levels wird nur ein einziges mal erstellt.


----------



## schlingel (2. Mai 2012)

Wie sieht denn so eine Level-View aus? Ist das ein Element dass dann auf's Canvas zeichnet oder sind das im XML definierte Layouts?


----------



## Maxim6394 (2. Mai 2012)

ich poste einfach mal die gesamte GameView klasse:

```
public class GameView extends SurfaceView {
	int groundY = 0;
	SurfaceHolder holder;
	GameLoop loop;
	Bitmap backGround;
	Player player;
	int bgColor = Color.BLACK;
	HeadUpDisplay hud;
	Sounds sounds;
	GameView nextLevel = null;
	Sprite exit = null;

	// ArrayList<GroundBlock> blocks = new ArrayList<GroundBlock>();
	List<Sprite> sprites = new CopyOnWriteArrayList<Sprite>();
	List<Sprite> bgSprites = new CopyOnWriteArrayList<Sprite>();
	GameView view;
	Activity context;
	public int x = 0, y = 0, bgx = 0, bgy = 0, bgSpriteX = 0, bgSpriteY = 0;
	DisplayMetrics metrics;

	int normalUnit = 192, smallUnit = 96;

	public GameView(Context context) {
		super(context);

		this.context = (Activity) context;

		hud = new HeadUpDisplay(this);

		metrics = new DisplayMetrics();
		this.context.getWindowManager().getDefaultDisplay().getMetrics(metrics);
		normalUnit = (int) (128 * metrics.density);
		smallUnit = (int) (64 * metrics.density);
		view = this;
		holder = this.getHolder();
		addCallback();
		// TODO Auto-generated constructor stub
	}

	public void changeActivity(Class c) {
		loop.running = false;
		context.finish();
		Intent i = new Intent(getContext(), c);
		getContext().startActivity(i);
		// ((Activity) getContext()).finish();

	}

	public void addCallback() {
		holder.addCallback(new Callback()

		{

			public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
					int arg3) {
				// TODO Auto-generated method stub

			}

			public void surfaceCreated(SurfaceHolder holder) {
				sounds = new Sounds(getContext());
				player = new Player(view);

				hud.makeInterface();

				createLevel();

				loop = new GameLoop(view);
				loop.start();
				// saveGame();

			}

			public void surfaceDestroyed(SurfaceHolder holder) {

			}

		}

		);

	}

	public int playSound(int sound, int... settings) {

		int id = -1;
		int loopMode = 0;
		int volume = 1;

		if (settings.length > 0) {
			loopMode = settings[0];

			if (settings.length > 1) {
				volume = settings[1];
			}
		}

		if (sound != -1) {

			id = sounds.sp.play(sound, volume, volume, 0, loopMode, 1);

			return id;
		}
		return -1;
	}

	public void saveGame() {

		try {
			FileOutputStream fos = context.openFileOutput("savegame",
					Context.MODE_PRIVATE);

			ObjectOutputStream os;
			try {
				os = new ObjectOutputStream(fos);
				PrintWriter w = new PrintWriter(os);
				w.write(player.hp + "\n");

				os.writeObject(player.ammo);
				w.write("\n");

				os.close();
				w.close();
				fos.close();

			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		try {
			FileInputStream fis = context.openFileInput("savegame");

			int i;
			try {
				while ((i = fis.read()) != -1) {
					Log.d("reading", String.valueOf(i));
				}

				fis.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void moveLevel(int x, int y) {

		this.x += x;
		this.y += y;

		if (backGround != null) {
			if (bgx <= -backGround.getWidth()) {
				bgx = 0;
			}

			if (bgx >= backGround.getWidth()) {
				bgx = 0;
			}

			if (bgy <= -backGround.getHeight()) {
				bgy = 0;
			}

			if (bgy >= backGround.getHeight()) {
				bgy = 0;
			}

		}

		if (this.y < -300) {

			view.post(new Runnable() {

				public void run() {
					// change level
				}

			});

		}
		for (Sprite s : sprites) {

			s.x += x / ((float) (s.distance) / 10);
			s.y += y / ((float) (s.distance) / 10);
			s.updateBounds();

		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {

		if (event.getAction() == MotionEvent.ACTION_UP)

		{
			hud.onRelease();
		}

		else {

			hud.pointerX = (int) event.getX() - x;
			hud.pointerY = (int) (event.getY() - y) - groundY;

			if (event.getAction() == MotionEvent.ACTION_DOWN) {
				for (int i = 0; i < hud.hud.size(); i++) {
					HudElement e = hud.hud.get(i);

					for (int h = 0; h < hud.hud.get(i).bounds.length; h++) {

						Rect r = hud.hud.get(i).bounds[h];

						if (r != null
								&& intersects((int) event.getX(),
										(int) event.getY(), e.bounds[h])) {
							e.onTouchEvent(event, h);
							break;
						}

					}
				}
			}

		}

		return true;
	}

	public boolean intersects(int x, int y, Rect r) {

		if (x >= r.left && x <= r.right && y >= r.top && y <= r.bottom) {
			return true;

		}

		return false;
	}

	public void createLevel() {

	}

	public void updateGame() {
		player.update();

		for (Sprite s : sprites) {

			if (s instanceof LevelExit) {
				if (player.bounds.intersect(s.bounds)) {

					// **** changeactivity

				}
			}

			if ((s instanceof Bullet) || s.x + s.width >= 0
					&& s.x <= this.getWidth() && s.y + s.height >= 0
					&& s.y <= getHeight()) {
				s.update();
			}

		}
	}

	public void onDraw(Canvas canvas) {

		if (canvas != null) {

			canvas.drawColor(bgColor);

			if (backGround != null) {

				// Rect src=new
				// Rect(0,0,backGround.getWidth(),backGround.getHeight());
				// Rect dest=new Rect(0,0, backGround.getWidth(),
				// backGround.getHeight());

				Rect src = new Rect(0, 0, backGround.getWidth(),
						backGround.getHeight());
				for (int i = -backGround.getWidth(); i < getWidth()
						+ backGround.getWidth(); i += backGround.getWidth()) {
					for (int h = -backGround.getHeight(); h < getHeight()
							+ backGround.getHeight(); h += backGround
							.getHeight()) {

						Rect dest = new Rect(i + bgx, h + bgy, i + bgx
								+ backGround.getWidth(), h + bgy
								+ backGround.getHeight());
						canvas.drawBitmap(backGround, src, dest, null);

					}
				}

			}

			int layerCount = 0;

			for (Sprite s : sprites) {

				if (s instanceof LevelExit) {
					canvas.drawRect(s.bounds, new Paint());
				}

				if (s.layer > layerCount) {
					layerCount = s.layer;
				}

			}

			if (player.layer > layerCount) {
				layerCount = player.layer;
			}

			for (int i = 0; i <= layerCount; i++) {
				if (player.layer == i) {
					player.drawWeapon(canvas);
					player.drawBitmap(canvas, player.bmp);
				}

				for (Sprite s : sprites) {
					if (s.layer == i) {
						if (s.currentGun != null) {
							s.drawWeapon(canvas);
						}

						if (s.bmp != null && s.x + (s.width * s.bmpScale) >= 0
								&& s.x <= this.getWidth()) {
							s.drawBitmap(canvas, s.bmp);

						}

					}

				}
			}

			hud.onDraw(canvas);

		}

	}

}
```

die levels sind nur aus der klasse abgeleitet und überschreiben die createLevel() methode.
da wird die xml geladen und für jedes element ein sprite erstellt, jeweils mit den eigenschaften aus der xml. die sprites kommen dann alle in die sprites list.


----------

