Android - Displaying ExoPlayer in a circle - android

I am trying to display a ExoPlayerView inside a circle, overlaying another ExoPlayer (picture in picture):
I have tried putting the 2nd player inside a frame with rounded corners (both this answer and this one) but the player will always escape the parent frame and draw the video's full rectangle.
I found this solution which uses a GLSurfaceView, however this solution uses the classic MediaPlayer and not ExoPlayer.

For the one that's supposed to have rounded corners, you can set in the layout XML file this about it:
app:surface_type="texture_view"
Found this solution here.
The drawback of using this is mainly performance and battery usage (written here) :
Should I use SurfaceView or TextureView? SurfaceView has a number of
benefits over TextureView for video playback:
Significantly lower power consumption on many devices. More accurate
frame timing, resulting in smoother video playback. Support for secure
output when playing DRM protected content. SurfaceView should
therefore be preferred over TextureView where possible. TextureView
should be used only if SurfaceView does not meet your needs. One
example is where smooth animations or scrolling of the video surface
is required prior to Android N (see How do I get smooth
animation/scrolling of video?). For this case, it’s preferable to use
TextureView only when SDK_INT is less than 24 (Android N) and
SurfaceView otherwise.

You need to create a custom container for it. try this and put you player view in it.
public class RoundFrameLayout extends FrameLayout {
private final Path clip = new Path();
private int posX;
private int posY;
private int radius;
public RoundFrameLayout(Context context) {
this(context,null);
}
public RoundFrameLayout(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public RoundFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// We can use outlines on 21 and up for anti-aliased clipping.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setClipToOutline(true);
}
}
#Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
posX = Math.round((float) width / 2);
posY = Math.round((float) height / 2);
// noinspection NumericCastThatLosesPrecision
radius = (int) Math.floor((float) Math.min(width, height) / 2);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setOutlineProvider(new OutlineProvider(posX, posY, radius));
} else {
clip.reset();
clip.addCircle(posX, posY, radius, Direction.CW);
}
}
#Override
protected void dispatchDraw(Canvas canvas) {
// Not needed on 21 and up since we're clipping to the outline instead.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
canvas.clipPath(clip);
}
super.dispatchDraw(canvas);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
// Don't pass touch events that occur outside of our clip to the children.
float distanceX = Math.abs(event.getX() - posX);
float distanceY = Math.abs(event.getY() - posY);
double distance = Math.hypot(distanceX, distanceY);
return distance > radius;
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
static class OutlineProvider extends ViewOutlineProvider {
final int left;
final int top;
final int right;
final int bottom;
OutlineProvider(int posX, int posY, int radius) {
left = posX - radius;
top = posY - radius;
right = posX + radius;
bottom = posY + radius;
}
#Override
public void getOutline(View view, Outline outline) {
outline.setOval(left, top, right, bottom);
}
}
}

Related

How can I prevent my custom view drawing from being clipped by the view bounds?

