I am implementing a simple render view class for Android extending SurfaceView. My main activity class includes an infinite while loop for other operations.
However, the app shows a black screen when main activity is in the infinite loop. As far as I know, main activity and surface view classes have their own separate threads, so surface view class should keep rendering even when main activity class is busy. The app works just fine when I prevent infinite loop by setting 'running' boolean variable false in the code.
What might be the reason of that surface view class stops rendering when my main activity is in an infinite loop?
My main activity and surface view classes are as follows:
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
public class MainActivity extends Activity{
RenderSurfaceView renderView;
public boolean running = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate ( savedInstanceState );
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
renderView = new RenderSurfaceView(this);
setContentView(renderView);
loop();
}
public void loop(){
running = true;
while(running){
}
}
protected void onResume() {
super.onResume();
renderView.resume();
}
protected void onPause() {
super.onPause();
renderView.pause();
}
}
This my render class that extends SurfaceView:
import java.util.Random;
import android.content.Context;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class RenderSurfaceView extends SurfaceView implements Runnable{
Thread renderThread = null;
SurfaceHolder holder;
volatile boolean running = false;
Random r = new Random();
public RenderSurfaceView(Context context) {
super(context);
holder = getHolder();
}
public void resume() {
running = true;
renderThread = new Thread(this);
renderThread.start();
}
public void run() {
while(running) {
if(!holder.getSurface().isValid())
continue;
render();
}
}
private void render(){
Canvas canvas = holder.lockCanvas();
canvas.drawRGB(r.nextInt(255), r.nextInt(255), r.nextInt(255));
holder.unlockCanvasAndPost(canvas);
}
public void pause() {
running = false;
while(true) {
try {
renderThread.join();
} catch (InterruptedException e) {
// retry
}
}
}
}
This
does not show the view immediately. Instead it has to go through a layout traversal first, which doesn't happen immediately but asynchronously to the
Activity
lifecycle methods, and it happens on the main thread. So running an infinite loop at the end ofonCreate()
prevents the layout traversal of the view hierarchy, which means yourSurfaceView
will never be shown.In theory you could experiment with starting your infinite loop delayed using a
Handler
, for experimental purposes maybe. In general infinite loops on the main thread are a super bad idea and I can't see a reason why you would want to do this, apart from experiments maybe.My self-answer to this question Modifying views in AsyncTask doInBackground() does not (always) throw exception has a bit more detail on what's going on behind the scenes. The question is not directly related to what you're asking here, but the background is the same I believe.