How to repeat a view animation variable number of times in android? - java

I have this swapAnimation method which basically swaps two views. I call this method inside a loop and pass different views on the swapAnimation method each time. But the problem is the animation happens only once. I want it to repeat n number of times.
void swapAnimation(View v1,View v2){
if(isAnimating)return;
isAnimating = true;
float x1,y1,x2,y2;
x1 =getRelativeX(v1);
x2 = getRelativeX(v2);
y1 = getRelativeY(v1);
y2 = getRelativeY(v2);
float x_displacement = (x2-x1);
float y_displacement = (y2-y1);
v1.animate().xBy(x_displacement).yBy(y_displacement);
v2.animate().xBy(-x_displacement).yBy(-y_displacement);
v1.animate().setDuration(500);
v2.animate().setDuration(500);
long duration = v1.animate().getDuration();
new CountDownTimer(duration+10,duration+10){
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
isAnimating = false;
}
}.start();
}
public static void arrange(LinearLayout container, Context context){
MainActivity activity = (MainActivity) context;
for(int i=0;i<container.getChildCount();i++){
BarView v1 = (BarView) container.getChildAt(i);
for(int j=i;j<container.getChildCount();j++){
BarView v2 = (BarView) container.getChildAt(j);
if(v1.getWeight() > v2.getWeight()){
Log.d(TAG, "bubbleSort: "+v1.getWeight()+">"+v2.getWeight());
activity.swapAnimation(v1,v2);
}
}
}
}

Try this
animation.setRepeatCount(Animation.INFINITE);

Related

What code should I put inside the Android Lifecycle method?

I am new in Android. I am currently developing a game and when I press the back button I realize that my activity's state is not saved so I search and I found out about Android Lifecycle. I read it and now i know how they work but the thing is I don't know how to pause and resume my activity or What code should I use because it is the auto-generated grid and my timer is CountDownTimer.
When I press the Back button this Activity is what appears.
GameModeActivity
Now i want to detect if the game is still going on .. so if I click again the game mode this is what should appear.
GamePlayActivity
The problem is The grid was back to its normal state. and when I click a button timer never runs. If possible i want to restore the player's progress (like the position of mines, the flags, and the timer itself.).
My question is ... Is there a specific code to get the whole state of activity? so that i can just pause it and when i came back it will just resume?
This is the code of timer and grid in GameEngine class:
public static GameEngine getInstance() {
if (instance == null) {
instance = new GameEngine();
}
return instance;
}
private GameEngine() {
}
public void startit() {
countdowntimer = new CountDownTimer(60000, 1000) {
TextView timer = (TextView) ((GamePlayActivity) context).findViewById(R.id.tvTimeValue);
#Override
public void onTick(long millisUntilFinished) {
timer.setText("" + millisUntilFinished / 1000);
}
#Override
public void onFinish() {
timer.setText("Times up!");
timer.setTextColor(Color.RED);
}
}.start();
}
public static void cancel() {
if (countdowntimer != null) {
countdowntimer.cancel();
countdowntimer = null;
}
}
public void createGrid(Context context) {
Log.e("GameEngine", "Creating Grid..");
this.context = context;
int[][] GeneratedGrid = Generator.generate(bombnumber, WIDTH, HEIGHT);
setGrid(context, GeneratedGrid);
}
private void setGrid(final Context context, final int[][] grid) {
for (int x = 0; x < WIDTH; x++) {
for (int y = 0; y < HEIGHT; y++) {
if (MinesweeperGrid[x][y] == null) {
MinesweeperGrid[x][y] = new Cell(context, x, y);
}
MinesweeperGrid[x][y].setValue(grid[x][y]);
MinesweeperGrid[x][y].invalidate();
}
}
}
public Cell getCellposition(int position) {
int x = position % WIDTH;
int y = position / WIDTH;
return MinesweeperGrid[x][y];
}
public Cell getCellposition(int x, int y) {
return MinesweeperGrid[x][y];
}
I call the GameEngine.getInstance().createGrid(this) class in onCreate method of GamePlayActivity
And when I press the Back button on phone it will go to the previous activity which is GameModeActivity.

Speeding the Random process