I'm attempting to extend ImageView and add a shadow. I'm running into a problem where the shadow is being clipped by the view bounds and looks quite bad:
I've attempted to set the width/height via LayoutParams programmatically as well as trying different XML properties like android:adjustViewBounds, but there is no change in the display. Similarly, setting a android:layout_margin is ineffective in preventing the shadow from being clipped.
Can anyone help me figure out how to avoid this clipping? I'm sure there is something obvious I'm overlooking here.
Update:
My code is very specific at this time to exactly one case: I'm trying to draw a circle "shadow" underneath a circle bitmap. It is obvious that the view bounds are causing the clipping, but I have not been able to find a solution that will allow me to expand the view bounds.
It has been claimed on #android-dev that my math is simply wrong. I am accounting for screen density, which is a common problem. I have triple checked my math on all counts and cannot find where it might be wrong.
Initially, on an xxhdpi screen, density 3.0, the 56dp image is exactly 168px wide and 168px high. After adding 2dp to the width and height to account for the offset, the layoutParams have width=174 and height=174.
My basic approach is to let the super ImageView do its thing and draw the bitmap specified in xml and all I want to do is draw a little something additionally. Is this approach fundamentally flawed?
I use the largest of width or height in onLayout to determine what the radius of my shadow circle should be: radius = Max(width, height) / 2. I draw a circle with this radius and center point at (Cx, Cy) where Cx is the midpoint of the width plus a x-offset and Cy is the midpoint of the height plus a y-offset to create the shadow effect. I draw the additional circle using a canvas to a bitmap and later in onDraw I place my circle on the canvas before allowing the ImageView super onDraw to take care of the source bitmap.
Additionally, in my onLayout I attempt to account for the x- and y-offset distances and add those to my view's width and height via LayoutParams, but no change in the size of the view is evidenced when the view is drawn.
Here is the code that I'm using: https://gitlab.com/dm78/ImageViewWithShadowExample/
Here is the relevant code:
activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<dm78.example.imageviewwithshadowexample.CustomShadowImageView
android:id="#+id/circle"
android:layout_gravity="center"
android:src="#drawable/circle"
android:layout_margin="16dp"
android:layout_width="56dp"
android:layout_height="56dp"/>
</FrameLayout>
CustomShadowImageView.java
package dm78.example.imageviewwithshadowexample;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Build;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.widget.FrameLayout;
import android.widget.ImageView;
public class CustomShadowImageView extends ImageView {
public static final String TAG = CustomShadowImageView.class.getSimpleName();
public static final float SHADOW_RADIUS_DP = 3f;
public static final float SHADOW_X_OFFSET_DP = 2f;
public static final float SHADOW_Y_OFFSET_DP = 2f;
private Paint mPaint;
private float mShadowRadius;
private float radius;
private float cx;
private float cy;
private float mShadowXOffset;
private float mShadowYOffset;
private Bitmap mShadowBitmap;
private FrameLayout.LayoutParams layoutParams;
private boolean expanded;
public CustomShadowImageView(Context context) {
super(context);
init();
}
public CustomShadowImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomShadowImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
Log.d(TAG, "init " + this.hashCode());
DisplayMetrics dm = getContext().getResources().getDisplayMetrics();
mShadowRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, SHADOW_RADIUS_DP, dm);
mShadowXOffset = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, SHADOW_X_OFFSET_DP, dm);
mShadowYOffset = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, SHADOW_Y_OFFSET_DP, dm);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
//noinspection deprecation
int shadowColor = getContext().getResources().getColor(R.color.shadow);
mPaint.setColor(shadowColor);
expanded = false;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.d(TAG, String.format("onMeasure %d w: %d, h: %d", this.hashCode(), MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)));
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Log.d(TAG, String.format("onLayout %d changed: %b, l: %d, t: %d, r: %d, b: %d", this.hashCode(), changed, left, top, right, bottom));
super.onLayout(changed, left, top, right, bottom);
if (changed) {
if (!expanded) {
layoutParams = (FrameLayout.LayoutParams) getLayoutParams();
layoutParams.width = (int) (layoutParams.width + mShadowXOffset);
layoutParams.height = (int) (layoutParams.height + mShadowYOffset);
expanded = true;
}
cx = (right - left) / 2 + mShadowXOffset;
cy = (bottom - top) / 2 + mShadowYOffset;
boolean widthGreater = (right - left) > (bottom - top);
radius = (widthGreater ? right - left : bottom - top) / 2;
if (mShadowBitmap == null) {
Bitmap bitmap = Bitmap.createBitmap(right - left, bottom - top, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawCircle(cx, cy, radius, mPaint);
if (Build.VERSION.SDK_INT >= 17 && !isInEditMode()) {
RenderScript rs = RenderScript.create(getContext());
Allocation input = Allocation.createFromBitmap(rs, bitmap, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
Allocation output = Allocation.createTyped(rs, input.getType());
ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
script.setRadius(mShadowRadius);
script.setInput(input);
script.forEach(output);
output.copyTo(bitmap);
}
mShadowBitmap = bitmap;
}
}
}
#Override
protected void onDraw(Canvas canvas) {
Log.d(TAG, "onDraw " + this.hashCode());
canvas.drawBitmap(mShadowBitmap, mShadowXOffset, mShadowYOffset, null);
super.onDraw(canvas);
}
}
By default, Views are only allowed by their parent to draw within their bounds and not beyond.
You have two options:
Either you add some padding to your Imageview to enlarge its bounds
instead of using layout_margin and you draw within these bounds.
Either you disable the child clipping behavior by setting android:clipChildren="false" to your FrameLayout.
If the cause is the view parent's padding, add the following line to the parent xml element:
android:clipToPadding="false"
android:clipChildren="false" in the parent layout worked for me

Custom timeline for View-Animation?

