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
Related
I have a fragment called MyRequestFragment, that contains a RecyclerView and binding the data to the RecyclerView using onBindViewHolder() using my adapter class.
Now every ViewHolder I have a button. and for every click on the button a POST request fired to the server and update a value. My problem is, if a success response comes, I need to hide the button on the particular ViewHolder.
The actual problem is the runOnUiThread() is not accept on the onBindViewHolder()
runOnUiThread(new Runnable() {
public void run() {
}
});
How do I call this inside the ViewHolder create / bind method.
My onBindViewHolder() full code is as bellow for reference.
#Override
public void onBindViewHolder(MyServiceViewHolder holder, int position) {
final MyServiceBean myServiceBean = serviceList.get(position);
holder.service_name.setText(myServiceBean.getService_name());
holder.last_updated.setText("Job Updated Date : " +myServiceBean.getDate(myServiceBean.getUpdated_at()));
holder.created_date.setText("Job Created Date : " + myServiceBean.getDate(myServiceBean.getCreated_at()));
holder.status.setText(myServiceBean.getStatus());
holder.service_note.setText("Service Note : " + myServiceBean.getService_note());
if (myServiceBean.getService_note().toString().isEmpty())
holder.service_note.setVisibility(View.GONE);
switch (myServiceBean.getStatus().toString().toLowerCase()) {
case "completed":
holder.status.setBackgroundColor(Color.GREEN);
break;
case "on progress":
holder.status.setBackgroundColor(Color.YELLOW);
break;
case "canceled":
holder.status.setBackgroundColor(Color.RED);
break;
case "rejected":
holder.status.setBackgroundColor(Color.RED);
break;
case "accept":
holder.status.setBackgroundColor(Color.BLUE);
break;
default:
holder.status.setBackgroundColor(Color.GRAY);
break;
}
if(myServiceBean.getEst_amount() != null) {
holder.estimation_region.setVisibility(View.VISIBLE);
holder.est_status.setText("Estimation is Available");
holder.btn_approve.setVisibility(View.VISIBLE);
holder.est_amount.setText("Estimation Amount: " + myServiceBean.getEst_amount());
if(myServiceBean.getEst_note() != null)
holder.est_note.setText("Estimation Note: " + myServiceBean.getEst_note());
if(myServiceBean.getEst_presented_by() != null)
holder.est_presented_by.setText("Estimation Prepared By: " + myServiceBean.getEst_presented_by());
if(myServiceBean.getEst_approved_by_customer() == "true"){
holder.btn_approve.setVisibility(View.GONE);
holder.est_status.setText("Estimation Approved on : " + myServiceBean.getEst_approved_date());
}else{
holder.btn_approve.setVisibility(View.VISIBLE);
}
}else{
holder.estimation_region.setVisibility(View.GONE);
holder.est_status.setText("Estimation on Process");
holder.btn_approve.setVisibility(View.GONE);
}
holder.btn_approve.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
updateRequest();
}
});
}
private void updateRequest() {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("est_approved_by_customer", true);
jsonObject.put("est_approved_date", "2017-10-30");
} catch (JSONException e) {
e.printStackTrace();
}
//progress_dialog.show();
OkHttpClient client = new OkHttpClient();
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
okhttp3.RequestBody body = RequestBody.create(JSON, jsonObject.toString());
okhttp3.Request request = new Request.Builder()
.url(ApplicationContants.BASE_URL + ApplicationContants.MY_SERVICE_APPROVE_URL)
.post(body)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, final IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
try {
String responseString = response.body().string();
JSONObject jsonObject = new JSONObject(responseString);
Gson gson = new Gson();
final MyServiceBean myServiceBean = gson.fromJson(jsonObject.toString(), MyServiceBean.class);
runOnUiThread(new Runnable() {
public void run() {
}
});
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
runOnUiThread() is a method of Activity.
Either call it on an Activity instance (if you have access to one), or use a Handler to post your Runnable to the message queue of the main thread:
new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
// do something
}
});
You should get your activity before calling runOnUiThread:
getActivity.runOnUiThread(new Runnable(){
#Override
public void run(){
/*your code*/
}
});
I have a code like this, which makes a anonymous thread
everytime the loop goes. And the length of cityArray is 17.
for(int i=0; i<cityArray.length; i++)
{
final int finalI = i;
new Thread(new Runnable() {
#Override
public void run() {
setMarkerIcon(cityArray[finalI]);
}
}).start();
}
And it calls the setMarkerIcon method, which runs the getBestMarkerItemfromArrayList, then runs runOnUiThread to update view.
public void setMarkerIcon( final String city ){
final MarkerItem markerItem = getBestMarkerItemfromArrayList(city);
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
Log.i(TAG, "run: ");
if(markerItem != null){
Glide.with(getContext())
.load(R.drawable.back_level3)
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(new SimpleTarget<Bitmap>() {
#Override
public void onResourceReady(Bitmap bitmap, GlideAnimation<? super Bitmap> glideAnimation) {
Log.i(TAG, "onResourceReady: " + map.getMarkers().size() + "__" + city);
for (int i = 0; i < markerOptions.length; i++) {
if (map.getMarkers().get(i).getData().equals(city)) {
map.getMarkers().get(i).setIcon(BitmapDescriptorFactory.fromBitmap(createDrawableFromView(city, bitmap)));
break;
}
}
}
});
The code works well, and there seems to be no problem at the moment.
But I just want to make sure that I am using the thread correctly.
Thanks.
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();
}
I have this below piece of code, I want to my thread to wait untill either of the callback functions are called.
Issue my code hits the line where i am making the synchObj wait but after that it just vanishes it doesn't move anywhere.
If after wait its not gonna move ahead how the notify will be called?
iGPlaceApi.getStreams(new Callback<mGooglePlacesApiResponse>() {
#Override
public void failure(RetrofitError retrofitError) {
String serverResponse = retrofitError.toString();
synchronized (synchObj) {
synchObj.notify();
//synchObj.notifyAll();
}
}
#Override
public void success(mGooglePlacesApiResponse googlePlacesObj, Response arg1){
nearbyPlaces = new String[googlePlacesObj.results.size()][4];
for (int i = 0; i < googlePlacesObj.results.size(); i++) {
mGooglePlaces.place place = googlePlacesObj.results.get(i);
nearbyPlaces[i][0] = place.icon;
nearbyPlaces[i][1] = place.name;
nearbyPlaces[i][2] = String.valueOf(place.geometry.location.lat);
nearbyPlaces[i][3] = String.valueOf(place.geometry.location.lng);
}
synchronized (synchObj) {
synchObj.notify();
//synchObj.notifyAll();
}
}
});
synchronized (synchObj) {
synchObj.wait();
}
Handler handler=new Handler();
Runnable thr = new Runnable() {
public void run() {
iGPlaceApi.getStreams(new Callback<mGooglePlacesApiResponse>() {
#Override
public void failure(RetrofitError retrofitError) {
String serverResponse = retrofitError.toString();
synchronized (synchObj) {
synchObj.notifyAll();
}
}
#Override
public void success(mGooglePlacesApiResponse googlePlacesObj, Response arg1) {
nearbyPlaces = new String[googlePlacesObj.results.size()][4];
for (int i = 0; i < googlePlacesObj.results.size(); i++) {
mGooglePlaces.place place = googlePlacesObj.results.get(i);
nearbyPlaces[i][0] = place.icon;
nearbyPlaces[i][1] = place.name;
nearbyPlaces[i][2] = String.valueOf(place.geometry.location.lat);
nearbyPlaces[i][3] = String.valueOf(place.geometry.location.lng);
}
synchronized (synchObj) {
synchObj.notifyAll();
}
}
});
}
};
handler.post(thr);
synchronized (synchObj) {
synchObj.wait();
}
You can't do that. The callbacks are going to be called on the same thread that is calling the getStreams method.
The callbacks cannot be called until your calling method returns. You probably need to call getStreams in yet another thread.
You are doing it wrong. Handler task will be executed on the same thread so in your case it will never be executed. If you want to wait for your task to be done you should use Thread like this:
// defined somewhere
boolean done = false;
Thread thr=new Thread(Runnable() {
public void run() {
iGPlaceApi.getStreams(new Callback<mGooglePlacesApiResponse>() {
#Override
public void failure(RetrofitError retrofitError) {
String serverResponse = retrofitError.toString();
synchronized (synchObj) {
done = true;
synchObj.notifyAll();
}
}
#Override
public void success(mGooglePlacesApiResponse googlePlacesObj, Response arg1) {
nearbyPlaces = new String[googlePlacesObj.results.size()][4];
for (int i = 0; i < googlePlacesObj.results.size(); i++) {
mGooglePlaces.place place = googlePlacesObj.results.get(i);
nearbyPlaces[i][0] = place.icon;
nearbyPlaces[i][1] = place.name;
nearbyPlaces[i][2] = String.valueOf(place.geometry.location.lat);
nearbyPlaces[i][3] = String.valueOf(place.geometry.location.lng);
}
synchronized (synchObj) {
done = true;
synchObj.notifyAll();
}
}
});
}
});
thr.start();
synchronized (synchObj) {
while (!done) {
synchObj.wait();
}
}
Note that instead of just runnable I'm using Thread, and done variable which indicates task status which is neccesary since wait call can spontaneously wake up and you have to call it again if the task has not been finished yet.
I just tried to implement a progressdialog and I have some issues to change the text during my long and complex calculations.
for (String aString:myStringArray){
Log.v(TAG, aString);
mProgressDialog.incrementProgressBy(1);
mProgressDialog.setMessage(aString);
}
I can clearly see the incrementProgressBy working and my dialog updating, but the message does not change.
Any idea on how to make that work?
Thank a lot.
Just found the answer, that's working fine:
runOnUiThread(changeMessage);
with that code:
private Runnable changeMessage = new Runnable() {
#Override
public void run() {
//Log.v(TAG, strCharacters);
m_ProgressDialog.setMessage(strCharacters);
}
};
I upload pictures to Firebase in a loop and updating the ProgressDialog each image:
(I am in a Fragment, so I use getActivity() before calling to runOnUiThread())
List<Bitmap> bitmaps;
int picCounter = 1;
...
progressDialog = ProgressDialog.show
(getContext(), "sending...", "just a minute", false, false);
new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < bitmaps.size(); i++) {
String filename = String.valueOf(i);
uploadPic(bitmaps.get(i), "img" + filename, new MyCallback() {
#Override
public void onFinish() {
picCounter++;
Objects.requireNonNull(getActivity()).runOnUiThread(new Runnable() {
public void run() {
progressDialog.setTitle ("upoading " + picCounter + "image from " + bitmaps.size());
}
});
}
});
}
}
}).start();
uploadPic method:
public interface MyCallback { void onFinish ();}
private void uploadPic(final Bitmap bitmap, final String fileName, final MyCallback callback) {
... // uploading to firebase and then:
callback.onFinish();
}