I am practising on a simple Android Game where a round button is randomly placed on the screen when the user taps on it..
it works fine but i want to speedify the process of placing the button so that the game gets harder for user...
here is the Code I'm using -
public class GameWindow extends Activity implements View.OnClickListener {
static int score;
private Timer t;
private int TimeCounter = 29;
private boolean canMove = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
////Remove title screen for activty.
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_game_window);
moveButton();
endonTimeOver();
}
public void endonTimeOver(){
////Activity timer for 60 seconds.
final TextView timer = (TextView) findViewById(R.id.seconds);
t = new Timer();
t.scheduleAtFixedRate(new TimerTask() {
////Set string to timer.
#Override
public void run() {
// TODO Auto-generated method stub
runOnUiThread(new Runnable() {
public void run() {
timer.setText(String.valueOf(TimeCounter)); // you can set it to a textView to show it to the user to see the time passing while he is writing.
TimeCounter = TimeCounter - 1;
}
});
}
}, 1000, 1000); // 1000 means start from 1 sec, and the second 1000 is do the loop each 1 sec.
new Timer().schedule(new TimerTask(){
public void run() {
GameWindow.this.runOnUiThread(new Runnable() {
public void run() {
startActivity(new Intent(GameWindow.this, Finished.class));
}
});
}
}, 30000);
}
////Move button.
private void moveButton()
{
if(!canMove){ return; }
runOnUiThread(
new Runnable()
{
#Override
public void run()
{
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
Button button = (Button)findViewById(R.id.button);
Random r = new Random();
int startX = width/2;
int startY = height/2;
if(score==0){
button.setX(startX);
button.setY(startY);
}
else {
int x = r.nextInt(width - 210);
int y = r.nextInt(height - 200);
button.setX(x);
button.setY(y);
}
}
}
);
}
////Display score
public void displayScore(int score) {
TextView scoreView = (TextView) findViewById(R.id.score);
scoreView.setText(String.valueOf(score));
}
#Override
public void onClick(View v) {
MediaPlayer mp = MediaPlayer.create(this, R.raw.buttonsound);
mp.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
// TODO Auto-generated method stub
mp.release();
}
});
mp.start();
score = score + 1;
displayScore(score);
switch (v.getId()) {
case (R.id.button): {
moveButton();
}
}
}
public static int getScore(){
return score;
}}
Use global variables for values that don't change:
findViewById is slow
Creating new Random every time is not necessary
getting the window parameter every time is not necessary either
You seem to be starting a new thread and telling it to runonui , this might be slowing you down , try this :
private void moveButton()
{
if(!canMove){ return; }
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
Button button = (Button)findViewById(R.id.button);
Random r = new Random();
int startX = width/2;
int startY = height/2;
if(score==0){
button.setX(startX);
button.setY(startY);
}
else {
int x = r.nextInt(width - 210);
int y = r.nextInt(height - 200);
button.setX(x);
button.setY(y);
}
}
the computation itself doesn't seem to heavy so no need for another thread , you can do it on the main thread , if you're calling from oncreate that means you're already on main thread , this might give you the answer if i understood the question , try it

My Android UI doesn't run?