I'd like to be able to create an arbitrary input for time into a standard Android animation. Instead of an animation running for 1 second, I want for instance the input to be a coordinate from user touch input. This way I could for instance create a circle motion of object A when the position in the circular motion is defined by a linear input on slide A.
Crude illustration:
Now I'm thinking this could be achieved with defining the translation animation in XML just as with regular animations under /res/anim, but overriding the time input to come from a user input control instead. It minght also be done with a custom interpolator, I'm not sure. I don't what a set start and end time of the animation, in any case.
Anyone have any suggestions on how to achieve this?
edit: To further answer a couple of the comments: Think if it as the user slides/drags the blue dot. No interpolation between the input occurs. As soon as the user lifts the finger, the "animation" stops.
If I understand correctly you need some sort of 'rigging' - Defining a movement of one element as a function of another. In your case this function needs to transform the the linear position into a circular position.
There is no animation involved - When the user moves the blue circle, the red one is moved accordingly.
You should register for callbacks for the blue circle movement (i.e. onTouchEvent, or a seekBar's on change, depending on how you implement your 'bar'). Then you calculate the new position of the red circle and then you put it there.
Here's a simple working example of a custom view that draws two circles according to a given percentValue. I tested using s simple SeekBar and it works:
public class CanvasView extends View {
private int centerX = 0;
private int centerY = 0;
private int radius = 0;
private final int handleRadius = 25;
private final Paint circlePaint = new Paint();
private final Paint handlePaint = new Paint();
private float percentValue = 0f;
public CanvasView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public CanvasView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CanvasView(Context context) {
super(context);
init();
}
private void init() {
circlePaint.setColor(Color.BLACK);
handlePaint.setColor(Color.RED);
}
// Call this whenever the value of that linear bar is changed - so when the user moves his finger etc.
public void setValue(float percentage) {
this.percentValue = percentage;
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// this is the main circle
canvas.drawCircle(centerX, centerY, radius, circlePaint);
// calculate the angle based on the percentage of the linear movement (substracting (pi/2) so the zero value is on top)
double angle = (percentValue / 100) * (2 * Math.PI) - Math.PI / 2;
// sin and cos to calculate the position of the smaller circle - the 'handle'
float handleX = centerX + (float) (radius * Math.cos(angle));
float handleY = centerY + (float) (radius * Math.sin(angle));
// drawing the circle
canvas.drawCircle(handleX, handleY, handleRadius, handlePaint);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// choose whatever values you want here, based on the view's size:
centerX = w / 2;
centerY = h / 2;
radius = w / 3;
}
}

Moving and rotating a triangle simultaneously around a circle: Android [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I have a triangle image whose one edge is always in the same direction as the circle.
This image has to be moved around the circle based on user swipe/drag. So, it has to both rotate (so that it's edge is in same direction as the circle) and at the same time revolve around the circle.
How to implement this feature?
UPDATE: My custom View is as follows:
public class ThermoView extends FrameLayout{
private ImageView mThermoBgrd;
private ImageView mCurTempArrow;
public static final int THEMROSTAT_BACKGROUND = 0;
public static final int THEMROSTAT_CURR_TEMP = 1;
public ThermostatView(Context context, AttributeSet attrs) {
super(context, attrs);
mThermoBgrd = new ImageView(context);
mThermoBgrd.setImageResource(R.drawable.circle_icon);
addView(mThermoBgrd, ThermostatView.THEMROSTAT_BACKGROUND);
mCurTempArrow = new ImageView(context);
mCurTempArrow.setImageResource(R.drawable.ruler_triangle_icon);
mCurTempArrow.setScaleType(ImageView.ScaleType.MATRIX);
addView(mCurTempArrow, ThermostatView.THEMROSTAT_CURR_TEMP, new LayoutParams(50, 50));
}
#Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
int currTempHeight = mCurTempArrow.getMeasuredHeight();
int currTempWidth = mCurTempArrow.getMeasuredWidth();
int parentWidth = right - left;
int parentHeight = bottom - top;
int padding = currTempHeight;
//We need square container for the circle.
int containerLeft = padding;
int containerTop = parentHeight - parentWidth + padding;
int containerRight = parentWidth - padding;
int containerBottom = parentHeight - padding;
int containerWidth = containerRight - containerLeft;
int containerHeight = containerBottom - containerTop;
//place the arrow indicating current temperature
int curTempLeft = containerRight - ((containerWidth/2) + currTempWidth/2);
int curTempTop = containerTop - (currTempHeight/2);
int curTempRight = curTempLeft + currTempWidth;
int curTempBottom = curTempTop + currTempHeight;
mCurTempArrow.layout(curTempLeft, curTempTop, curTempRight, curTempBottom);
}
try this (it uses Paths instead of Bitmaps but the idea is the same):
public class MyView extends View {
private Paint mPaint;
private Path mTriangle;
private Path mCircle;
private Matrix mMatrix;
private float mAngle;
public MyView(Context context) {
super(context);
mPaint = new Paint();
mPaint.setStrokeWidth(10);
mPaint.setStyle(Style.STROKE);
mTriangle = new Path();
mTriangle.moveTo(0, -21);
mTriangle.lineTo(0, 21);
mTriangle.lineTo(36, 0);
mTriangle.close();
mCircle = new Path();
mCircle.addCircle(0, 0, 50, Direction.CW);
mMatrix = new Matrix();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float w2 = getWidth() / 2f;
float h2 = getHeight() / 2f;
mAngle = (float) (180 * Math.atan2(event.getY() - h2, event.getX() - w2) / Math.PI);
invalidate();
return true;
}
#Override
protected void onDraw(Canvas canvas) {
float w2 = getWidth() / 2f;
float h2 = getHeight() / 2f;
mMatrix.reset();
mMatrix.postTranslate(w2, h2);
canvas.concat(mMatrix);
mPaint.setColor(0xaaff0000);
canvas.drawPath(mCircle, mPaint);
mMatrix.reset();
mMatrix.postTranslate(60, 0);
mMatrix.postRotate(mAngle);
canvas.concat(mMatrix);
mPaint.setColor(0xaa00ff00);
canvas.drawPath(mTriangle, mPaint);
}
}
Since I don't know if you are using open GL or a standard canevas, I can't really give you some working code. But the general idea is (assuming you have the current position of the triangle (x, y) stored, and the center of your circle (cx, cy) stored.
Do the following:
v = (cx-x, cy-y) // v is the normal vector of your triangle: it faces the center of the circle
triangle.translate(v) // translate to the center of the circle
triangle.rotate(angle) // rotate the triangle on itself
v.rotate(angle) // apply the same rotation on the normal vector
triangle.translate(-v) // translate back on the circle, but since v is rotated, the position will be updated
I hope it is clear enough, good luck
EDIT:
First, you should really try to be more accurate: in your first post, you didn't say that the triangle was an image (that's important). Then you don't say what is your current rendering, what works, what doesn't. I would be easier to help you to know what your program currently display.
From your code, I assume you place the triangle image properly , but it is not rotated. So first, try to add
//place the arrow indicating current temperature
int curTempLeft = containerRight - ((containerWidth/2) + currTempWidth/2);
int curTempTop = containerTop - (currTempHeight/2);
int curTempRight = curTempLeft + currTempWidth;
int curTempBottom = curTempTop + currTempHeight;
mCurTempArrow.setRotate(angle); // rotate the image. angle is in degrees
mCurTempArrow.layout(curTempLeft, curTempTop, curTempRight, curTempBottom);
If you don't know the angle, you might have to compute it from the previous position of the triangle

No controls visible on S3

I face the following issue - come of the people that downloaded my new space simulation game (but not all) are complaining, that they do not see any controls on their devices. The problem seems to be present on S3 devices only. I am with S3 myself, and everything is appearing as designed.
The controls are implemented as custom radio buttons, I will post the code below, however my question is:
What could cause such different behavior?
public class CenteredRadioButton extends RadioButton {
private Drawable buttonDrawable;
public CenteredRadioButton(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CompoundButton, 0, 0);
buttonDrawable = a.getDrawable(1);
setButtonDrawable(R.drawable.radio_empty);
}
public void setCustomDrawable(Drawable drawable) {
buttonDrawable = drawable;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (buttonDrawable != null) {
buttonDrawable.setState(getDrawableState());
final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
final int height = buttonDrawable.getIntrinsicHeight();
int y = 0;
switch (verticalGravity) {
case (Gravity.BOTTOM) : {
y = getHeight() - height;
break;
} case (Gravity.CENTER_VERTICAL) : {
y = (getHeight() - height) / 2;
break;
}
}
int buttonWidth = buttonDrawable.getIntrinsicWidth();
int buttonLeft = (getWidth() - buttonWidth) / 2;
buttonDrawable.setBounds(buttonLeft, y, buttonLeft + buttonWidth, y + height);
buttonDrawable.draw(canvas);
}
}
}
It turned out, that GIF image format is not entirely supported in some Android versions, for more information you could take a look at the thread below and a big THANK YOU to Rich for solving the issue!
Images not loading on Galaxy S3

Animate a Drawable in a custom view

I'm trying to animate a ShapeDrawable in a custom view. But I am not sure what the best method is to accomplish this task.
Should I try and draw a pawn on a path and call invalidate() until it has reached the destination square? Or is there some better method using maybe an AsyncTask or Handler?
Here is my code, I have omitted a lot of methods and variables in order to make it readable.
public class CheckerBoard extends View {
public enum State implements Parcelable {
EMPTY(0), WHITE(1), BLACK(2);
}
private final State[][] boardStates = new State[SIZE][SIZE];
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(bgColor);
for (int y = 0; y < SIZE; y++) {
for (int x = 0; x < SIZE; x++) {
if ((y % 2 == 0 && x % 2 != 0) || (y % 2 != 0 && x % 2 == 0)) {
drawRect(x, y, canvas);
drawPawn(x, y, canvas);
}
}
}
}
private void drawRect(int x, int y, Canvas c) {
}
private void drawPawn(int x, int y, Canvas c) {
}
private void init() {
setupBoard();
pawnLinePaint.setStyle(Paint.Style.STROKE);
wPawnDrawable.getPaint().setColor(wColor);
wPawnDrawable.getPaint().setShadowLayer(tileSize + 2, 4, 4, Color.GRAY);
bPawnDrawable.getPaint().setColor(bColor);
bPawnDrawable.getPaint().setShadowLayer(tileSize + 2, 4, 4, Color.GRAY);
playerState = startState;
}
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
int x = (int) (event.getX() / tileSize);
int y = (int) (event.getY() / tileSize);
if (selection[0] >= 0) { // A tile is already selected
if (isValidMove(selection[0], selection[1], x, y)) {
makeMove(x, y);
clearSelection();
switchPlayer();
invalidate();
}
} else { // New selection
if (isValidSelection(x, y)) {
selection[0] = x;
selection[1] = y;
invalidate();
}
}
return true;
default:
return super.onTouchEvent(event);
}
}
private void makeMove(int x, int y) {
// Move the pawn to the new square
boardStates[y][x] = boardStates[selection[1]][selection[0]];
// Old square is now empty
boardStates[selection[1]][selection[0]] = State.EMPTY;
}
private void switchPlayer() {
playerState = playerState == State.WHITE ? State.BLACK : State.WHITE;
}
public CheckerBoard(Context context) {
super(context);
init();
}
public CheckerBoard(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CheckerBoard(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private class Pawn extends ShapeDrawable {
public Pawn() {
super(new OvalShape());
}
public void drawWithCircles(Canvas canvas, float x, float y){
super.draw(canvas);
canvas.drawCircle(x * tileSize + pawnDiameter, y * tileSize + pawnDiameter, pawnDiameter - pawnPadding,
pawnLinePaint);
canvas.drawCircle(x * tileSize + pawnDiameter, y * tileSize + pawnDiameter, pawnDiameter - pawnPadding * 6,
pawnLinePaint);
canvas.drawCircle(x * tileSize + pawnDiameter, y * tileSize + pawnDiameter, pawnDiameter - pawnPadding * 8,
pawnLinePaint);
}
}
}
Thank you for your help.
Blight
You should create two threads for your application. One thread is the UI thread that only draws the board in its current state. The other thread is the Game engine or animation thread that moves the items on the board.
The first thread runs at whatever your desired frame rate is and the 2nd thread should run considerably faster. This way you don't actually have to handle the animation yourself as the UI thread just draws the board as it currently is. In your engine thread you update the state of the game,board,chess pieces, every cycle of the thread.
Doing things this way has a couple of benefits. First your game's framerate won't drop if the Engine thread gets bogged down in some sort of computation. Second it allows you to abstract the drawing away from the game in a way that will make debugging much easier.
Take a progress bar for example. Let say you tried to create a file uploader with a progress bar but only had one thread. So you start the progress bar then start uploading the file. If the upload process is blocking then you have to wait for the file to finish uploading before you can update the progress bar, essentially rendering the progress bar useless. But if you did this with two threads then you could set it up so one thread simply updates the progress bars graphics based upon some common variable. The other tread is responsible for performing an action and updating the progress variable.
Check out these links for more info:
http://obviam.net/index.php/the-android-game-loop/
http://www.rbgrn.net/content/54-getting-started-android-game-development
http://www.helloandroid.com/tutorials/using-threads-and-progressdialog

Categories

Resources