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.
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'm using android socket.io but the problem is that emit event runs twice instead of once , i mean that i wrote just one emit code in the onCreate method , but it sends two request for the server ?
I searched alot but not found anything .
I use node js in the backend ,and my code has not any problems .
Is there a bug in socket.io for android ?
Here is my code :
SocketManager.getInstance().connect();
// Creating Bids
final Handler mHandler04 = new Handler(Looper.getMainLooper());
mHandler04.post(new Runnable() {
#Override
public void run() {
SocketManager.getInstance().getSocket().emit("allc", "some");
SocketManager.getInstance().getSocket().on("allcRes", new Emitter.Listener() {
#Override
public void call(final Object... args) {
g.context.runOnUiThread(new Runnable() {
#Override
public void run() {
JSONArray jsonArray = (JSONArray) args[0];
arrayComps.clear();
Log.d(TAG, "run: " + jsonArray);
try {
for (int i = 0; i < jsonArray.length(); i++) {
createView(jsonArray.getJSONObject(i).getString("title"), jsonArray.getJSONObject(i).getString("realprice"), jsonArray.getJSONObject(i).getString("id"), jsonArray.getJSONObject(i).getString("starttime"), jsonArray.getJSONObject(i).getString("img"));
CustomViewCompetition css = (CustomViewCompetition) LinearLayoutItemHolder.getChildAt(i);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
});
}
});
final Handler bidsupdateHandler = new Handler(Looper.getMainLooper());
bidsupdateHandler.post(new Runnable() {
#Override
public void run() {
SocketManager.getInstance().getSocket().on("bidsupdate", new Emitter.Listener() {
#Override
public void call(final Object... args) {
final JSONArray jsonArray = (JSONArray) args[0];
g.context.runOnUiThread(new Runnable() {
#Override
public void run() {
Log.d(TAG, "run in bidsupdate");
try {
for (int i = 0; i < jsonArray.length(); i++) {
bidsMap.put(jsonArray.getJSONObject(i).getInt("key"), jsonArray.getJSONObject(i).getInt("value"));
}
for (int i = 0; i < LinearLayoutItemHolder.getChildCount(); i++) {
CustomViewCompetition cs = (CustomViewCompetition) LinearLayoutItemHolder.getChildAt(i);
Log.d(TAG, "run in cs " + cs.txtCsRealPrice.getText());
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
});
}
});
the Problem is when i get the cs.txtCsTitle.getText() it is just showing me one of them
Add this line:
SocketManager.getInstance().getSocket().emit("allc", "some");
just after:
SocketManager.getInstance().connect();
So your code will be like
SocketManager.getInstance().connect();
SocketManager.getInstance().getSocket().emit("allc", "some");
And remove from where you are already using in handler. Also you dont need handlers why you are using handlers? Create your listener and emit your subscription out of handlers it needs to be created or subscribed once. On creation of emitter listener pass views if you need to update any view. then update the views here you may need runnable to update UI on uiThread.
Create Class as follows:
public class YourListener implements Emitter.Listener
{
private yourView view;
public YourListener (View view)
{
this.view = view;
}
#Override
public void call(Object... args)
{
// do your work here
}
}
and replace below code :
SocketManager.getInstance().getSocket().on("allcRes", new Emitter.Listener() {
#Override
public void call(final Object... args) {
g.context.runOnUiThread(new Runnable() {
#Override
public void run() {
JSONArray jsonArray = (JSONArray) args[0];
arrayComps.clear();
Log.d(TAG, "run: " + jsonArray);
try {
for (int i = 0; i < jsonArray.length(); i++) {
createView(jsonArray.getJSONObject(i).getString("title"), jsonArray.getJSONObject(i).getString("realprice"), jsonArray.getJSONObject(i).getString("id"), jsonArray.getJSONObject(i).getString("starttime"), jsonArray.getJSONObject(i).getString("img"));
CustomViewCompetition css = (CustomViewCompetition) LinearLayoutItemHolder.getChildAt(i);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
});
with:
SocketManager.getInstance().getSocket().on("your_subscription", new YourListener (yourView));
I would like to add some ImageViews to a RelativeLayout view.
The code that I'm using is as follows:
Thread thread = new Thread(new Runnable() {
ArrayList<ImageView> icons = new ArrayList<ImageView>();
#Override
public void run() {
for (int i = 0; i < 20; i++) {
ImageView imageView1 = new ImageView(G.context);
imageView1.setImageResource(R.drawable.music_icon);
imageView1.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT));
imageView1.getLayoutParams().width = (int) convertDpToPixel(20);
imageView1.getLayoutParams().height = (int) convertDpToPixel(20);
icons.add(imageView1);
Log.i("LOG", "Icons Size: " + icons.size());
Log.i("LOG", "I: " + i);
relativeLayout.addView(icons.get(i));
icons.get(i).startAnimation(animationMusic);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.start();
The first time the loop runs fine, but the second time there's an error in the line:
relativeLayout.addView(icons.get(i));
Where is the problem?
One major problem is manipulating the view (e.g. adding a View) from a background thread. You can get similar async behavior by making use of Android's AsyncTask objects and do any UI manipulation from the onPostExecute method.
Without know more about what you're doing, it's hard to find a solution that will work for you. I was mainly pointing out a primary issue with your code.
Here is an attempt to rewrite your code in a way that might work better in an Android environment:
public void addImageViews() {
for(int i = 0; i < 20; i++) {
asyncAdd(i, G.context);
}
}
protected void asyncAdd(final int index, final Context c) {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(3000 * index);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
relativeLayout.addView(generateImageView(c));
}
}.execute();
}
protected ImageView generateImageView(Context c) {
ImageView imageView1 = new ImageView(c);
imageView1.setImageResource(R.drawable.music_icon);
imageView1.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT));
imageView1.getLayoutParams().width = (int) convertDpToPixel(20);
imageView1.getLayoutParams().height = (int) convertDpToPixel(20);
return imageView1;
}
I am having Pull to Refresh https://github.com/chrisbanes/Android-PullToRefresh as given in this link. Everything works fine. But when my list item finishes, the loading icon and pull to refresh label is still visible. So, how to disable the scrolling when end of list reached?
mainListView.setOnRefreshListener(new OnRefreshListener() {
#Override
public void onRefresh(PullToRefreshBase refreshView) {
String total_bk_count = subCategory .getTotal_Book_Count();
count_of_book = Integer.parseInt(total_bk_count);
listCountt = mainbooksAdpater.getCount();
Log.e("StroreActivity","Total book count---====----====---+"+count_of_book);
Log.e("StroreActivity","list Count---====----====---+"+listCountt);
if(listCountt < count_of_book)
{
int bookCount = Common.getBookCountNumber();
Common.setBookCount(bookCount+1);
String refresh_Pull_Url = Common.getUrlForeCategoryBooks(id, Common.NUMBER_OF_BOOKS_PER_REQUEST);
Log.e("Rathis to Check url", Common.getUrlForeCategoryBooks(id, Common.NUMBER_OF_BOOKS_PER_REQUEST));
PulltoRefreshAsync onCatBooksTaskScroll = new PulltoRefreshAsync(Common.getUrlForeCategoryBooks(id, Common.NUMBER_OF_BOOKS_PER_REQUEST));
onCatBooksTaskScroll.execute();
Log.e("StroreActivity","Total Book count::" + book_count_no);
}
else
{
mainListView.setMode(Mode.DISABLED);
Toast.makeText(getApplicationContext(), "end of list", Toast.LENGTH_SHORT).show();
}
}
});
Asynctask Class:
public class PulltoRefreshAsync extends AsyncTask<Object,Object,Object> {
int refreshCount;
String refresh_URL;
public PulltoRefreshAsync(String url) {
refresh_URL = url;
}
/*
* PulltoRefreshAsync(int i) { refreshCount = i; }
*/
#Override
protected void onPreExecute() {
super.onPreExecute();
Log.e("Checking Purpose", refresh_URL);
}
#Override
protected String doInBackground(Object... arg0) {
JsonParserRefresh jp = new JsonParserRefresh();
Log.e("StroreActivity","Array to String::" + refresh_URL);
String jsonString = jp.getJSONFromURL(refresh_URL);
Log.e("StroreActivity","JsonString::" + jsonString);
jsonParseForCategoryBooksGridScroll(jsonString);
return null;
}
#Override
protected void onPostExecute(Object result) {
super.onPostExecute(result);
/*
* if(mProgressDialog.isShowing()) { mProgressDialog.dismiss(); }
*/
final MainBooksAdapter mainbooksAdpater = new MainBooksAdapter(
StoreActivity.this, R.layout.aa, mainBooksList);
final int old_pos = mainListView.getRefreshableView()
.getFirstVisiblePosition() + 1;
mainListView.setAdapter(mainbooksAdpater);
tvvisiblebookCount.setText("" + mainbooksAdpater.getCount());
/*if(listCountt < count_of_book)
{
mainListView.setMode(Mode.DISABLED);*/
mainListView.post(new Runnable() {
#Override
public void run() {
mainListView.onRefreshComplete();
mainListView.getRefreshableView().setSelection(old_pos);
}
});
//}
mainbooksAdpater.notifyDataSetChanged();
}
}
For other people who might have similat issue:
you don't have to implement it this way
mainListView.post(new Runnable() {
#Override
public void run() {
mainListView.onRefreshComplete();
mainListView.getRefreshableView().setSelection(old_pos);
}
});
instead do just like this :
mainListView.onRefreshComplete();
one more thing I noticed, instead of saving the old pos value to get back to it, why not just use notifyDataSetChanged it leaves the position of the list the way it is, just try not to re-instanciate you list, i.e: mainBooksList = ..., instead try this:
mainBooksList.clear();
mainBooksList.addAll(YOUR DATA);
adapter.notifyDataSetChanged();
voila!
hope this helps someone
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();
}