Android - Nested Handler / Runnable - java

My application content part had too much code. There were about 3000 lines of XML code. This caused my application to startup slowly. (launch in about 8 seconds) I placed the content in 6 viewstub objects. and I created a lot of handlers. Is it a problem? Is it hierarchically correct? How can I do all these handler operations asynctask.
Also how can I make my content lighter and faster.
Thanks in advance!
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
viewStubPager.setLayoutResource(R.layout.viewstubpager);
coachStubPager = viewStubPager.inflate();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
viewStub1.setLayoutResource(R.layout.viewstub1);
coachStub1 = viewStub1.inflate();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
viewStub2.setLayoutResource(R.layout.viewstub2);
coachStub2 = viewStub2.inflate();
viewStub3.setLayoutResource(R.layout.viewstub3);
coachStub3 = viewStub3.inflate();
viewStub4.setLayoutResource(R.layout.viewstub4);
coachStub4 = viewStub4.inflate();
viewStub5.setLayoutResource(R.layout.viewstub5);
coachStub5 = viewStub5.inflate();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Objects.requireNonNull(notificationManager).cancelAll();
sharedPreferencesKeys();
initialize();
calculate();
sharedPrefStartup();
alertDialogClickListener();
changeListener();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
layouts = new int[]{R.layout.vki_slide1, R.layout.vki_slide2, R.layout.vki_slide3, R.layout.vki_slide4, R.layout.vki_slide5, R.layout.vki_slide6, R.layout.vki_slide7, R.layout.vki_slide8, R.layout.vki_slide9};
VKIPagerAdapter = new MyViewPagerAdapter();
vkipager.setAdapter(VKIPagerAdapter);
VKIPagerAdapter.notifyDataSetChanged();
vkipager.setOffscreenPageLimit(10);
vkipager.addOnPageChangeListener(viewPagerPageChangeListener);
pageIndicator.setCount(layouts.length);
pageIndicator.setSelection(0);
bottombar.setVisibility(View.VISIBLE);
}
}, 100);
}
}, 100);
}
}, 100);
}
}, 100);
}
}, 150);

It's a bit late, but this might help others...
I don't know if the code in the question will start faster with my proposed solution (I doubt this will be the case), however, it's way more readable and uses only one Runnable. This can also be used for animations.
I derived this example from the following answer:
https://stackoverflow.com/a/11198037/6423246
Handler mHandler = new Handler();
int inflater = YOUR_CONSTANT_1;
void yourFunction() {
// ...your first inflater code here...
mHandler.postDelayed(mRunnable, your_delay_in_millis);
}
Runnable mRunnable = new Runnable() {
#Override
public void run() {
switch(inflater) {
case YOUR_CONSTANT_1 : {
// ...your second inflater code here...
inflater = YOUR_CONSTANT_2;
mHandler.postDelayed(mRunnable, your_delay_in_millis);
break;
}
case YOUR_CONSTANT_2 : {
// ...your third inflater code here...
inflater = YOUR_CONSTANT_3;
mHandler.postDelayed(mRunnable, your_delay_in_millis);
break;
}
// etcetera
case YOUR_CONSTANT_LAST : {
// ...your last inflater code here...
// in your final case, you could opt to remove callbacks
mHandler.removeCallbacks(mRunnable);
break;
}
}
}
};

Related

How to display different image after another with Glide?

I want to display an other image after a delay. Here is my code:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView imageView=findViewById(R.id.imageView);
ArrayList<String> test = new ArrayList<String>();
test.add("e");
test.add("a");
if (test.get(0) == "e") {
Glide.with(this)
.load("https://something.something/something.jpg")
.into(imageView);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (test.get(1) == "a") {
Glide.with(this)
.load("https://something.something/something2.jpg")
.into(imageView);
}
}
}
But only the 2nd image apppears if i do that. Any solution?
Create a new method
private void loadImage(String imageLink){
Glide.with(this).load(imageLink).into(imageView);
}
now simply call this where you want to load first image and second image in the same imageView
loadImage("imageLink");
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do something after 3sec
loadImage("next ImageLink");
}
}, 3000);
Something like this, you can also modify loadImage method so it can also accept ImageView as a parameter if you want to load images in different ImageView with delay
if (test.get(0) == "e") {
loadImage("https://something.something/something.jpg");
}
if (test.get(1) == "a") {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do something after 3sec (3000 = 3 sec)
loadImage("https://something.something/something2.jpg");
}
}, 3000);
}
Hope this will help!
Edit 1:
if you want to load both pics with delay use
if (test.get(0) == "e") {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do something after 3sec (3000 = 3 sec)
loadImage("https://something.something/something.jpg"); // image 1
}
}, 3000);
}
if (test.get(1) == "a") {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do something after 3sec (3000 = 3 sec)
loadImage("https://something.something/something2.jpg"); // image 2
}
}, 3000);
}