I implemented AsyncTask to execute results. Here is the error I get...
FATAL EXCEPTION: AsyncTask #1
Process: ai69.psoui, PID: 3287
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:309)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:200)
at android.os.Handler.<init>(Handler.java:114)
at android.app.Activity.<init>(Activity.java:754)
at android.support.v4.app.SupportActivity.<init>(SupportActivity.java:31)
at android.support.v4.app.BaseFragmentActivityGingerbread.<init>(BaseFragmentActivityGingerbread.java:37)
at android.support.v4.app.BaseFragmentActivityHoneycomb.<init>(BaseFragmentActivityHoneycomb.java:29)
at android.support.v4.app.BaseFragmentActivityJB.<init>(BaseFragmentActivityJB.java:30)
at android.support.v4.app.FragmentActivity.<init>(FragmentActivity.java:79)
at android.support.v7.app.AppCompatActivity.<init>(AppCompatActivity.java:61)
at ai69.psoui.MainActivity.<init>(MainActivity.java:0)
at android_tests.CustomUseCase.<init>(CustomUseCase.java:19)
at android_tests.TestFactory.getTest(TestFactory.java:15)
at ai69.psoui.ParticleActivity.runTest(ParticleActivity.java:91)
at ai69.psoui.ParticleActivity$runTests.doInBackground(ParticleActivity.java:53)
at ai69.psoui.ParticleActivity$runTests.doInBackground(ParticleActivity.java:50)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
I have looked at different SOF posts about "Looper.prepare()" but the thing is, prior to a few changes in changing static variables to getter/setter methods, my UI was working fine.
Here is my code...
public class ParticleActivity extends AppCompatActivity {
public final static String EXTRA_MESSAGE = "PSOUI.MESSAGE";
private ProgressDialog pd;
private double[] results = {-1.0, -1.0, -1.0};
EditText particles;
EditText iterations;
EditText userSol;
EditText userBatt;
private double battery;
private double solution;
//int numberOfDimensions = MainActivity.dimensions.size();
//public ArrayList<Double> costData = MainActivity.costDATA; //costs that
the user enters for each resource
//public ArrayList<Double> costWlan = MainActivity.costWLAN;
//public ArrayList<Double> costUtilities = MainActivity.costUTILITY;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_particle);
particles = (EditText) findViewById(R.id.particles);
iterations = (EditText) findViewById(R.id.iterations);
userSol = (EditText) findViewById(R.id.solution);
userBatt = (EditText) findViewById(R.id.battery);
pd = null;
runPSOButton();
}
#Override
public void onPause(){
super.onPause();
if(pd != null)
pd.dismiss();
}
public class runTests extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) { //sort this out
results = runTest("CustomUseCase"); //i only want to run this one!!!
return null;
}
#Override
protected void onPostExecute(Void v) {
if (results != null && results.length > 0 && results[0] != -1) {
loadIntent(results);
} //otherwise it will evaluate the next logic statement results[0] != -1 with no chance of NulLPointerException
}
#Override
protected void onPreExecute() {
pd = ProgressDialog.show(ParticleActivity.this, "Busy", "Algorithm is currently executing");
pd.setCancelable(true);
pd.show();
}
}
public void runPSOButton() {
final Button runPSO = (Button) findViewById(R.id.runpso);
runPSO.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
new runTests().execute();
}
});
}
public double[] runTest(String test) {
int noPart = Integer.parseInt(particles.getText().toString());
int noIter = Integer.parseInt(iterations.getText().toString());
return new TestFactory(noPart, noIter).getTest(test).test();
}
public void loadIntent(double[] result) {
double[] results = result;
Intent intent = new Intent(this, SolutionActivity.class);
intent.putExtra(EXTRA_MESSAGE, results);
startActivity(intent);
}
public double setBatteryCost(){
battery = Double.parseDouble(userBatt.getText().toString());
return battery;
}
public double getBatteryCost(){return setBatteryCost();}
public double setUserSolution(){
solution = Double.parseDouble(userSol.getText().toString());
return solution;
}
public double getUserSolution(){return setUserSolution();}
}
Can someone explain whats happening? New to Android Studio and have been developing for only 3 months in Java, so for any solutions can I kindly request an explanation for it too? Much appreciated thank you
UPDATE:
Here is my mainActivity...
public class MainActivity extends AppCompatActivity {
//declare variables
EditText name;
EditText data;
EditText wlan;
EditText utility;
Button addservice;
ListView lv;
ListView lv2;
ListView lv3;
ListView lv4;
public ArrayList<String> servicenames;
public ArrayList<String> dimensions;
public ArrayList<Double> costDATA;
public ArrayList<Double> costWLAN;
public ArrayList<Double> costUTILITY;
ArrayAdapter<String> namesAdapter;
ArrayAdapter<Double> dataAdapter;
ArrayAdapter<Double> wlanAdapter;
ArrayAdapter<Double> utilityAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//map the components to the variables
name = (EditText) findViewById(R.id.servicename);
data = (EditText) findViewById(R.id.data);
wlan = (EditText) findViewById(R.id.wlan);
utility = (EditText) findViewById(R.id.utility);
addservice = (Button) findViewById(R.id.addservice);
lv = (ListView) findViewById(R.id.lv);
lv2 = (ListView) findViewById(R.id.lv2);
lv3 = (ListView) findViewById(R.id.lv3);
lv4 = (ListView) findViewById(R.id.lv4);
//create arraylists for each component
servicenames = new ArrayList<String>();
dimensions = new ArrayList<String>();
costDATA = new ArrayList<Double>();
costWLAN = new ArrayList<Double>();
costUTILITY = new ArrayList<Double>();
//create adapters to pass on the arraylist
namesAdapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, servicenames);
dataAdapter = new ArrayAdapter<Double>(MainActivity.this, android.R.layout.simple_list_item_1, costDATA);
wlanAdapter = new ArrayAdapter<Double>(MainActivity.this, android.R.layout.simple_list_item_1, costWLAN);
utilityAdapter = new ArrayAdapter<Double>(MainActivity.this, android.R.layout.simple_list_item_1, costUTILITY);
//display each arraylist in the listviews
lv.setAdapter(namesAdapter);
lv2.setAdapter(wlanAdapter);
lv3.setAdapter(dataAdapter);
lv4.setAdapter(utilityAdapter);
namesAdapter.notifyDataSetChanged();
dataAdapter.notifyDataSetChanged();
wlanAdapter.notifyDataSetChanged();
utilityAdapter.notifyDataSetChanged();
dimensions.add("DATA");
dimensions.add("WLAN");
onClickBtn();
}
public void onClickBtn() { //when user clicks button, the user input is added to the listview, and cleared for the next service
addservice.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String namesOfService = name.getText().toString(); //user input for service names
String costOfData = data.getText().toString(); //user input for data costs
String costOfWLAN = wlan.getText().toString(); //user input for wlan costs
String costOfUtility = utility.getText().toString(); //user input for utility costs
Double doubleWLAN = Double.parseDouble(costOfWLAN); //convert user input into double
Double doubleData = Double.parseDouble(costOfData);
Double doubleUtility = Double.parseDouble(costOfUtility);
costDATA.add(doubleData); //add the double costs to each resource arraylist
costWLAN.add(doubleWLAN);
costUTILITY.add(doubleUtility);
servicenames.add(namesOfService);
dimensions.add(namesOfService);
namesAdapter.notifyDataSetChanged();
dataAdapter.notifyDataSetChanged();
wlanAdapter.notifyDataSetChanged();
utilityAdapter.notifyDataSetChanged();
name.setText(""); //empty the edit text fields when button is clicked
wlan.setText("");
data.setText("");
utility.setText("");
}
});
}
public void nextButton(View view) //next button, onto the next activity
{
Intent intent = new Intent(MainActivity.this, ParticleActivity.class);
startActivity(intent);
}
public int getDimensions(){ return dimensions.size();}
public ArrayList<String> getElements(){ return servicenames;}
public ArrayList<Double> getCostDATA(){;return costDATA;}
public ArrayList<Double> getCostWLAN(){return costUTILITY;}
public ArrayList<Double> getCostUTILITY(){return costUTILITY;}
}
As you can see, the arraylists that store the user input is accessible using getters and setters rather than setting the arraylists static (which I did before). I access these arraylists in another class called CustomUseCase and CustomService. Here is the code for customUseCase:
public class CustomUseCase extends Test {
MainActivity mainActivity = new MainActivity();
ParticleActivity particleActivity = new ParticleActivity();
private int numberOfDimensions = mainActivity.getDimensions();
private ArrayList<Double> costData = mainActivity.getCostDATA(); //costs that the user enters for each resource
private ArrayList<Double> costWlan = mainActivity.getCostWLAN();
private ArrayList<Double> costUtilities = mainActivity.getCostUTILITY();
private double batteryCost = particleActivity.getBatteryCost();
private int maxIter;
private int noParticles;
public CustomUseCase(int noParticles, int maxIterations) {
this.noParticles = noParticles;
this.maxIter = maxIterations;
}
#Override
public double[] test() {
long max = 10000; //maximum number of iterations, override //2 bits for the WLAN/DATA and the rest for the amount of services the user inputs
double[] results = new double[numberOfDimensions]; //new array of results with numOfBits as number of elements
for (int i = 1; i <= max; i++) {
BinaryPso bpso = new BinaryPso(noParticles,
numberOfDimensions);
ParticleActivity getUserInput = new ParticleActivity();
CustomService customService =
new CustomService(batteryCost, costData, costWlan, costUtilities);
long start = System.currentTimeMillis(); //start time
bpso.setSolution(getUserInput.getUserSolution()); //changed this to user selection
bpso.optimize(maxIter, customService, true);
this.found += (bpso.getFound() ? 1 : 0);
this.iterations += bpso.getSolIterations(); //use the method in bpso to get number of iterations taken
long end = System.currentTimeMillis() - start; //end time minus start time
this.sumTimes += end; //override the time spent variable
System.out.println("P-value: " + Particle.getValue(Particle.bestGlobal()));
System.out.println("P-bitCombo: " + Arrays.toString(Particle.bestGlobal()));
System.out.println("P-goodness: " + customService.getGoodness(Particle.bestGlobal()));
}
System.out.println("Time: " + sumTimes / max);
System.out.println("Iterations: " + iterations / max);
System.out.println("Success Rate: " + found);
boolean[] bestCombo = Particle.bestGlobal();
for (Boolean b : bestCombo) {
System.out.print(b + " ");
}
System.out.println();
results[0] = sumTimes / max;
results[1] = iterations / max;
results[2] = found;
return results;
}
public static List<Boolean> getBestComboArray() { //method to get best global array
boolean[] bestCombo = Particle.bestGlobal(); //calculate best global
List<Boolean> bestCombi = new ArrayList<>(bestCombo.length);
for (int x = 0; x < bestCombo.length; x++) {
bestCombi.add(bestCombo[x]);
}
return bestCombi;
}
}
And here is my CustomService class:
public class CustomService implements Goodness {
MainActivity mainActivity = new MainActivity();
private int numOfDimensions = mainActivity.getDimensions();
private ArrayList<String> serviceNames = mainActivity.getElements();
private ArrayList<Double> costData = mainActivity.getCostDATA();
private ArrayList<Double> costWlan = mainActivity.getCostWLAN();
private ArrayList<Double> costUtilities = mainActivity.getCostUTILITY();
private double batteryCost;
public void setBatteryCost(double batteryCost) {
this.batteryCost = batteryCost;
}
public CustomService(double batteryCost, ArrayList<Double> costData, ArrayList<Double> costWlan,
ArrayList<Double> costUtilities) {
if (costUtilities == null || costUtilities.size() < 1 || costData.size() < 1 || costWlan.size() < 1) {
throw new RuntimeException("Please add atleast 1 cost to Data, WLAN and Utility");
}
this.batteryCost = batteryCost; //make sure you add battery field to UI, user enters battery level
this.costData = costData;
this.costWlan = costWlan;
this.costUtilities = costUtilities;
}
public double getGoodness(boolean[] bits) {
double utility = 0.0;
double rcost = 0.0;
ArrayList<Double> resourceCost = new ArrayList<Double>();
Collections.sort(costUtilities); //sort the costUtilities arraylist
double maxValue = Collections.max(costUtilities); //get the maximum value from the costUtilities arraylist
if(bits[0] && bits[1]){
return -500;
}
if(!bits[0] || bits[1]){
return -1000;
}
for(int x = 1; x < numOfDimensions; x++){
if(bits[x] == costUtilities.contains(maxValue)){
return -1900;
}
}
if (bits[0]) {
resourceCost = costData;
} else if (bits[1]) {
resourceCost = costWlan;
}
for (int i = 2; i <= serviceNames.size(); i++) { //if i = 2, 2<=4
if (bits[i]) {
utility += costUtilities.get(i-2);
rcost += resourceCost.get(i-2);
}
}
if (rcost < batteryCost) {
return utility;
}
return utility * 0.50;
}
}
you can not update UI items on nonUIThread.
search usage of runOnUiThread on google.
call your method in runOnUiThread().
#Override
protected Void doInBackground(Void... params) { //sort this out
runOnUiThread (new Runnable() {
public void run() {
results = runTest("CustomUseCase");
}
}
return null;
}
This explains all: "Can't create handler inside thread that has not called Looper.prepare()" and it seems your TestFactory() method creates a Handler without a Looper.
Inside a secondary Thread a Handler should be like this
....
Looper.prepare();
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// do work with received messages
}
};
Looper.loop();
....
More info : What is the purpose of Looper and how to use it?

