I am building a simple game (using Java and android xml) and I want to refresh a TextView with a numeric value as often as possible (let's say 5-10 times a second)
Questions:
Is there a better way to show a numeric value refreshing more than once a second?
How to do it efficiently?
My current code:
void textViewRefresher() {
Thread t = new Thread() {
#Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(100);
runOnUiThread(new Runnable() {
#Override
public void run() {
DecimalFormat format = new DecimalFormat("#.#");
format.setDecimalSeparatorAlwaysShown(false);
bankValue = bankValue + 0.1 * perSecondValue;
String truncatedBank = format.format(bankValue);
bankText.setText(truncatedBank);
totalValue = totalValue + 0.1 * perSecondValue;
String truncatedTotal = format.format(totalValue);
totalText.setText("Total: " + truncatedTotal);
}
});
}
} catch (InterruptedException e) {
}
}
};
t.start();
}
Related
I have a picture of a lightbulb
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/light_bulb_off" />
<item android:drawable="#drawable/light_bulb_on" />
</transition>
I also have the folowing method to turn on/off this lightbulb depending on condition
private void ImageClick(boolean b) {
final ImageView image = (ImageView) findViewById(R.id.image);
TransitionDrawable drawable = (TransitionDrawable) image
.getDrawable();
if (b) {
drawable.startTransition(1000); //Turn on
} else {
drawable.reverseTransition(1000); //Turn off
}
}
Now, if I call this method from a button, in normal intervals like 2seconds, everything is fine, the light turns on and there is a nice transition effect
but I also have a background thread that pols a server with 500ms intervals to get some data
Handler handler = new Handler();
Runnable runnable;
int delay = 500;
String DeviceIP = "192.168.101.11";
private void StartNetworkThread() {
handler.postDelayed( runnable = new Runnable() {
public void run() {
UpdateDeviceStatus();
handler.postDelayed(runnable, delay);
}
}, delay);
}
private void UpdateDeviceStatus() {
//See every device if its online or not
String url = "";
url = MainActivity.internetOptions.getURL() + "/" + DeviceIP + "/cm?cmnd=Power";
Request request = new Request.Builder().url(url).build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.d("HTTP", "Device: " + DeviceIP + " failed");
DeviceActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
ImageClick(false);
}
});
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
String myResponse = response.body().string();
if (myResponse.equals("{\"POWER\":\"ON\"}")) {
Log.d("HTTP", "Device: " + DeviceIP + " works");
DeviceActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
ImageClick(true);
}
});
} else {
DeviceActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
ImageClick(false);
}
});
}
}
}
});
}
Now the problem is, if this background thread is calling this ImageClick method, which should turn light on on transition, light blinks like a broken flurescent tube
Instead of light being on all the time (since ImageClick(true) most of the time, because server tells that light is on)
so TLRD:
if you call ImageClick(true) 2 times in a row, instead of light staying on, it blinks
Now I don't know why it blinks (flickers, there is no transition, just anoying flicker which makes you go crazy if you look at it long enough), but if it has to blink (it also blinks if I drawable.startTransition(0); (0 should mean no transition so keep light on), so if the light has to blink it should blink with 50Hz, but I would much prefer it staying on if you call ImageClick(true) 2 times in a row
Now the light being image of a lightbulb and on state meaing show #drawable/light_bulb_on
off state meaning show #drawable/light_bulb_off
Hope someone know how to stop the image to flicker. Thanks for anwsering and Best Regards
I solved it, with a few more if statments
int LightTurnedOnCount = 0;
int LightTurnedOffCount = 0;
void TurnWeb(boolean b) {
final ImageView image = (ImageView) findViewById(R.id.image);
TransitionDrawable drawable = (TransitionDrawable) image
.getDrawable();
if (b && LightTurnedOnCount < 1) {
drawable.startTransition(1000); //Turn on
LightTurnedOnCount++;
} else if (!b && LightTurnedOffCount < 1) {
drawable.resetTransition(); //Turn off
LightTurnedOffCount++;
}
}
private void UpdateDeviceStatus() {
//See every device if its online or not
String url = "";
url = MainActivity.internetOptions.getURL() + "/" + DeviceIP + "/cm?cmnd=Power";
Request request = new Request.Builder().url(url).build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.d("HTTP", "Device: " + DeviceIP + " failed");
DeviceActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
TurnWeb(false);
LightTurnedOnCount = 0;
}
});
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
String myResponse = response.body().string();
if (myResponse.equals("{\"POWER\":\"ON\"}")) {
Log.d("HTTP", "Device: " + DeviceIP + " works");
DeviceActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
TurnWeb(true);
LightTurnedOffCount = 0;
}
});
} else {
DeviceActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
TurnWeb(false);
LightTurnedOnCount = 0;
}
});
}
}
}
});
}
The light does not flicker anymore
I have three strings
String one="Connecting.";
String two="Connecting..";
String three="Connecting...";
I have a textView, what I want is to set text to textview in this order..
one-->two-->three-->one-->two-->three and so on until the process is completed.
I have done it in a for loop based on value i.e
if(value%3==0){
tx.setText(one);
}
else if(value%3==1){
tx.setText(two);
}
else
{
tx.setText(three);
}
This is done inside a thread and it is working well.
But I dont want to rely on "value".. I jst want that until process is completed the text changes in order as mentioned above.
I know it is vague but I am not getting how to do this.
Please if someone can give any hint.
code:
public void startProgress(View view) {
bar.setProgress(0);
tx.setText("Connect");
new Thread(new Task()).start();
}
class Task implements Runnable {
#Override
public void run() {
for (int i = 0; i <= 10; i++) {
final int value = i;
try {
Thread.sleep(500);
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
bar.setProgress(value);
String one="Connecting.";
String two="Connecting..";
String three="Connecting...";
if(value%3==0){
tx.setText(one);
}
else if(value%3==1){
tx.setText(two);
}
else
{
tx.setText(three);
}
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
It makes sense to have a counter like value that keeps incrementing. But you could do it a little more simply:
String[] texts = new String[3] {"Connecting.", "Connecting..", "Connecting..."};
int value = 0;
// ...
tx.setText(texts[value]);
value = (value+1)%3;
This way, you don't need your big messy if statement. You will need to find another way of notifying your thread when the job is done, rather than just having a fixed number of iterations.
Use TextSwitcher instead of TextView...It will work
I make a game about 8Puzzle on android with AI using A* algorithm.
Everything works fine but there is a problem, there are some function that is executed in parallel.
What I want is the function is executed after another function is finished.
Here is code:
if(AItype.equals("A*"))
{
DisableButton();
DisableClickImageView();
AStarSolver as = new AStarSolver();
as.solvePuzzle(arr, GOAL); //Solve the puzzle
displayResult(as.solutionPath); //display animation
as = null;
Toast.makeText(getApplicationContext(), "Finished", Toast.LENGTH_LONG).show();
copySTARTtoArray();
setImageResource();
EnableButton();
}
I want text "Finished" is displayed after function displayResult() is finished but the text "Finished"
show at the same time with function displayResult().
How to solve this??
Edit:
Here is the code for displayResult();
public void displayResult(final Stack<Node> solutionPath)
{
Handler handler = new Handler();
for (int i = 0; i < solutionPath.size(); i++)
{
handler.postDelayed(new Runnable() {
public void run() {
Node solNode = solutionPath.pop();
//solNode.NodeState.
tile00.setImageResource(solNode.getImageResourceBasedNodeState(0));
tile01.setImageResource(solNode.getImageResourceBasedNodeState(1));
tile02.setImageResource(solNode.getImageResourceBasedNodeState(2));
tile10.setImageResource(solNode.getImageResourceBasedNodeState(3));
tile11.setImageResource(solNode.getImageResourceBasedNodeState(4));
tile12.setImageResource(solNode.getImageResourceBasedNodeState(5));
tile20.setImageResource(solNode.getImageResourceBasedNodeState(6));
tile21.setImageResource(solNode.getImageResourceBasedNodeState(7));
tile22.setImageResource(solNode.getImageResourceBasedNodeState(8));
}
}, 800 * (i + 1));
}
}
It display the result of animation (Ex: tile0 to tile1)
Try this.
public void displayResult(final Stack<Node> solutionPath)
{
Handler handler = new Handler();
for (int i = 0; i < solutionPath.size(); i++)
{
handler.postDelayed(new Runnable() {
public void run() {
Node solNode = solutionPath.pop();
//solNode.NodeState.
tile00.setImageResource(solNode.getImageResourceBasedNodeState(0));
.
.
.
tile22.setImageResource(solNode.getImageResourceBasedNodeState(8));
}
}, 800 * (i + 1));
}
// Put following code
handler.postDelayed(
new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), "Finished", Toast.LENGTH_LONG).show();
}
},800*(solutionPath.size()+1)
);
}
Your code should be look like this.
solvePuzzle(...){
// solved #1
displayResult(...){
}
// solved #2
displayResult(...){
}
}
or use thread.
as.solvePuzzle(arr, GOAL); //Solve the puzzle
displayResult(as.solutionPath); //display animation
means solvePuzzle is all done, then call displayResult.
function(){
//code of this function
function1();
}
function1(){
//code of this function
function2();
}
function2(){
}
I want when user choose from listview an item (Brand name device),load data arrays with integers. I try to make a remote control.The application must load arrays for power,channel up,down,vol up,vol down functions.How i can do this?I have one listview(devices) and buttons power,Volume,Channel.
Every button use one array with integers for IR pulses.
private OnClickListener btnSendChanUpListener = new OnClickListener() {
public void onClick(View v) {
if(run==0) {
run = 1;
new Thread(new Runnable() {
public void run() {
int[] mod1ChanUpX1 = {346,173,......};//Channel up X1 device
try {
SendIRcommand( frequency, mod1ChanUpX1 );
}
catch(Exception e) {
Log.e( "Error transmitting...");
}
run=0;
}}).start();
}
}
};
I am trying to create a loop that will update a TextView.
The idea is to create some sort of progress indicator, that will increment the
loading precentge.
This is what I have tried, but the result is that I see only the last update of the loop, so I get "100%" with no incremntation.
runOnUiThread(new Runnable() {
public void run() {
final TextView progesss = (TextView)findViewById(R.id.progress);
for(int k=1 ; k<=100; k++)
{
progesss.setText(String.valueOf(k) + "%");
try {
Thread.sleep(15);
} catch(InterruptedException e) {
}
}
}
});
Any ideas of how to achieve my goal?
Thanks!
Your Runnable blocks the UI thread when doing Thread.sleep. Instead of sleeping, you should post a new Runnable again. Try with something like this:
final Handler handler = new Handler();
handler.post( new Runnable(){
private int k = 0;
public void run() {
final TextView progess = (TextView)findViewById(R.id.progress);
progess.setText(String.valueOf(k) + "%");
k++;
if( k <= 100 )
{
// Here `this` refers to the anonymous `Runnable`
handler.postDelayed(this, 15);
}
}
});
That will give the UI thread a chance to run between each call, letting it do its stuff like handling input and drawing stuff on the screen.
You use background thread and UI Thread.
public class testAsync extends AsyncTask<Void, Integer, Voi>{
TextView progress; // You will set TextView referans
protected void doInBackground(){
for(int k=1 ; k<=100; k++)
{
try {
Thread.sleep(1000);
publishProgress(k);
} catch(InterruptedException e) {}
}
}
protected void onProgressUpdate(Integer.. values)
{
progress.setText(values[0]+");
}
}
}