Can I use startForeground(id, notification) in a service to update notification progress bar properly?

I have a situation where I need to update the notification progress bar after some few more milliseconds. If I use notification manager to update the progress, then the notification will show up even after calling stopForground(true) which is not what I need.
Here is the sample code using the notification manager to update.
private void doStuff() {
// starting in foreground
startForeground(123, notification.build());
final Thread thread = new Thread(new Runnable() {
#Override
public void run() {
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
timer++;
if(timer > 10){
stopForeground(true);
stopSelf();
return;
}
if(!bound){
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
notificationManager.notify(123, notification.setProgress(10, timer, false).build());
}
}, 2000);
}
handler.postDelayed(this, 1000);
}
}, 1000);
}
});
thread.start();
}
otherwise, if I use startForground() way, the notification won't show up after the 2000 milliseconds and I get the desired behavior as shown below:
private void doStuff() {
// starting in foreground
startForeground(123, notification.build());
final Thread thread = new Thread(new Runnable() {
#Override
public void run() {
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
timer++;
if(timer > 10){
stopForeground(true);
stopSelf();
return;
}
if(!bound){
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
startForeground(123, notification.setProgress(10, timer, false).build());
}
}, 2000);
}
handler.postDelayed(this, 1000);
}
}, 1000);
}
});
thread.start();
}
My question is if there would be something wrong I'm not aware of using this way because I have never seen anyone doing it. Please help! Thanks!

Execute function after 5 seconds in Android

I am new in android development and now my launcher activity show only 5 seconds and after that I want to check the user is logged in or not function and perform the actions.
here is my code.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
exactPreferences = getSharedPreferences("ExactPreference",MODE_PRIVATE);
setContentView(R.layout.activity_landing_page);
session = exactPreferences.getString(Model.getSingleton().SHARED_SESSION_ID,null);
Log.i("Session Id",session);
displayData(); // I want to perform this function after 5 seconds.
}
private void displayData() {
if(session.equals("")){
Intent loginIntent = new Intent(LandingPage.this,
LoginActivity.class);
startActivity(loginIntent);
Log.i("User Logged In", "False");
}
else
{
Intent objIntent = new Intent(LandingPage.this,
IndexPageActivity.class);
startActivity(objIntent);
Log.i("User Logged In", "True");
}
}
You can use the Handler to add some delay.Call the method displayData() as below so that it will be executed after 5 seconds.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
displayData();
}
}, 5000);
Note : Do not use the threads like Thread.sleep(5000); because it will block your UI and and makes it irresponsive.
Assign millisDelayTime variable with the milliseconds you desire to cause a delay. mActivity is an object of Activity for providing Application Context. In your case millisDelayTime should be initialized with 5000
mActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//your code here
}
}, millisDelayTime);
}
});
Use a CountDownTimer
// There's a TextView txtCount in Main Activity
final int secs = 5;
new CountDownTimer((secs +1) * 1000, 1000) // Wait 5 secs, tick every 1 sec
{
#Override
public final void onTick(final long millisUntilFinished)
{
txtCount.setText("" + (int) (millisUntilFinished * .001f));
}
#Override
public final void onFinish()
{
txtCount.setText("GO!");
finish();
// Time's up - Start the Login Activity
final Intent tnt =
new Intent(getApplicationContext(), LoginActivity.class);
startActivity(tnt);
}
}.start();
Since, Handler is now deprecated so use this code :
new Handler(Looper.myLooper()).postDelayed(new Runnable() {
#Override
public void run() {
//do what you want
}
}, 5000);
Try this, code create CountDownTimer with one tick
timer = new CountDownTimer(5000, 5000)
{
public void onTick(long millisUntilFinished)
{
}
public void onFinish()
{
displayData();
}
};
timer.start();
long delay = 1000;
long period = 50000;
Timer task = new Timer();
task.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
getDriver(sessionManager.getKEY(), ride_id);
}
}, delay, period);
For kotlin way
Handler().postDelayed({
//do something
}, 5000)
When possible, try to avoid using postDelayed. It is a bad practice, since it can lose the reference to the objects that you want to draw on your screen and cause a NPE. Use a Handler instead. First of all, create a global variable Handler in which you will have to "handle" the logic for your code. Do so by using the function handleMessage.
Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
if(msg.what == 1){
// your code here
}
}
};
Then, wherever you want to execute it, just call the function:
// 1 is the ID of your process
handler.sendEmptyMessageDelayed(1, 5000);
Please remember that in the onDestroyView method (in a Fragment) or the onDestroy (in an Activity) you will have to call
handler.removeMessages(1)
The best option to achieve this is using a Handler:
int TIME = 5000; //5000 ms (5 Seconds)
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
function(); //call function!
}
}, TIME);