Move View with Thread

i cannot move a custom view with this code :
Ball.java
public class Ball extends View {
int x, y;
public Ball(Context context) {
super(context);
}
public void setSizes( int x, int y) {
this.x = x;
this.y = y;
}
protected void onDraw(Canvas c) {
Paint paint = new Paint();
paint.setColor(Color.BLACK);
int radius = 50;
c.drawCircle(x,y,radius,paint);
}
}
BounceLoop.java
public class BounceLoop extends Thread {
int width, height, x, y;
boolean jumping = false;
public void setSizes(int width, int height) {
this.width = width;
this.height = height;
}
public void run() {
jumping = true;
x = 0;
y = 0;
while(jumping) {
}
}
}
and MyActivity.java
public class MyActivity extends Activity {
RelativeLayout content;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
content = (RelativeLayout) findViewById(R.id.content);
BounceLoop thread = new BounceLoop();
thread.setSizes(content.getWidth(), content.getHeight());
thread.start();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.my, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
How do i move the ball from the BounceLoop thread ? I don't want to do it with AsyncTask, do i have to use handlers or ?
your thread will probably need a reference of your custom view and in the run() I would have expected something like
public void run() {
jumping = true;
x = 0;
y = 0;
while(jumping) {
mCircleView.setPosition(newX, newY);
mCircleView.postInvalidate();
}
}
be aware that you can't touch the UI Through another thread, this is way I called postInvalidate() instead of invalidate(). The former will reschedule a draw event on the UI Thread
Finally i did this :
public class MyActivity extends Activity {
RelativeLayout content;
Handler myHandler;
Ball view;
Thread loop;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
content = (RelativeLayout) findViewById(R.id.content);
view = new Ball(this);
view.setPosition(50, 50);
content.addView(view);
myHandler = new Handler() {
public void handleMessage(Message msg) {
int x = (int) msg.arg1;
int y = (int) msg.arg2;
Log.d("ss", String.valueOf(x));
view.setPosition(x, y);
}
};
}
public void onWindowFocusChanged(boolean hasChanged) {
super.onWindowFocusChanged(hasChanged);
loop = new Thread(new Runnable() {
#Override
public void run() {
int x = 0;
int y = 0;
Log.d("width", String.valueOf(view.getWidth()));
while (x < content.getWidth() - view.radius) {
x += 5;
y += 7;
Message msg = new Message();
msg.arg1 = x;
msg.arg2 = y;
myHandler.sendMessage(msg);
try {
Thread.sleep(25);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
loop.start();
}
}
but this is not comfortable for me to have the thread in the activity, how can i export it to another class...

Spawning threads in a onSensorChanged() in Android

I'm making an app that tracks exercise movements based on orientation and accelerometer readings(the exercise movements are very slow). What I have is a strategy pattern kind of a situation where I have an abstract class for exercise movement and the concrete exercise movements implement the actual thing. Problem is, I am spawning threads to track different exercises in the onSensorChanged() method in my activity. since this is going to be called a lot of times, I don't know if my code will spawn as many threads. Do they get garbage collected?
Code:
public class WorkoutBuddy extends Activity implements SensorEventListener {
TextView t1, t2, t3, t4, t5, t6, t7;
SensorManager sensorManager;;
private Sensor sensorAccelerometer;
private Sensor sensorMagneticField;
private float[] valuesAccelerometer;
private float[] valuesMagneticField;
private float[] valuesOrientation;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.exercise_buddy);
sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
sensorAccelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorMagneticField = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
valuesAccelerometer = new float[3];
valuesMagneticField = new float[3];
valuesOrientation = new float[3];
matrixR = new float[9];
matrixI = new float[9];
matrixValues = new float[3];
//mediaPlayer = MediaPlayer.create(this, R.raw.first_position_confirmation);
}
#Override
protected void onPause() {
sensorManager.unregisterListener(this,sensorAccelerometer);
sensorManager.unregisterListener(this,sensorMagneticField);
super.onPause();
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
float[] orientation;
private float[] matrixR;
private float[] matrixI;
private float[] matrixValues;
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
valuesAccelerometer = lowPass(event.values.clone(), valuesAccelerometer);
} else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
valuesMagneticField = lowPass(event.values.clone(), valuesMagneticField);
}
if (valuesAccelerometer != null && valuesMagneticField != null) {
SensorManager.getRotationMatrix(matrixR, matrixI, valuesAccelerometer, valuesMagneticField);
if(true){
SensorManager.getOrientation(matrixR, matrixValues);
double azimuth = Math.toDegrees(matrixValues[0]);
double pitch = Math.toDegrees(matrixValues[1]);
double roll = Math.toDegrees(matrixValues[2]);
valuesOrientation[0]=(float) pitch;
valuesOrientation[1]=(float) roll;
valuesOrientation[0]=(float) azimuth;
Thread forExc1 = new Thread(new LeftShoulder(valuesAccelerometer, valuesOrientation, this));
Thread forExc2 = new Thread(new RightShoulder(valuesAccelerometer, valuesOrientation, this));
forExc1.run();
forExc2.run();
}
}
}
#Override
protected void onResume() {
sensorManager.registerListener(this,sensorAccelerometer,SensorManager.SENSOR_DELAY_NORMAL);
sensorManager.registerListener(this,sensorMagneticField,SensorManager.SENSOR_DELAY_NORMAL);
super.onResume();
}
//Low pass filter used to smooth the sensor readings
protected float[] lowPass( float[] input, float[] output ) {
float ALPHA = 0.25f;
if ( output == null ) return input;
for ( int i=0; i<input.length; i++ ) {
output[i] = output[i] + ALPHA * (input[i] - output[i]);
}
return output;
}
}
package com.example.msapp2;
public abstract class ExerciseMovement implements Runnable{
protected float[] acc, ori;
protected boolean played = false;
}
package com.example.msapp2;
import android.content.Context;
import android.media.MediaPlayer;
public class LeftShoulder extends ExerciseMovement {
MediaPlayer mediaPlayer;
public LeftShoulder(float[] accelerometer, float[] orientation, Context context){
mediaPlayer = MediaPlayer.create(context, R.raw.first_position_confirmation);
acc = accelerometer;
//this.ori = orientation;
}
public void run(){
if(acc[0]> -10 && acc[0] < -8.5 && !played){
mediaPlayer.start();
played = true;
}
}
}
If you just override OnSensorChanged and output a Log.d , you'll see it's called hundreds, if not thousands, of times per second.
I suggest you the opposite approach: Create just one thread to process in background the different received events, then feed such thread from onSensorChanged.
Implement kind of an event queue in the thread. Assume thousands of events will arrive, constantly.
SOmething like:
private class ShoulderMovementProcessorThread extends Thread {
.....
// this will be called from the UI thread, just add event to the (synchronized) queue.
public void publish (int[] valuesAccelerometer, int[] valuesWhatever) {
add_event_to_queue();
}
// this is the typical event loop where you read one from the queue, process it, then wait for the next
public void run() {
-> get event
-> process event
-> wait for next event
}
}
ShoulderMovementProcessorThread mShoulderProcessor=new ShoulderMovementProcessorThread(...);
#Override
public void onSensorChanged(SensorEvent event) {
decodeEvent (event); // fills up azimuth, roll, etc.
mShoulderProcessor.publish(valuesAccelerometer, valuesWhatever);
}
// decode an event
private void decodeEvent (SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
valuesAccelerometer = lowPass(event.values.clone(), valuesAccelerometer);
} else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
valuesMagneticField = lowPass(event.values.clone(), valuesMagneticField);
}
if (valuesAccelerometer != null && valuesMagneticField != null) {
SensorManager.getRotationMatrix(matrixR, matrixI, valuesAccelerometer, valuesMagneticField);
if(true){
SensorManager.getOrientation(matrixR, matrixValues);
double azimuth = Math.toDegrees(matrixValues[0]);
double pitch = Math.toDegrees(matrixValues[1]);
double roll = Math.toDegrees(matrixValues[2]);
valuesOrientation[0]=(float) pitch;
valuesOrientation[1]=(float) roll;
valuesOrientation[0]=(float) azimuth;
}
}
}
I implemented something similar recently:
public class DBWorkerThread implements Runnable
{
private SensorEnum sensorType;
private LinkedBlockingQueue<float[]> sensorData;
private DBService dbService;
public DBWorkerThread(SensorEnum type, DBService dbService)
{
this.sensorType = type;
this.dbService = dbService;
this.sensorData = new LinkedBlockingQueue<float[]>();
}
/**
* Add data to queue
* #param values
*/
public void addDataToProcess(float[] values)
{
if (sensorData.size() < sensorData.remainingCapacity())
{
try
{
this.sensorData.put(values);
}
catch (Exception ex)
{
LogService.log("Error adding queue: " + ex.getMessage());
}
LogService.log("Added to queue. Size: " + sensorData.size());
}
}
/**
* Processes queue of data
*/
#Override
public void run()
{
// Moves the current Thread into the background
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
while (sensorData.size() > 0)
{
try
{
float[] values = sensorData.take();
storeData(values);
}
catch (Exception ex)
{
LogService.log("Error in queue: " + ex.getMessage());
}
}
}
/**
* Store data to database
* #param values
*/
private void storeData(float[] values)
{
// store data
}
}
Hopes this helps

Categories

Resources