I have activity and when it is created it sends some requests, so it takes time to load this activity.
Is it possible to show "loading layout" while requests are proceeding?
I tried something like this, but it doesn't work:
setContentView(R.layout.loading);
sendRequests();
setContentView(R.layout.main);
To accomplish this, you could add a "loading layout" to your main layout.
Something like this:
<FrameLayout
android:id="#+id/loading_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Loading stuff" />
</FrameLayout>
Then when it is time to show your loading layout you can do:
FrameLayout loadingLayout = findViewById(R.id.loading_layout);
loadingLayout.setVisibility(View.VISIBLE);
When you want to hide it simply:
loadingLayout.setVisibility(View.GONE);
You will want to make sure that you do network requests off of the main thread, and return to the main thread whenever it is time to update the UI (i.e. show/hide the loading layout).
You can add a progress bar in activity or fragment.
If you are using Retrofit or etc., use this approach:
Set the progressbar visible before request
and invisible it when onResponse or onFailure called
binding.progressBar.setVisibility(View.VISIBLE);
// request
call.enqueue(new Callback<MovieResponse>() {
#Override
public void onResponse(Response<MovieResponse> response) {
Log.d(TAG, "onResponse is called");
// invisible progress bar here
binding.progressBar.setVisibility(View.INVISIBLE);
if (!response.isSuccess()) {
Log.d(TAG, "No Success");
}
mMovieList = response.body().getMovies(); // <- response is null here
mMovieAdapter.notifyDataSetChanged();
}
#Override
public void onFailure(Throwable t) {
Log.i(TAG, "onFailure is called");
// invisible progress bar here
binding.progressBar.setVisibility(View.INVISIBLE);
Toast.makeText(getActivity(), "Failed !", Toast.LENGTH_LONG).show();
}
});
You can create common class for custom progress dialog,
public class CustomProgressDialog extends Dialog {
public CustomProgressDialog(#NonNull Context context) {
super(context);
init(context);
}
public CustomProgressDialog(#NonNull Context context, int themeResId) {
super(context, themeResId);
init(context);
}
protected CustomProgressDialog(#NonNull Context context, boolean cancelable, #Nullable OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
init(context);
}
void init(Context context) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().getDecorView().getRootView().setBackgroundResource(android.R.color.transparent);
getWindow().setDimAmount(0.1f);
getWindow().getDecorView().setOnApplyWindowInsetsListener((v, insets) -> {
insets.consumeSystemWindowInsets();
return insets;
});
View view = LayoutInflater.from(context).inflate(
R.layout.dialog_custom, null
);
setContentView(view);
setCancelable(false);
setCanceledOnTouchOutside(false);
}
}
dialog_custom.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="10dp">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_centerHorizontal="true"
android:indeterminateTint="#color/colorPrimary" />
</RelativeLayout>
Declare this class in your activity or parent activity to use in every child classes,
public class BaseFragment extends Fragment {
protected CustomProgressDialog mDialog;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDialog = new CustomProgressDialog(requireActivity());
}
}
To show dialog before your api call
mDialog.show();
To dismiss dialog in response or error
mDialog.dismiss();
Related
I am using this code, everything are working fine, but progressbar is not showing. I want to block my ui during the method implementation and want to show progressbar. I want to get behaviour like progressDialog.
Here is my method
public void effct(int effectNo) {
final int finalEffectNO = effectNo;
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
progressLayout.setVisibility(View.VISIBLE);
progressLayoutLinear.setVisibility(View.VISIBLE);
Thread thread = new Thread(){
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
imageViewFragment.applyEffect(finalEffectNO);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
progressLayout.setVisibility(View.GONE);
progressLayoutLinear.setVisibility(View.GONE);
}
});
}
};
thread.start();
}
My xml code for progressLayout
<LinearLayout
android:id="#+id/progressBarLinearLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/colorPrimaryDark"
android:gravity="center"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:padding="12dp"
android:visibility="gone"
android:orientation="horizontal">
<ProgressBar
android:id="#+id/progressBar"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginRight="10dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Loading"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:textSize="18sp"/>
</LinearLayout>
For above your requirement you must use ProgressDialog for same, here is an example
Example
Try using an AsyncTask instead of Thread, something like this :
new AsyncTask<Void, Void, Void>() {
#Override
protected void onPreExecute() {
progressLayoutLinear.setVisibility(View.VISIBLE);
}
#Override
protected Void doInBackground(final Void ... params ) {
runOnUiThread(new Runnable() {
#Override
public void run() {
imageViewFragment.applyEffect(finalEffectNO);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
}
});
return null;
}
#Override
protected void onPostExecute( final Void result ) {
progressLayoutLinear.setVisibility(View.GONE);
}
}.execute();
Hope this helps
There’s a few ways to solve your problem - check this video for more information. The most basic approach might be an AsyncTask, which could look like this:
public class DummyAsyncTask extends AsyncTask<Void, Void, Void> {
private final Window window;
private final ProgressBar progressBar;
public DummyAsyncTask(Window window, ProgressBar progressBar) {
this.window = window;
this.progressBar = progressBar;
}
#Override protected void onPreExecute() {
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
progressBar.setVisibility(View.VISIBLE);
}
#Override protected Void doInBackground(Void... voids) {
// Do the heavy lifting.
}
#Override protected void onPostExecute(Void aVoid) {
window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
progressBar.setVisibility(View.GONE);
}
}
You execute it by running new DummyAsyncTask(/* params */).execute();.
Do note that AsyncTask does not adhere to the lifecycle and holding a reference to a Context aware instance is just asking for trouble. A safer alternative might be using LiveData:
public void effect(int effectNo) {
// Show progress and disable user interaction here.
final ListData<Content> data = model.applyEffect(effectNo);
data.observe(this, (Observer<Content>) c -> {
// Apply results, hide progress & enable user interaction.
});
}
Given the above, you should be careful how you handle showing & hiding progress, so you don’t accidentally disable user interaction forever.
I've to just show a count down fragment at certain trigger which includes a progress bar that reduces count on tick of a countdown timer.
I'm using following simple steps:
Call startTimer() in onCreateView of fragment.
In startTimer() define a CountDownTimer class where onTick method reduces progress of a ProgressBar and onFinish shows a Toast message.
Start this timer on UI thread using getActivity().runOnUIThread()
Problem is the timer executes but ProgressBar keeps showing indeterminate progress i.e. it remains unchanged. Toast is also seen at the finish but nothing changes for progress bar.
What's going wrong here?
Below is the current code:
public class IncomingRequestFragment extends Fragment {
private OnFragmentInteractionListener mListener;
private FrameLayout root;
private CountDownTimer mCountDownTimer;
private ProgressBar mProgressBar;
public IncomingRequestFragment() {
// Required empty public constructor
}
public static IncomingRequestFragment newInstance(String param1, String param2) {
IncomingRequestFragment fragment = new IncomingRequestFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
int progress=25;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
root = (FrameLayout) inflater.inflate(R.layout.fragment_incoming_request, container, false);
mProgressBar = (ProgressBar) root.findViewById(R.id.countDown);
progress = mProgressBar.getMax();
mProgressBar.setIndeterminate(false);
mProgressBar.setProgress(progress);
startTimer();
return root;
}
private void startTimer() {
mCountDownTimer = new CountDownTimer(25000,1000) {
#Override
public void onTick(long millisUntilFinished) {
mProgressBar.setProgress(progress--);
Log.d("count",String.valueOf(progress));
}
#Override
public void onFinish() {
Toast.makeText(getContext(),"You just missed a trip!",Toast.LENGTH_SHORT).show();
}
};
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
mCountDownTimer.start();
}
});
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
Layout XML:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.taxiwaxidriver.ui.fragments.IncomingRequestFragment">
<ProgressBar
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/countDown"
android:layout_margin="60dp"
android:max="25"
android:progressTint="#android:color/holo_blue_dark"
android:progressBackgroundTint="#android:color/holo_blue_dark"
android:progress="25"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:padding="12dp"
android:weightSum="2"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="#color/white"
android:text="REJECT"
android:id="#+id/rideLater"
android:background="#drawable/rounded_button_left"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="ACCEPT"
android:textColor="#color/white"
android:background="#drawable/rounded_button_right"
android:id="#+id/rideNow"/>
</LinearLayout>
</FrameLayout>
Output of above code is:
05-07 10:49:05.623 21455-21455 D/count: 24
05-07 10:49:06.626 21455-21455 D/count: 23
05-07 10:49:07.636 21455-21455 D/count: 22
05-07 10:49:08.653 21455-21455 D/count: 21
.
.
.
05-07 10:49:28.917 21455-21455 D/count: 1<br>
mistake was missing the style attribute for ProgressBar defined in XML
style=""?android:attr/progressBarStyleHorizontal"
Thanks to pskink's comment
I've got a FragmentActivity in which I fire an AsyncTask that gathers a list of data. This activity has a ListFragment and I want to update the listview as the data keeps coming.
I have another fragment that should also get the data, so I implemented some quick version of observer pattern, so that they both get notified when an element has been added to the list:
private void addElement(MyListElement item) {
myList.add(item);
Collections.sort(myList, Collections.reverseOrder());
notifyObservers();
}
private void notifyObservers() {
for(IListObserver dObserver: observers){
dObserver.updateList(myList);
}
}
But my list is never updated (or the other fragment, for the matter).
Here is the ListFragment code:
public class MyListFragment extends SherlockListFragment implements IListObserver{
private TextView first;
private Context mContext;
private List<MyListElement> myList;
private MyListAdapter myListAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
this.mContext = getActivity().getApplicationContext();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.layout_listview, container, false);
myList = new ArrayList<SizeDirectory>(0);
myListAdapter = new MyListAdapter(getActivity(), myList);
setListAdapter(myListAdapter);
myListAdapter.notifyDataSetChanged();
return view;
}
#Override
public void updateList(List<MyListElement> myList) {
this.myList = myList;
this.myListAdapter.notifyDataSetChanged();
getListView().requestLayout();
}
}
And this is the AsyncTask:
class ListLoader extends AsyncTask<String, MyListElement, Boolean> {
private String LOG_TAG = ListLoader .class.getSimpleName();
/**
* Maybe show loading indicator
*/
#Override
protected void onPreExecute() {
super.onPreExecute();
}
protected Boolean doInBackground(String... args) {
MyListElement item = getListItem(...)
publishProgress(item );
return true;
}
/**
* After completing background task Dismiss the progress dialog
**/
protected void onPostExecute(Boolean result) {
if (result) {
//Everything was ok
}
}
#Override
protected void onProgressUpdate(MyListElement... values) {
super.onProgressUpdate(values);
addElement(values[0]);
}
}
The funny thing is, if I put this AsyncTask in my ListFragment, and call updateList from there, then I do get the list updated as the asynctask progresses.
I though maybe this was due to the activity Lifecycle calling the onCreateView of my Fragment AFTER creating activity (and thus resetting the list) but I checked with debugger and it's not the case. I am also assuming this is not related to not being able to update UI from another thread since I do it from onProgressUpdate plus I would've gotten an Exception (or wouldn't I?).
EDIT: layout_listview
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/firstTextView"
android:layout_width="fill_parent"
android:layout_height="129dp"
android:scrollbars="vertical"
android:text="#string/hello_world" />
<Button
android:id="#+itd/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="Button" />
</RelativeLayout>
<ListView
android:id="#id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
After the updateList() call, your list adapter is still holding a reference to the original value of myList . Simply setting MyListFragment.myList won't update the adapter. You need a way of setting MyListAdapter's copy of the list. If this is one of the stock Android adapters you may need to create a new adapter for the new list and set it on the list fragment.
I've included a custom AlertDialog in my app. After updating my Galaxy Nexus to Jelly Bean the dialog is not displayed anymore. Only the screen is darkened. The processes around the dialog (like loading data) are working perfectly. On older OS versions the code worked (including ICS 4.0.4).
The problem appears no matter the dialog is created and shown in an AsyncTask or outside.
Has anybody similar problems?
Here is the code:
public class TLProgressDialog extends AlertDialog{
/*Log tag */
#SuppressWarnings("unused")
private static final String TAG = "TLProgressDialog";
#SuppressWarnings("unused")
private Context context;
private AnimationDrawable animation;
protected TLProgressDialog(Context context) {
super(context);
this.context = context;
}
public TLProgressDialog(Context context, boolean cancelable,
OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
this.context = context;
}
public TLProgressDialog(Context context, int theme) {
super(context, theme);
this.context = context;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tlprogressdialog);
ImageView img = (ImageView)findViewById(R.id.dialog_img);
img.setBackgroundResource(R.drawable.tlprogress_animation);
animation = (AnimationDrawable) img.getBackground();
img.post(new Starter());
}
public static TLProgressDialog show(Context context){
TLProgressDialog dlg = new TLProgressDialog(context);
dlg.setCanceledOnTouchOutside(false);
dlg.setCancelable(false);
dlg.show();
return dlg;
}
private class Starter implements Runnable {
public void run() {
animation.start();
}
}
}
The xml layout is just a single ImageView which hostes an animated image:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="#+id/dialog_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/>
</RelativeLayout>
Did you uncheck "Show notification" for your app? (check it in Settings/apps/ and "show notifications").
My fault, just found out that I've included GIF's for the animation. This seems not working anymore. After converting to PNG's it works again.
I made a simple extension of CheckBoxPreference so that I could have my own custom view with an image icon to the left of the title. The code is below:
public class CustomCheckBoxPreference extends CheckBoxPreference {
private Drawable icon;
public CustomCheckBoxPreference(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.CustomCheckBoxPreference, 0, 0);
icon = arr.getDrawable(R.styleable.CustomCheckBoxPreference_icon);
setLayoutResource(R.layout.custom_checkbox_pref);
}
#Override
protected void onBindView(View view) {
super.onBindView(view);
ImageView prefsIcon = (ImageView) view.findViewById(R.id.prefs_icon);
prefsIcon.setImageDrawable(icon);
}
The problem is that for some reason the OnPreferenceChangeListener I set to any CustomCheckboxPreference has no effect and is not stored. I tried overriding some of the android methods for the implementation calling super and then printing a line to see what gets called. Notably callChangeListener does not get called. It is this method that leads to the callback for onPreferenceChanged. I tried throwing in a call to onPreferenceChanged inside of setChecked just to see what would happen and the OnPreferenceChangeListener is null:
getOnPreferenceChangeListener().onPreferenceChange(this, checked);
This is how I set the preferencechangelistener:
mTwitterPref.setChecked(!mTwitter.needsAuth());
mTwitterPref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
System.out.println("Twitter Preference Changed!");
if ((Boolean) newValue) {
if (mTwitter.needsAuth()) {
System.out.println("We Need To Login To Twitter!");
IntentUtils.startActivityForResult(ProfileAccountsActivity.this,
TwLoginActivity.class, ACTIVITY_OAUTH);
}
} else {
showDialog(DIALOG_LOGOUT_TWITTER);
}
return false;
}
});
I am a bit confused as to why the preferencechangelistener is not working properly as I only overwrite onBindView and the constructor; I call super in both. Any thoughts?
Set android:focusable="false" and android:clickable="false" on the CheckBox:
<CheckBox
android:id="#+android:id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:clickable="false" />
More info on this thread: Clickable rows on custom ArrayAdapter
I had the same issue with custom button. I tried the solution provided by #jeanh and it works. But my button was not pressed, only area around it was highlighted. Moreover, what if you have a few buttons? Obviously, that this solution won't work. So, I decided to dig deeper and my solution was below:
xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/widget_frame" android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="15dp"
android:paddingTop="5dp"
android:paddingRight="10dp"
android:paddingBottom="5dp"
>
<!-- define my button -->
<Button android:id="#android:id/title"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="17sp"
android:typeface="sans"
android:textStyle="bold"
android:textColor="#000000"
></Button>
</RelativeLayout>
Java class:
public class ButtonPreference extends Preference {
private final String TAG = getClass().getName();
public interface ButtonListener {
public void onCustomClick();
}
public ButtonListener buttonListener;
public void setButtonListener(ButtonListener buttonListener){
this.buttonListener = buttonListener;
}
public ButtonPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ButtonPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected View onCreateView(ViewGroup parent){
RelativeLayout layout = null;
try {
LayoutInflater mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layout = (RelativeLayout)mInflater.inflate(R.layout.button_preference, parent, false);
//FIND OUR BUTTON IN LAYOUT
Button button = (Button) layout.findViewById(android.R.id.title);
if(button!=null){
Log.e(TAG, "button found");
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(buttonListener!=null){
buttonListener.onCustomClick(); //INVOKE OUR EVENT!
}
}
});
}
}
catch(Exception e)
{
Log.e(TAG, "Error creating info preference", e);
}
return layout;
}
}
HOW TO USE IT? Simple!
public class WallpaperSettings extends PreferenceActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.prefs);
ButtonPreference defaultSettingsButton = (ButtonPreference) findPreference(EngineCore.pref+"defaultSettings");
defaultSettingsButton.setButtonListener(new ButtonListener() {
#Override
public void onCustomClick() {
Gdx.app.log("ButtonListener", "onCustomClick");
}
});
}
}
I hope it helps someone else.
I found solution !
In my case, I extends DialogPreference to my custom Dialog class,
public class SvDialogPreference extends DialogPreference
I also confuse, because in PreferenceFragment, onPreferenceChange never worked.
SvDialogPreference pref= (SvDialogPreference) findPreference("mainKey");
if( pref != null ) {
pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
// Never execute !
}}
To resolve this. I called "super.callChangeListener" in onDialogClosed.
public class SvDialogPreference extends DialogPreference{
....
#Override
protected void onDialogClosed(boolean positiveResult) {
double InputValue = Double.parseDouble(KEY.getText().toString());
super.callChangeListener(InputValue);
super.onDialogClosed(positiveResult);
}
Now, onPreferenceChange worked fine !