I have a project which a activity have more than 1000 buttons. i am updating the background color of these buttons after taking the color information from the database. This whole process is a very big process and took 8 seconds to load my activity.
i have implement Asynctask for that but the problem is with this exception because "Only the original thread that created a view hierarchy can touch its views". because my long operation is on that part where i am updating my UI elements
After that i have implemented a thread that runs on UIthread for updating ui elements, this works fine according to its function, this thread update my ui but it stucks my application for 5-6 seconds. and then i thought of implementing a progress dialog for that 5-6 seconds. but if i implement progress dialog on runOnUiThread(new Runnable(){} it doesn't work. because updating ui and progress dialog runs on the same time. so progress dialog flashes for few milliseconds. and the activity still remains the same as it was before.
I don't know that to use for updating ui if they took long time to update.
This is my code where i update by ui elements from database.
for (int i = 0; i < list.size(); i++) {
Button btn = list.get(i);
Platform p = db.setplatformncolor(btn.getTag().toString());
String color = p.getColor();
if (color.equals("red")) {
btn.setBackgroundColor(Color.RED);
}
if (color.equals("green")) {
btn.setBackgroundColor(Color.rgb(0, 176, 80));
}
Any help is appreciated.
Thanks.!!
the for loop take two long time, try to just put the loop in thread and setBackgroundColor in ui thread.
new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < list.size(); i++) {
final Button btn = list.get(i);
Platform p = db.setplatformncolor(btn.getTag().toString());
String color = p.getColor();
if (color.equals("red")) {
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setBackgroundColor(Color.RED);
}
});
}
if (color.equals("green")) {
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setBackgroundColor(Color.rgb(0, 176, 80));
}
});
}
}
}
}).start();
You can declare a green button theme and a red button theme like this
<style name="RedButton" parent="#android:style/Widget.Button">
<item name="android:background">#android:color/holo_red_light</item>
</style>
<style name="GreenButton" parent="#android:style/Widget.Button">
<item name="android:background">#android:color/holo_green_light</item>
</style>
Then just apply the theme. The system will automatically apply your background color for all buttons. See here if want more details about themes switching.
AsyncTask can fix your problem. the most time consuming operation in this code is
db.setplatformncolor(btn.getTag().toString());
so you have to move this line into doInBackground() method and after adding to DB call publishProgress() also you should implement onProgressUpdate() and change your button backgrounds in this method
this might be a bit tricky and complex solution for starters , but is efficient and applicable to your requirement.
Android has launched DataBinding Library, which will update your XML dynamically , try it
https://developer.android.com/topic/libraries/data-binding/index.html
If your app api level >=11 and if you only need two colors, then you can create a drawable xml for your buttons' background like:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/red" android:state_activated="false" />
<item android:drawable="#color/green" android:state_activated="true"/>
and then just change btn.setActivated(true/false);
Related
For the moment I have two AppCompatActivity:
The main one, which only displays a launcher UI (i.e. : there is only my app's logo, shown in large size) (ConstraintLayout)
The home one, which displays both a Drawer navigation menu (DrawerLayout) and the real app's UI (ConstraintLayout).
I want to fade out my launcher UI during 2 seconds. After this animation, I will start the second Activity, which must be faded in.
How should I do this?
I looked for some fading-in and fading-out in the in ConstraintLayout and DrawerLayout but I didn't find them. The idea was to adjust their value within the onCreate event handler of the main and other Activity (for the ConstraintLayout of the main, and also for the DrawerLayout and ConstraintLayout of the other).
To fade out current activity:
Create a style in res/values:
<style name="PageTransition.Activity" parent="#android:style/Animation.Activity">
<item name="android:activityOpenEnterAnimation">#android:anim/fade_in</item>
<item name="android:activityOpenExitAnimation">#android:anim/fade_out</item>
<item name="android:activityCloseEnterAnimation">#android:anim/fade_out</item>
<item name="android:activityCloseExitAnimation">#android:anim/fade_in</item>
</style>
Then in your activiy's style which is usually Apptheme for MainActivity:
add this line :
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">#color/one</item>
<item name="colorPrimaryDark">#color/one</item>
<item name="colorAccent">#color/colorAccent</item>
name="android:windowAnimationStyle">#style/PageTransition.Activity</item>
</style>
To start next activity's UI delayed:
For your case, you'll need to use handler to delay transitions:
private final int interval = 1000; // 1 Second
private Handler handler = new Handler();
private Runnable runnable = new Runnable() {
public void run() {
ValueAnimator animator1 = ValueAnimator.ofInt(10, 0);
animator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float x = (Integer) valueAnimator.getAnimatedValue() / (float) 10;
yourview.setAlpha(x);
}
});
animator1.setDuration(500);
animator1.start();
}
Call this oncreate:
handler.postAtTime(runnable, System.currentTimeMillis() + interval);
handler.postDelayed(runnable, 2000); //two seconds
Obviously, you wanna set your initial alphas to 0.
Hope this helped!
EDIT:
Define your own fadein-fadeout anims if your want to customize duration...
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:interpolator/decelerate_quad"
android:fromAlpha="startalpha" android:toAlpha="endalpha"
android:duration="{YourDuration in ms}"/>
If the previous way fails for some APIs, use this before starting your activity:
...
overridePendingTransition(int enterAnim, int exitAnim);
startActivity(intent);
....
Can there be more than 2 items in transition drawable? I need to change background so second frames fades in than on top of it third does and so on to fourth...
for now I have this:
<?xml version="1.0" encoding="UTF-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/voting_button_not1"/>
<item android:drawable="#drawable/voting_button_not2"/>
<item android:drawable="#drawable/voting_button_not3"/>
<item android:drawable="#drawable/voting_button_not4"/>
<item android:drawable="#drawable/voting_button_not5"/>
<item android:drawable="#drawable/voting_button_not1"/>
</transition>
And I got the button:
<ImageButton android:id="#+id/skipButton"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/coldf1f2"
android:scaleType="fitCenter"
android:adjustViewBounds="true"/>
P.S. never mind that its an ImageButton, that doesn't make any difference.
And in my code I got smth like this:
TransitionDrawable vote_not = (TransitionDrawable)skip.getBackground();
vote_not.startTransition(1000);
It plays transition from first item to second. But I need the full list be played.
It seems like TransitionDrawable is meant to operate only with two layers. Taken from the Android documentation for the class:
An extension of LayerDrawables that is intended to cross-fade between
the first and second layer.
I think you can specify more than two layers, because this is extension of layered drawable, but in the case of the TransitionDrawable actually only the first two are used.
you can try this option using a handler
mAnimateImage is a imageView
and DrawableImage is an array with drawables
int DrawableImage[] = {R.drawable.back_red , R.drawable.back_green, R.drawable.back_purple};
final Handler handler = new Handler();
final int[] i = {0};
final int[] j = {1};
handler.postDelayed(new Runnable() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
Resources res = getApplicationContext().getResources();
TransitionDrawable out = new TransitionDrawable(new Drawable[]{res.getDrawable(DrawableImage[i[0]]), res.getDrawable(DrawableImage[j[0]])});
out.setCrossFadeEnabled(true);
mAnimateImage.setImageDrawable(out);
out.startTransition(4000);
i[0]++;
j[0]++;
if (j[0] == DrawableImage.length) {
j[0] = 0;
}
if (i[0] == DrawableImage.length) {
i[0] = 0;
}
handler.postDelayed(this, 8000);
}
});
}
}, 0);
You can do this with a combination of using a Handler and re-applying the TransitionDrawable for the elements of the array.
See my answer at https://stackoverflow.com/a/54584103/114549
Sounds like you might want AnimationDrawable:
http://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html
I've one menu button and a motion class for a longer state_pressed state (0,5 sec.). So long all works fine, but one problem occurs :
I've to press first time on my button, state_pressed doesn't work at this first time then on the second attempt my code works correctly and state_pressed works with 0,5 seconds duration.
How can I make it that it works on the first press? I think tehre is a problem with the hover.xml file and in combination with the setBackgroundDrawable?
Thanks all in advance for ur help!
This is my hover.XML drawable
<?xml version="1.0" encoding="utf-8"?>
<item android:state_focused="false"
android:state_pressed="true"
android:drawable="#drawable/buttonstyle_pressed" />
<item android:drawable="#drawable/buttonstyle" />
And this is my java code
Button menubutton_start;
menubutton_start = (Button) FindViewById(R.id.menustart);
menubutton_start.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
menubutton_start.setBackgroundDrawable(getResources().getDrawable(R.drawable.hover));
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
Intent myIntent = new Intent(GameActivity.this, NextActivity.class);
GameActivity.this.startActivity(myIntent);
}
}, 500); // end of Handler new Runnable()
} // end of OnClick()
}); // end of setOnClickListener
The pressed state will happen automatically if you apply that style to the button.
You shouldn't have to manually set the pressed state in your code at all.
my problem is, I have custom listView filled from Runnable returnRes. It fills particular data in layout I have named as lay (R.id.layoutList). My aim is to have different colour for each lay in my listView, I want to switch colours between each. 1st is dark blue, second light blue, thir dark blue and so on... This code is doing well, but with no result, my custom listView is still black, when I change it in XML, it is changing, but not when it is set from Java. Any ideas?
Thanks
private Runnable returnRes = new Runnable() {
#Override
public void run() {
if(myTasks != null && myTasks.size() > 0){
TasksAdapter.notifyDataSetChanged();
LinearLayout lay=(LinearLayout)findViewById(R.id.layoutList);
for(int i=0;i<myTasks.size();i++){
TasksAdapter.add(myTasks.get(i));
if(i>0){
if(i%2==0){
lay.setBackgroundColor(R.color.background);
}
}else{
if(i>0){
lay.setBackgroundColor(R.color.lightBlue);
}
}
}
}
ProgressDialog.dismiss();
TasksAdapter.notifyDataSetChanged();
}
};
Try googling. getResources().R.color.lightBlue is not the actual color, it's the id of
the color resource (which is an integer code for the color). It will work fine if you use it
in an API which expects ids of resources, but setBackgroundColor
actually needs the code of the color.
colors and ids are both just coded as int when you come down to it, so it's
really easy to confuse one for the other.
yourlayout.setBackgroundDrawable(getResources().getDrawable(R.drawable.yourbackgroundimage))
I need to display progress icon in button so that user can interact other GUI elements while background task is processing.
I have searched in Android developer site and found that we can use animated drawables but don't know how to use them. Please advise on the same.
The very simple way to do this without using the animated drawable is to use "PregressBar" component in the design layout xml. When u need to show it, just set it's visibility property to visible and when you need to hide it, u can set it's visibility property to GONE. But remember this is UI task so when u need to do this with non-UI thread, u need to use Handler to set the status of "ProgressBar" component at runtime.
Below id the component in the layout file.
<ProgressBar
android:id="#+id/progressBar1"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</ProgressBar>
Below is the code written in java file
ProgressBar prg;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main1);
prg=(ProgressBar)findViewById(R.id.ProgressBar1);
prg.setVisibility(ProgressBar.GONE);
}
public void start_background_process()
{
// starting the process
prg.setVisibility(ProgressBar.VISIBLE);
new Thread(new Runnable()
{ public void run()
{
// Do your background stuff here which takes indefinite time
mHandlerUpdateProgress.post(mUpdateUpdateProgress);
}
} ).start();
}
final Handler mHandlerUpdateProgress= new Handler();
final Runnable mUpdateUpdateProgress = new Runnable() {
public void run() {
// ending the process
prg.setVisibility(ProgressBar.GONE);
}
};
If the default progress indicator is good enough for you (i.e. the spinning wheel), then you can just use ProgressBar. To change it from a normal progress bar to a spinning wheel, use progressBar.setIndeterminate(true).