Hello guys I'm trying to update the UI after a short delay and for this I'm using handler's postdelayed method. The following code initially sets my textview text to "Processing" and the code that's included in the the handler's runnable gets executed but doesn't update the UI? Please note that this is done in a Fragment
TextView progressText=(TextView)parent.findViewById(R.id.inProgressText);
progressText.setText("Processing");
getActivity().getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
TextView progressText=(TextView)parent.findViewById(R.id.inProgressText);
progressText.setText("Request completed");
}
}, 3000);
Thanks for your help
Change
getActivity().getMainLooper()).postDelayed(new Runnable()
to:
final Handler handler = new Handler();
Then
handler.postDelayed(new Runnable() {
#Override
public void run() {
final TextView progressText=(TextView)findViewById(R.id.inProgressText);
progressText.setText("Request completed");
}
}, 3000);
Use this code
public class MainActivity extends Activity {
TextView progressText = null;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.activity_main, container, false);
progressText = (TextView) rootView.findViewById(R.id.inProgressText);
progressText.setText("Processing");
progressText.postDelayed(new Runnable() {
#Override
public void run() {
progressText.setText("Request completed");
}
}, 3000);
return rootView;
}
}
Please try this way : I checked in Fragement and it is working perfectly.
View parent= inflater.inflate(R.layout.your_fragement, container, false);
TextView progressText=(TextView)parent.findViewById(R.id.inProgressText);
progressText.setText("Processing");
progressText.postDelayed(new Runnable() {
#Override
public void run() {
progressText.setText("Request completed");
}
}, 3000);
Related
I am developing an application on Android.
I have an issue with a Fragment, the code can be found below.
The idea is to have an Image View display a list of Picture in an infinite loop. In order to realize this, I have created a new Thread, so as not to block the UI Thread. With a while (0 < 5) statement I create an infinite loop. Then I run an if...else statement to check on which Picture we are to determine the next picture to go to.
A Handler is used to take care of the 10 seconds delay between switching pictures. And finally another runnable takes care of the posting to the UI Thread.
This seems like a very complicated way of getting things done, anyone used the simpler code?
On top of that, somewhere in my code, there is an error. I cannot spot it, anyone?
Here is my code.
public class SecAct_Foto_Fragment extends Fragment {
int counter = 0;
View rootView;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.sec_act_photo_layout, container, false);
return rootView;
}
Thread myThread = new Thread(new Runnable() {
#Override
public void run() {
while (0 < 5) {
//so far it loops only once
//you start with run_rocks and but_left
final ImageView pic_view = (ImageView) rootView.findViewById(R.id.foto_groot);
final ImageView three_but = (ImageView) rootView.findViewById(R.id.knoppen);
//create a runnable for the picture view
pic_view.post(new Runnable() {
#Override
public void run() {
//every 10 seconds, switch picture and button fragment
if (counter == 0) {
final Handler handler0 = new Handler();
handler0.postDelayed(new Runnable() {
#Override
public void run() {
pic_view.post(new Runnable() {
#Override
public void run() {
pic_view.setImageResource(R.drawable.run_mount);
}
});
counter = 1;
}
}, 10000L);
} else if (counter == 1) {
final Handler handler1 = new Handler();
handler1.postDelayed(new Runnable() {
#Override
public void run() {
pic_view.post(new Runnable() {
#Override
public void run() {
pic_view.setImageResource(R.drawable.run_away);
}
});
counter = 2;
}
}, 10000L);
} else {
final Handler handler2 = new Handler();
handler2.postDelayed(new Runnable() {
#Override
public void run() {
pic_view.post(new Runnable() {
#Override
public void run() {
pic_view.setImageResource(R.drawable.run_rocks);
}
});
counter = 0;
}
}, 10000L);
}
}
});
myThread.start();
}
}
});
}
private class AsyncQueryRun extends AsyncTask {
#Override
protected Object doInBackground(Object[] objects) {
for (...){
////do what you want
runOnUiThread(new Runnable() {
#Override
public void run() {
///do what you want to be handled by UI thread
}});
SystemClock.sleep(60); ////wait as long as you want in mili sec.
}
}
#Override
protected void onPostExecute(Object o) {
}
}
You can use Handler in following way :
final ImageView pic_view = (ImageView) rootView.findViewById(R.id.foto_groot);
private int animationCounter = 1;
private Handler imageSwitcherHandler;
imageSwitcherHandler = new Handler(Looper.getMainLooper());
imageSwitcherHandler.post(new Runnable() {
#Override
public void run() {
switch (animationCounter++) {
case 1:
pic_view.setImageResource(R.drawable.run_mount);
break;
case 2:
pic_view.setImageResource(R.drawable.run_mount2);
break;
case 3:
pic_view.setImageResource(R.drawable.run_mount3);
break;
}
animationCounter %= 4;
if(animationCounter == 0 ) animationCounter = 1;
imageSwitcherHandler.postDelayed(this, 3000);
}
});
I have decided to try the solution of #NehaK and work with the ImageSwitcher View.
Added the following code in XML..
<ImageSwitcher
android:id="#+id/foto_groot_imageswitch"
android:layout_width="match_parent"
android:layout_height="220dp"
app:srcCompat="#drawable/run_rocks"
/>
Then used it in my Fragment..
public class SecAct_Foto_Fragment extends Fragment {
int counter = 0;
View rootView;
private ImageSwitcher pic_image_switch;
private Handler pic_image_switch_handler;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.sec_act_photo_layout, container, false);
/*Animation anim_in = AnimationUtils.loadAnimation(getActivity(), R.anim.enter_from_left);
pic_image_switch.setInAnimation(anim_in);*/
//pic_image_switch = new ImageSwitcher(getActivity());
pic_image_switch = (ImageSwitcher) rootView.findViewById(R.id.foto_groot_imageswitch);
pic_image_switch.setFactory(new ViewSwitcher.ViewFactory() {
#Override
public View makeView() {
ImageView imageView = new ImageView(getActivity());
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
imageView.setLayoutParams(new ImageSwitcher.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
return imageView;
}
});
pic_image_switch_handler = new Handler(Looper.getMainLooper());
pic_image_switch_handler.post(new Runnable() {
#Override
public void run() {
switch (counter) {
case 0:
pic_image_switch.setImageResource(R.drawable.run_mount);
break;
case 1:
pic_image_switch.setImageResource(R.drawable.run_away);
break;
case 2:
pic_image_switch.setImageResource(R.drawable.run_rocks);
break;
}
counter += 1;
if (counter == 3) {
counter = 0;
}
pic_image_switch.postDelayed(this, 1000);
}
});
return rootView;
}
}
I know
if I want to use a thread in UI group, must use a handler.
because, android UI is single thread model.
so, If another thread accesses the UI,
occur
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
so I use handler
but same occur error message.
private static TextView sTextView; //global variable
public void showText(final TextView textView) {
sTextView = textView;
sTextView.findViewById(R.id.text);
Looper.prepare();
final Handler handler = new Handler();
new Thread(new Runnable() {
#Override
public void run() {
handler.post(new Runnable() {
#Override
public void run() {
sTextView.setText("123123123");
}
});
}
}).start();
Looper.loop();
}
and showText called
private VideoCapture videoCapture; //global variable
private TextView mText; //global variable
public void beginCapture() {
videoCapture.showText(mText);
}
and I build. but occur error.
It should be the UI thread, not any random thread.
For fragment:
((Activity)mContext).runOnUiThread(new Runnable() {
#Override
public void run() {
sTextView.setText("123123123");
}
});
For Activity:
MyActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
sTextView.setText("123123123");
}
});
Thats it, you don't need any Handlers or Loopers or Threads just the above lines of code.
I have a Fragment which sets up a ListView and creates a Handler to update the Listview periodically. However, it looks like the Handler still runs after the Fragment has been destroyed.
The following is the code.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//boilerplate code
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
assignAdapter();
handler.postDelayed(this, 15000);
}
});
return v;
}
Updating the ListView after the destruction of the Fragment causes the app to crash. How can I cause the Handler to stop as the Fragment gets destroyed? I would also like to know what effects if any pausing the app has on the Handler as well.
You need to implement handler like this
private Handler myHandler;
private Runnable myRunnable = new Runnable() {
#Override
public void run() {
//Do Something
}
};
#Override
public void onDestroy () {
mHandler.removeCallbacks(myRunnable);
super.onDestroy ();
}
You need to store a reference to your handler and runnable in the fragment, and then when the fragment is destroyed you need to remove callbacks from the handler passing in the runnable.
private Handler mHandler;
private Runnable mRunnable;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//boilerplate code
mRunnable = new Runnable() {
#Override
public void run() {
assignAdapter();
handler.postDelayed(this, 15000);
}
};
mHandler = new Handler(mRunnable);
mHandler.post();
return v;
}
#Override
public void onDestroy() {
mHandler.removeCallbacks(mRunnable);
super.onDestroy();
}
Another way of stopping the handler with the use of WeakReference to the fragment:
static final class UpdateUIRunnable implements Runnable {
final WeakReference<RouteGuideFragment> weakRefToParent;
final Handler handler;
public UpdateUIRunnable(RouteGuideFragment fragment, Handler handler) {
weakRefToParent = new WeakReference<RouteGuideFragment>(fragment);
this.handler = handler;
}
public void scheduleNextRun() {
handler.postDelayed(this, INTERVAL_TO_REDRAW_UI);
}
#Override
public void run() {
RouteGuideFragment fragment = weakRefToParent.get();
if (fragment == null || fragment.hasBeenDestroyed()) {
Log.d("UIUpdateRunnable", "Killing updater -> fragment has been destroyed.");
return;
}
if (fragment.adapter != null) {
try {
fragment.adapter.forceUpdate();
} finally {
// schedule again
this.scheduleNextRun();
}
}
}
}
where fragment.hasBeenDestroyed() is simply a getter for mDestroyed property of a fragment:
#Override
public void onDestroy() {
super.onDestroy();
mDestroyed = true;
}
Someone posted another question similar and the problem is due to a bug in the ChildFragmentManager. Basically, the ChildFragmentManager ends up with a broken internal state when it is detached from the Activity. Have a look at the original answer here
I have a set of methods and each method takes time to do its task.
For instance,
After Method setRules() is executed,
The progress level should increase to 30.
After Method getLogs() is executed,
The progress level should increase to 60.
After Method getChartView() is executed,
The progress level should increase to 100.
But the ProgressBar increases till 30 and not goes beyond that although my all the methods are executing.
Code -
public class DialogPopup extends DialogFragment
{
private static int myProgress=0;
private ProgressBar progressBar;
private int progressStatus=0;
private Handler myHandler=new Handler();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
super.onCreateView(inflater, container, savedInstanceState);
view = inflater.inflate(R.layout.main,container, false);
progressBar = (ProgressBar) view.findViewById(R.id.progressBar1);
beginYourTask();
return view;
}
public void beginYourTask()
{
myProgress=0;
progressBar=(ProgressBar)view.findViewById(R.id.myProgress);
progressBar.setMax(100);
//progressBar.setVisibility(View.VISIBLE);
/*Do some work in background thread*/
new Thread(new Runnable()
{
#Override
public void run()
{
progressStatus=setRules();
myHandler.post(new Runnable()
{
public void run()
{
progressBar.setProgress(progressStatus);
}
});
progressStatus=getLogs();
myHandler.post(new Runnable()
{
public void run()
{
progressBar.setProgress(progressStatus);
}
});
progressStatus=getChartView();
myHandler.post(new Runnable()
{
public void run()
{
progressBar.setProgress(progressStatus);
}
});
/*Hides the Progress bar*/
myHandler.post(new Runnable()
{
#Override
public void run()
{
progressBar.setVisibility(View.GONE);
progressStatus=0;
myProgress=0;
}
});
}
private int setRules()
{
//Code here takes time
//set progress to 30
return 30;
}
private int getLogs()
{
//Code here takes time
//set progress to 60
return 60;
}
private int getChartView()
{
//Code here takes time
//set progress to 100
return 100;
}
}).start();
}
NOTE:
I took the help to create such Progress Bar from the tutorial -android-progress-bar-horizontal.
Use an AsyncTask for this kind of thing:
public void beginYourTask()
{
new AsyncTask<Void, Integer, Void>(){
#Override
public Void doInBackground(Void...params){
publishProgress(setRules());
publishProgress(getLogs());
publishProgress(getChartView());
return null;
}
#Override
public void onProgressUpdate(Integer... progress) {
progressBar.setProgress(progress[0]);
}
#Override
public void onPostExecute(Void result){
progressBar.setVisibility(View.GONE);
}
}.execute();
}
That's the idea, there may be typos.
The tutorial from your link hasn't been updated for a while and normally you don't want to use a Thread in this situation because AsyncTask is designed to save you from all the thread problems you would encounter while using Thread
Read the documentation on this and you'll know when to use a Thread or an AsyncTask
I'm trying to code a timer for Android, but I'm getting problems with the handler. This line:
handler.post(new Runnable(){
...is triggering a NullPointerException. Why?
public class HomeFragment extends Fragment {
private int stunde,minute,sekunde;
private TextView textfield;
private Button buttonStart,buttonStop;
private Handler handler;
private boolean Running = true;
private Runnable runnable;
private Thread thread;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
buttonStart =(Button) rootView.findViewById(R.id.button1);
buttonStop = (Button) rootView.findViewById(R.id.button2);
buttonStop.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
thread.stop();
}
});
textfield = (TextView) rootView.findViewById(R.id.startZeit);
buttonStart.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
Running = true;
runnable = new Runnable(){
#Override
public void run() {
while(Running){
try{
Thread.sleep(1000);
}
catch(InterruptedException e){
e.printStackTrace();
}
handler.post(new Runnable(){
#Override
public void run(){
sekunde+=1;
if(sekunde == 60){
minute +=1;
sekunde = 0;
}if(minute == 60){
stunde +=1;
}
textfield.setText(String.format("%02d",stunde)+" : "+String.format("%02d", minute)+" : "+String.format("%02d",sekunde));
}
});
}
}
};
thread = new Thread(runnable);
thread.start();
handler = new Handler();
}
});
return rootView;
}
}`
Your handler has to be instantiated with
handler = new Handler();
before it is used.
Your formatting is quite hard to read but you get a NPE if runnable or handler have not been initialised. Since you are providing a new runnable object, that means your handler has not been initialised.
I think you are creating your handler inside an onClickListener. Try initialising it in onCreate or towards the top of onCreateView for clarity.
Goodluck
Because you didn't initialized the handler object. So you are getting a NullPointerException on it.
You will need to do some thing like that:
Handler handler = new Handler();
Somewhere in your code before you can use this object.