Calling from wrong thread exception

I am trying to develop an application, that uses threads to implement slideshow. I am retrieving the image path from SQLite and displaying them on the ImageView. The problem, where I got struck is, I got confused and so I am unable to understand, from which thread I am calling images() method, where I am actually implementing the slideshow.
I got the Logcat as follows -
09-03 13:47:00.248: E/AndroidRuntime(10642): FATAL EXCEPTION: Thread-151
09-03 13:47:00.248: E/AndroidRuntime(10642): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
09-03 13:47:00.248: E/AndroidRuntime(10642): at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:5908)
09-03 13:47:00.248: E/AndroidRuntime(10642): at com.example.fromstart.MainActivity.images(MainActivity.java:90)
09-03 13:47:00.248: E/AndroidRuntime(10642): at com.example.fromstart.MainActivity$2.run(MainActivity.java:59)
09-03 13:47:00.248: E/AndroidRuntime(10642): at java.lang.Thread.run(Thread.java:841)
MainActivity.java:
public class MainActivity extends Activity
{
ImageView jpgView;
TextView tv;
//adapter mDbAdapter;
adapter info = new adapter(this);
String path;
Handler smHandler = new Handler()
{
public void handleMessage(Message msg)
{
TextView myTextView =
(TextView)findViewById(R.id.textView1);
myTextView.setText("Button Pressed");
}
};
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
jpgView = (ImageView)findViewById(R.id.imageView1);
tv = (TextView) findViewById(R.id.textView1);
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
final Runnable runnable = new Runnable()
{
public void run()
{
images();
}
};
int delay = 1000; // delay for 1 sec.
int period = 15000; // repeat every 4 sec.
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask()
{
public void run()
{
smHandler.post(runnable);
}
}, delay, period);
Thread mythread = new Thread(runnable);
mythread.start();
return true;
}
public void handleMessage(Message msg)
{
String string = "sample";
TextView myTextView = (TextView)findViewById(R.id.textView1);
myTextView.setText(string);
}
public void images()
{
try
{
for(int i=0;i<=20;i++)
{
path = info.getpath();
Bitmap bitmap = BitmapFactory.decodeFile(path);
jpgView.setImageBitmap(bitmap);
}
}
catch(NullPointerException er)
{
String ht=er.toString();
Toast.makeText(getApplicationContext(), ht, Toast.LENGTH_LONG).show();
}
}
}
I am a newbie to android, just now started working on Threads. If you find any mistakes in my code, please point out those and please suggest me, the right way to deal with this problem.
Thanks in advance.
UPDATE:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Handler mHandler = new Handler();
// Create runnable for posting
runOnUiThread(new Runnable()
{
public void run()
{
images();
}
});
int delay = 1000; // delay for 1 sec.
int period = 15000; // repeat every 4 sec.
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask()
{
public void run()
{
images();
}
}, delay, period);
}
public void images()
{
try
{
Toast.makeText(getApplicationContext(), "1", Toast.LENGTH_LONG).show();
path = info.getpath();
Toast.makeText(getApplicationContext(), "2", Toast.LENGTH_LONG).show();
Bitmap bitmap = BitmapFactory.decodeFile(path);
Toast.makeText(getApplicationContext(), "3", Toast.LENGTH_LONG).show();
jpgView.setImageBitmap(bitmap);
Toast.makeText(getApplicationContext(), "4", Toast.LENGTH_LONG).show();
}
catch(NullPointerException er)
{
String ht=er.toString();
Toast.makeText(getApplicationContext(), ht, Toast.LENGTH_LONG).show();
}
}
}
You cannot update/access ui from from a thread.
You have this
public void run()
{
images();
}
And in images you have
jpgView.setImageBitmap(bitmap);
You need to use runOnUiThread for updating ui.
runOnUiThread(new Runnable() {
#Override
public void run() {
// do something
}
});
TimerTask also runs on a different thread. So you have use a Handler for updati ui.
You can use a handler.
Edit:
Handler m_handler;
Runnable m_handlerTask ;
m_handler = new Handler();
m_handlerTask = new Runnable()
{
#Override
public void run() {
// do something. call images()
m_handler.postDelayed(m_handlerTask, 1000);
}
};
m_handlerTask.run();
If you still wish to use a timer task use runOnUiThread
timer.scheduleAtFixedRate(new TimerTask()
{
public void run()
{
runOnUiThread(new Runnable() {
#Override
public void run() {
images();
}
});
}
}, delay, period);
To update UI from any other Thread you must use
runOnUiThread(<Runnable>);
which will update your UI.
Example:
runOnUiThread(
new Runnable()
{
// do something on UI thread Update UI
});

