This question already has answers here:
Android "Only the original thread that created a view hierarchy can touch its views."
(33 answers)
Closed 8 years ago.
So I understand the error. I'm trying to adjust the UI with a thread that isn't the main UI thread. But that's inherently the problem. Doing image processing (in this case greyscaling multiple bitmaps) is a CPU intensive task. Therefore, wouldn't me trying to launch a thread that deals with image processing be the right thing to do? Or is my thought just an ideal thought that simply isn't possible because of the valid error I am receiving? Is there a work around that I'm unaware of?
Actual error message:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
//Package declaration
//Many import statements
public class PhotoViewer extends Activity implements OnClickListener {
private Button refresh_;
private Button grey_;
private ImageView image1_;
private ImageView image2_;
private ImageView image3_;
private ImageView image4_;
private GreyBitmaps gMap_;
private Bitmap bMap1_;
private Bitmap bMap2_;
private Bitmap bMap3_;
private Bitmap bMap4_;
private int num_;
private boolean makeGrey_;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_photos);
// this GreyBitmaps class creates the other thread
gMap_ = new GreyBitmaps();
refresh_ = (Button) findViewById(R.id.refresh);
grey_ = (Button) findViewById(R.id.grey);
image1_ = (ImageView) findViewById(R.id.view1);
image2_ = (ImageView) findViewById(R.id.view2);
image3_ = (ImageView) findViewById(R.id.view3);
image4_ = (ImageView) findViewById(R.id.view4);
refresh_.setOnClickListener(this);
grey_.setOnClickListener(this);
makeGrey_ = false;
getPhotos();
setBitmap();
//num_ =0;
}
public void onClick(View v) {
Log.d("onClick", "Begin");
if(v == refresh_){
refreshPhoto();
}else if (v == grey_){
greyPhoto();
}
Log.d("onClick", "end");
}
protected void onResume(){
super.onResume();
gMap_.resume();
}
protected void onPause(){
super.onPause();
gMap_.pause();
}
private void refreshPhoto(){
getPhotos();
}
private void greyPhoto(){
makeGrey_ = true;
}
private void getPhotos(){
bMap1_ = BitmapFactory.decodeResource(getResources(), R.drawable.p1);
bMap2_ = BitmapFactory.decodeResource(getResources(), R.drawable.p2);
bMap3_ = BitmapFactory.decodeResource(getResources(), R.drawable.p3);
bMap4_ = BitmapFactory.decodeResource(getResources(), R.drawable.p4);
}
private void setBitmap(){
image1_.setImageBitmap(bMap1_);
image2_.setImageBitmap(bMap2_);
image3_.setImageBitmap(bMap3_);
image4_.setImageBitmap(bMap4_);
}
private Bitmap goGrey(Bitmap bmIn){
final double gs_red = 0.299;
final double gs_green = 0.587;
final double gs_blue = 0.114;
int width = bmIn.getWidth();
int height = bmIn.getHeight();
Bitmap bmOut = Bitmap.createBitmap(width, height, bmIn.getConfig());
int a, r, g, b;
int pix;
for(int x = 0; x<width; x++){
for(int y = 0; y<height; y++){
pix = bmIn.getPixel(x, y);
a = Color.alpha(pix);
r = Color.red(pix);
g = Color.green(pix);
b = Color.blue(pix);
r = g = b = (int) (gs_blue*b +gs_green*g +gs_red*r);
//write out
bmOut.setPixel(x, y, Color.argb(a, r, g, b));
}
}
return bmOut;
}
public class GreyBitmaps implements Runnable{
Thread t = null;
boolean isActive = false;
public void run() {
Log.d("Runnable", "running");
//num_ = 100;
while(isActive) {
Log.d("Runnable", "running2");
num_ = 200;
setBitmap();
try {
Thread.sleep(100);
if (makeGrey_) {
goGrey(bMap1_);
goGrey(bMap2_);
goGrey(bMap3_);
goGrey(bMap4_);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void pause(){
isActive = false;
while(true){
try{
t.join();
}catch (InterruptedException e) {
e.printStackTrace();
Log.e("Error", "Failed to join thread");
}
break;
}
t = null;
}
public void resume(){
isActive = true;
t = new Thread(this);
t.start();
}
}
}
Call your setBitmap() method in runOnUiThread thread.
See this link for runOnUiThread method implementation https://stackoverflow.com/a/11140429/4384828
Related
From this thread: How to Customize a Progress Bar In Android
I made my own progress bar using ClipDrawAble animation and it works perfecty, and the code is here:
public class MainActivity extends AppCompatActivity {
private EditText etPercent;
private ClipDrawable mImageDrawable;
private Button fly_to_50;
// a field in your class
private int mLevel = 0;
private int fromLevel = 0;
private int toLevel = 0;
//public static final int MAX_LEVEL = 10000;
public static final int MAX_LEVEL = 10000;
public static final int LEVEL_DIFF = 100;
public static final int DELAY = 0;
public static final int START_AT_50 = 50;
private Handler mUpHandler = new Handler();
private Runnable animateUpImage = new Runnable() {
#Override
public void run() {
doTheUpAnimation(fromLevel, toLevel);
}
};
private Handler mDownHandler = new Handler();
private Runnable animateDownImage = new Runnable() {
#Override
public void run() {
doTheDownAnimation(fromLevel, toLevel);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etPercent = (EditText) findViewById(R.id.etPercent);
ImageView img = (ImageView) findViewById(R.id.imageView1);
mImageDrawable = (ClipDrawable) img.getDrawable();
mImageDrawable.setLevel(0);
}
private void doTheUpAnimation(int fromLevel, int toLevel) {
mLevel += LEVEL_DIFF;
mImageDrawable.setLevel(mLevel);
if (mLevel <= toLevel) {
mUpHandler.postDelayed(animateUpImage, DELAY);
} else {
mUpHandler.removeCallbacks(animateUpImage);
MainActivity.this.fromLevel = toLevel;
}
}
private void doTheDownAnimation(int fromLevel, int toLevel) {
mLevel -= LEVEL_DIFF;
mImageDrawable.setLevel(mLevel);
if (mLevel >= toLevel) {
mDownHandler.postDelayed(animateDownImage, DELAY);
} else {
mDownHandler.removeCallbacks(animateDownImage);
MainActivity.this.fromLevel = toLevel;
}
}
public void onClick50(View v){
mImageDrawable.setLevel(START_AT_50);
}
public void onClickOk(View v) {
//int temp_level = ((Integer.parseInt(etPercent.getText().toString())) * MAX_LEVEL) / 100;
int temp_level = ((Integer.parseInt(etPercent.getText().toString())) * MAX_LEVEL) / 100;
if (toLevel == temp_level || temp_level > MAX_LEVEL) {
return;
}
toLevel = (temp_level <= MAX_LEVEL) ? temp_level : toLevel;
if (toLevel > fromLevel) {
// cancel previous process first
mDownHandler.removeCallbacks(animateDownImage);
MainActivity.this.fromLevel = toLevel;
mUpHandler.post(animateUpImage);
} else {
// cancel previous process first
mUpHandler.removeCallbacks(animateUpImage);
MainActivity.this.fromLevel = toLevel;
mDownHandler.post(animateDownImage);
}
}
}
I set my "DELAY" variable to be 0, which increased the speed a little bit, however, I am not completely satisfied with the speed and would love to increase the speed more. Is this somehow possible? And if not, is there a chance that I can create a normal progress(would work here for sure), but using my own custom edited images?
Appreciate all answers!
Thank you.
SOLVED:
I changed this line:
mDownHandler.postDelayed(animateDownImage, DELAY);
with this:
mDownHandler.postAtTime(animateDownImage,DELAY);
I am using AChartEngine to plot values obtained from Ubidots in real-time. The graph is retrieving values in real-time however when no value is being sent on Ubidots, the last retrieved value sent on Ubidots is being plotted again as shown in the screenshot.
Here are my codes:
LineGraph.java:
public class LineGraph {
private GraphicalView view;
private TimeSeries dataset = new TimeSeries("LDR Values");
private XYMultipleSeriesDataset mDataset = new XYMultipleSeriesDataset();
private XYSeriesRenderer renderer = new XYSeriesRenderer(); // This will be used to customize line 1
private XYMultipleSeriesRenderer mRenderer = new XYMultipleSeriesRenderer(); // Holds a collection of XYSeriesRenderer and customizes the graph
public LineGraph()
{
// Add single dataset to multiple dataset
mDataset.addSeries(dataset);
// Customization time for line 1!
renderer.setColor(Color.BLUE);
renderer.setPointStyle(PointStyle.SQUARE);
renderer.setFillPoints(true);
renderer.setDisplayChartValues(true);
renderer.setChartValuesSpacing(10);
// mRenderer: renderer that controls the full charts and add the single renderer for each series:
// Enable Zoom
//mRenderer.setZoomButtonsVisible(true);
mRenderer.setMarginsColor(Color.argb(0x00, 0xff, 0x00, 0x00));
mRenderer.setXTitle("Day #");
mRenderer.setYTitle("LDR Values");
mRenderer.setYAxisMax(30000);
mRenderer.setYAxisMin(10000);
mRenderer.setShowGrid(true);
// Add single renderer to multiple renderer
mRenderer.addSeriesRenderer(renderer);
}
public GraphicalView getView(Context context)
{
view = ChartFactory.getLineChartView(context, mDataset, mRenderer);
return view;
}
public void addNewPoints(Point p)
{
dataset.add(p.getX(), p.getY());
}
}
Point.java:
public class Point {
private int x;
private int y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
private TextView mTextMessage;
private static GraphicalView view;
private LineGraph line = new LineGraph();
private static Thread thread;
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
mTextMessage.setText(R.string.title_home);
return true;
case R.id.navigation_dashboard:
mTextMessage.setText(R.string.title_dashboard);
return true;
case R.id.navigation_notifications:
mTextMessage.setText(R.string.title_notifications);
return true;
}
return false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextMessage = (TextView) findViewById(R.id.message);
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
thread = new Thread() {
public void run()
{
for (int i = 0; i <1000; i++)
{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Point p = UbidotsData.getDataFromReceiver(i); // We got new data!
line.addNewPoints(p); // Add it to our graph
view.repaint();
}
}
};
thread.start();
}
#Override
protected void onStart() {
super.onStart();
view = line.getView(this);
setContentView(view);
}
}
UbidotsData.java
public class UbidotsData {
//private static Context context;
public static Point getDataFromReceiver(int x)
{
ApiClient api = new ApiClient("XXXXXXXXXXXXXXXXXXX");
Variable ldr = api.getVariable("XXXXXXXXXXXXXXXXXXX");
Value[] values = ldr.getValues();
int newValue = (int) values[0].getValue();
if(newValue>22000){
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
MediaPlayer mp = MediaPlayer.create(Context.getContext(), notification);
mp.start();
}
return new Point(x, newValue);
}
}
Furthermore, when I close the app and open it again, it starts to plot the same data retrieved from Ubidots previously (when I ran the program while it was fetching data in real-time). How do I make the data permanent in the graph instead of having the graph plot it again when I open it? Should I be using AsyncTask instead of Thread in this case?
To make it clearer, it is this line which fetches the value:
int newValue = (int) values[0].getValue();
I want make a Dice game, i have use a github project (https://github.com/dylanmtaylor/Simple-Dice).
The MainActivity is available here : https://github.com/dylanmtaylor/Simple-Dice/blob/master/src/com/dylantaylor/simpledice/RollDice.java
I want to get the value of the dice
Exemple :
If the first dice is 1 and the second is 6 we have a total of 7 i want make an action.
I have make a button who change a textview, this button try to get the number of the dices.
TextView hwTextView = (TextView)findViewById(R.id.textView8);
hwTextView.setText(String.valueOf(diceSum));
I have try to get the value "diceSum", "diceImages", "dice", "dice[roll[0]", "dice[roll[1]" but that didn't show a number.
How can i do try to get the value of the dice ?
My MainActivity
public class dices extends AppCompatActivity {
Button button;
private final int rollAnimations = 50;
private final int delayTime = 15;
private Resources res;
private final int[] diceImages = new int[] { R.drawable.d1, R.drawable.d2, R.drawable.d3, R.drawable.d4, R.drawable.d5, R.drawable.d6 };
private Drawable dice[] = new Drawable[6];
private final Random randomGen = new Random();
#SuppressWarnings("unused")
private int diceSum;
private int roll[] = new int[] { 6, 6 };
private ImageView die1;
private ImageView die2;
private LinearLayout diceContainer;
private SensorManager sensorMgr;
private Handler animationHandler;
private long lastUpdate = -1;
private float x, y, z;
private float last_x, last_y, last_z;
private boolean paused = false;
private static final int UPDATE_DELAY = 50;
private static final int SHAKE_THRESHOLD = 800;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
paused = false;
setContentView(R.layout.activity_dixit);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.setStatusBarColor(Color.parseColor("#2c3e50"));
}
View view = this.getWindow().getDecorView();
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
button=(Button)findViewById(R.id.button_roll);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
rollDice();
TextView hwTextView = (TextView)findViewById(R.id.textView8);
hwTextView.setText(String.valueOf(diceSum));
}
});
res = getResources();
for (int i = 0; i < 6; i++) {
dice[i] = res.getDrawable(diceImages[i]);
}
die1 = (ImageView) findViewById(R.id.die1);
die2 = (ImageView) findViewById(R.id.die2);
animationHandler = new Handler() {
public void handleMessage(Message msg) {
die1.setImageDrawable(dice[roll[0]]);
die2.setImageDrawable(dice[roll[1]]);
}
};
}
private void rollDice() {
if (paused) return;
new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < rollAnimations; i++) {
doRoll();
}
}
}).start();
MediaPlayer mp = MediaPlayer.create(this, R.raw.roll);
try {
mp.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mp.start();
}
private void doRoll() { // only does a single roll
roll[0] = randomGen.nextInt(6);
roll[1] = randomGen.nextInt(6);
diceSum = roll[0] + roll[1] + 2; // 2 is added because the values of the rolls start with 0 not 1
synchronized (getLayoutInflater()) {
animationHandler.sendEmptyMessage(0);
}
try { // delay to alloy for smooth animation
Thread.sleep(delayTime);
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
public void onResume() {
super.onResume();
paused = false;
}
public void onPause() {
super.onPause();
paused = true;
}
}
I didn't understand why your code didn't work. I myself making a very small games based on "Scarne's dice game(pig)" and myself facing the challenge of retrieving the value of dice rolled. Mind, I am just using one die. This is what I did:
int userScore;
private int[] diceArray = {R.drawable.d1, R.drawable.d2, R.drawable.d3,
R.drawable.d4,R.drawable.d5,R.drawable.d6};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onRollBtnClicked() {
ImageView diceFace = (ImageView) findViewById(R.id.diceFaceImageView);
userScore = randomIntegerGenerator(1,6); // this is what you need
diceFace.setImageResource(diceArray[userScore]);
}
// function to return random integer from min to max
public int randomIntegerGenerator(int min, int max) {
return random.nextInt((max - min) + 1) + min;
}
I am storing my rolled die value in userScore. You can use the similar approach.
My android app is crashing when using SharedPreferences to try and carry the final score over from when the game ends. The app crashes inside the onTouchEvent at the line.
SharedPreferences.Editor editor = mySharedPreferences.edit();
The idea is when the game ends it final score that is within the SVGameView to carry over into the SVGameOver class and display there. If anyone could give some advice that would be great!
SVGameView:
public class SVGameView extends SurfaceView implements Runnable {
private SurfaceHolder holder;
Thread thread = null;
volatile boolean running = false;
static final long FPS = 30;
private Sprite sprite;
private long lastClick;
private Bitmap ball, gameOver;
//private int x = 200, y = 200;
private int scorePosX = 100;
private int scorePosY = 100;
private int countScore = 0;
private int life = 1;
SharedPreferences mySharedPreferences;
public SVGameView(Context context) {
super(context);
thread = new Thread(this);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
running = false;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
running = true;
thread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
ball = BitmapFactory.decodeResource(getResources(), R.drawable.ball2);
gameOver = BitmapFactory.decodeResource(getResources(),R.drawable.endscreen);
sprite = new Sprite(this, ball);
context.getSharedPreferences("myPrefsFile",Context.MODE_PRIVATE);
}
#Override
public void run() {
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
while (running) {
Canvas c = null;
startTime = System.currentTimeMillis();
try {
c = getHolder().lockCanvas();
synchronized (getHolder()) {
update();
onDraw(c);
}
} finally {
if (c != null) {
getHolder().unlockCanvasAndPost(c);
}
}
sleepTime = ticksPS-(System.currentTimeMillis() - startTime);
try {
if (sleepTime > 0)
thread.sleep(sleepTime);
else
thread.sleep(10);
} catch (Exception e) {}
}
}
private void update(){
sprite.update();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
canvas.drawPaint(paint);
paint.setColor(Color.WHITE);
paint.setTextSize(48);
canvas.drawText("Score: " + countScore, scorePosX, scorePosY, paint);
canvas.drawText("Lives: " + life, 500, 100, paint);
sprite.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(System.currentTimeMillis()-lastClick > 300){
lastClick = System.currentTimeMillis();
}
synchronized (getHolder()){
if(sprite.isHit(event.getX(), event.getY())){
countScore += 1;
sprite.increase();
}else{
life --;
}
}
if(life == 0) {
getContext().startActivity(new Intent(getContext(), SVGameOver.class));
//Intent intent;
//intent = new Intent(getContext(), SVGameView.class);
//intent.putExtra("scoreOutput", countScore);
//Crashes Here
SharedPreferences.Editor editor = mySharedPreferences.edit();
editor.putString("cScore", String.valueOf(countScore));
}
return super.onTouchEvent(event);
}
}
SVGameOver Class:
public class SVGameOver extends Activity implements View.OnClickListener{
Button btnBack;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
btnBack = (Button)findViewById(R.id.btnBack);
btnBack.setOnClickListener(this);
SharedPreferences mySharedPreferences = getSharedPreferences("myPrefsFile", 0);
String theScore = mySharedPreferences.getString("cScore","");
TextView textView = (TextView)findViewById(R.id.scoreOutput);
textView.setText(theScore);
//intent = getIntent();
//String uir = intent.getStringExtra("scoreOutput");
}
#Override
public void onClick(View v) {
}
}
XML Layout:
https://gyazo.com/8e49d02c66dde7ff0e7f09a4fa9eacd2
You're missing:
mySharedPreferences = context.getSharedPreferences("myPrefsFile", Context.MODE_PRIVATE);
in your SVGameView, so mySharedPreferences always null.
You missed assigning SharedPreferencesobject to your reference mySharedPreferences in SVGameView(Context context) -
context.getSharedPreferences("myPrefsFile",Context.MODE_PRIVATE);
Change it to
mySharedPreferences = context.getSharedPreferences("myPrefsFile",Context.MODE_PRIVATE);
You are not initializing the SharedPreference object right.
Use this library, which simplifies the use of SharedPreferences and will make life simpler for you.
Android-SharedPreferences-Helper simplifies usage of the default Android SharedPreferences Class. The developer can do in a few lines
of code which otherwise would have required several. Simple to
understand as compared to the default class and easy to use.
For the past few days I've been playing around with sensors and canvas.
So far I've managed to control the location of a bitmap based on device's angles.
The way app works is it gets orientation data, and depending on how much the device is tilted, it moves the bitmap left or right on the screen.
I do most of my testing on my Samsung Galaxy S II GT-i9100 running android 4.2.2 (AOKP), and the app works pretty much flawlessly, apart from the app crashing when resuming it (I think I know what's causing that).
The problem I'm having is as follows:
When I try running the same code on a Sony Xperia Z (running android 4.1.2, stock from Sony) the whole app becomes choppy (the bitmap barely moves), and I think it's because the sensor data retrieval is choppy/slow. Same happens on my friend's Sony Xperia S.
I gave the app to my other friend who has a Nexus 4, he says he has no such problems.
GameView
public class GameView extends SurfaceView {
private Bitmap bmp;
private SurfaceHolder holder;
private GameLoopThread gameLoopThread;
private int x = 0;
private int xMultiplier = 0;
private Paint textPaint;
//lowPass
private float smoothVal = 0; //Main variable, check algorithm
private int smoothing = 5; //How strong the smoothing is, larger the value, more time is needed before the value reaches actual sensor value
//Sensors
private SensorManager sensorManager;
private SensorEventListener sensorEventListener;
//Rotation matrices for converting coordinate systems
private float[] rotationMatrixR = new float[9];
private float[] rotationMatrixI = new float[9];
//Arrays storing data for gravity and geomagnetic data needed to get device's angles
private float[] gravity = new float[3];
private float[] geomagnetic = new float[3];
//Array holding angles
private float[] angles = new float[3];
public GameView(Context context) {
super(context);
gameLoopThread = new GameLoopThread(this);
holder = getHolder();
textPaint = new Paint();
textPaint.setColor(Color.WHITE);
textPaint.setTextSize(20);
sensorManager = (SensorManager)getContext().getSystemService(Context.SENSOR_SERVICE);
sensorEventListener = new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
Sensor sensor = sensorEvent.sensor;
if (sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
gravity = sensorEvent.values;
}
else if (sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
geomagnetic = sensorEvent.values;
}
SensorManager.getRotationMatrix(rotationMatrixR, rotationMatrixI, gravity, geomagnetic);
SensorManager.getOrientation(rotationMatrixR, angles);
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
};
sensorManager.registerListener(sensorEventListener, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_FASTEST);
sensorManager.registerListener(sensorEventListener, sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_FASTEST);
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
gameLoopThread.setRunning(false);
while (retry) {
try {
gameLoopThread.join();
retry = false;
}
catch (InterruptedException e) {
//Shit hit the fan
Log.e("GameLoopThread", e.toString());
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder){
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
});
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
}
#Override
protected void onDraw(Canvas canvas)
{
x = (int) ((canvas.getWidth() / 100) * ((lowPass(angles[2]) * 100) + 50));
canvas.drawColor(Color.DKGRAY); //This also clears the screen
canvas.drawBitmap(bmp, x, canvas.getHeight() - bmp.getHeight() - 20, null);
canvas.drawText("Azimuth (Z): " + Float.toString(angles[0]),25,25, textPaint);
canvas.drawText("Pitch (X): " + Float.toString(angles[1]),25,45, textPaint);
canvas.drawText("Roll (Y): " + Float.toString(angles[2]),25,65, textPaint);
canvas.drawText("X: " + Integer.toString(x),25,85,textPaint);
}
public static BigDecimal roundFloat(float d, int decimalPlace) {
BigDecimal bd = new BigDecimal(Float.toString(d));
bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
return bd;
}
private float lowPass(float curValue) {
smoothVal += (curValue - smoothVal) / smoothing;
return smoothVal;
}
}
GameLoopThread
public class GameLoopThread extends Thread {
static final long FPS = 25;
private GameView view;
private Boolean running = false;
public GameLoopThread(GameView view){
this.view = view;
}
public void setRunning(boolean run){
running = run;
}
#Override
public void run(){
long tickPS = 1000/FPS;
long startTime;
long sleepTime;
while(running){
Canvas c = null;
startTime = System.currentTimeMillis();
try {
c = view.getHolder().lockCanvas();
synchronized (view.getHolder()){
view.onDraw(c);
}
}
catch (NullPointerException e) {
Log.e("GameLoopThread", e.toString());
}
finally {
if (c != null) {
view.getHolder().unlockCanvasAndPost(c);
}
}
sleepTime = tickPS - (System.currentTimeMillis() - startTime);
try {
if (sleepTime > 0) {
sleep(sleepTime);
}
else {
sleep(10);
}
}
catch (Exception e) {
Log.e("GameLoopThread", e.toString());
}
}
}
}