How to stop series of postDelayed handlers

I have a series of postDelayed handlers. I'm having trouble to set a mathode that stops the handlers when the user is tapping on the stop button at any time I he wants.
I'll appreciate any help someone able to provide.
Thanks
while (!lessonIsRunning) {
Handler handler0 = new Handler();
handler0.postDelayed(new Runnable() {
#Override
public void run() {
plate1.setVisibility(ImageView.VISIBLE);
plate2.setVisibility(ImageView.VISIBLE);
plate3.setVisibility(ImageView.VISIBLE);
}
}, 6000);
Handler handler1 = new Handler();
handler1.postDelayed(new Runnable() {
#Override
public void run() {
apples1.setVisibility(ImageView.VISIBLE);
}
}, 9000);
Handler handler2 = new Handler();
handler2.postDelayed(new Runnable() {
#Override
public void run() {
plus1.setVisibility(TextView.VISIBLE);
}
}, 9250);
}
public void stopLesson(View V){
}
instead of writing the Runnable task in an anonymous way you must define it with a name, so that later you will have a link to it to remove:
//there is no need for multiple handlers
//handler must be declared outside all functions, in order for you to use it everywhere.
Handler handler = new Handler();
Runnable myFirstTask = new Runnable (){
#Override
public void run() {
plate1.setVisibility(ImageView.VISIBLE);
plate2.setVisibility(ImageView.VISIBLE);
plate3.setVisibility(ImageView.VISIBLE);
} };
Runnable mySecondTask = new Runnable(){
#Override
public void run() {
plus1.setVisibility(TextView.VISIBLE);
}
};
Runnable myThirdTask = new Runnable(){
#Override
public void run() {
apples1.setVisibility(ImageView.VISIBLE);
} }
//you can put different tasks on the same handler object
while (!lessonIsRunning) {
handler.postDelayed(myFirstTask,6000);
handler.postDelayed(mySecondTask,9250);
handler.postDelayed(myThirdTask,9000);
}
public void stopLesson(View V){
//notice that you don't need these, because the handlers are not recursive
//you don't have lines "handler.postDelayed(sameTask,someTime);"
//in your run Method of the runnable
if(handler!=null){
handler.removeCallbacks(myFirstTask);
handler.removeCallbacks(mySecondTask);
handler.removeCallbacks(myThirdTask);
//if this method is inside onPause or onDestroy add this line as well:
handler=null;
}
}
you can give
handler0.removeCallbacksAndMessages(null);
handler1.removeCallbacksAndMessages(null);
handler2.removeCallbacksAndMessages(null);
a try. The doc says when you submit a null token all callbacks and message are removed.

Categories

Resources