I have a fragment with a listview.
When I click on the Navigation Drawer to open this fragment it takes 2-3 seconds to load.
I make an API call from AsyncTask. I call it from my onResume() in my fragment because I want to inflate the layout and then call the API and show ProgressDialog in opened fragment and wait for the AsyncTask to finish then populate ListView. Problem is that my fragment takes 2-3 seconds(frozen screen) and then loads completely with API call finished and list populated. There is no way to show fragment and than populate list. I tried in all Override methods in fragment. Always the same result. Also when I remove all code from fragment, it loads fast.
Any tips why is that happening?
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_history, container, false);
historySearchET = (EditText) v.findViewById(R.id.historySearchEditText);
listview = (ListView) v.findViewById(R.id.historyListView);
emptyView = v.findViewById(R.id.empty);
return v;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
historySearchET.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
#Override
public void afterTextChanged(Editable s) {
Log.d("aaa", "*** Search value changed: " + s.toString());
adbHistory.getFilter().filter(s.toString());
listview.setAdapter(adbHistory);
}
});
}
#Override
public void onResume() {
super.onResume();
APIManager apiManager = APIManager.getInstance(getActivity());
historyList = apiManager.getUserHistroy();
adbHistory= new HistoryAdapter (getActivity(), 0, historyList);
listview.setAdapter(adbHistory);
listview.setEmptyView(emptyView);
}
}
EDIT: Added code.
This is fastest solution that I got worked out. Still 2-3 seconds and frozen screen in meantime. Tried overriding different methods but still same problem, sometimes slower-sometimes faster.
Related
I've got simple application consisting of 2 screens.
On the first I've got EditText view and button.
When user entry text and press button, main screen changes and user can see typed value together with switch button that's there for returning to previous destination.
The problem's when user haven't typed anything and press button. I've got exception that says, "string is empty".
I've tried using textChangedListener but that isn't working.
First screen consist of ViewModel and MutableLiveData object for storing typed value.
Here's the code:
Main screen:
public class MainFragment extends Fragment {
private MainViewModel mViewModel;
public static MainFragment newInstance() {
return new MainFragment();
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.main_fragment, container, false);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mViewModel = new ViewModelProvider(this).get(MainViewModel.class);
// TODO: Use the ViewModel
EditText editText = getView().findViewById(R.id.valueEntry);
editText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
return;
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
mViewModel.setValue(Float.valueOf(editText.getText().toString()));
}
#Override
public void afterTextChanged(Editable editable) {
return;
}
});
Button button = getView().findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
MainFragmentDirections.MoveToSecond action = MainFragmentDirections.moveToSecond( );
action.setVal(mViewModel.getValue());
Navigation.findNavController(view).navigate(action);
}
});
}
ViewModel instance:
public class MainViewModel extends ViewModel {
private MutableLiveData<Float> value = new MutableLiveData<>();
public void setValue(Float c){value.setValue(c);}
public Float getValue()
{
return value.getValue();
}
use this code when the user pressed the button
if (!entered_sting.equals(""))
{
// show text to other works
}
use this if in first of button press event
A cleaner option would be to check for an empty string and not for equals("")
if (!entered_sting.trim().isEmpty())
{
// show text to other works
}
So, I am working on a mapping application (for a botanical garden) that lets me search data that I have stored in an SQL database to store names and coordinates of various plant life (I have the database set up and working).
The main issue I am running into is getting the search bar functioning properly. I have the material search bar overlaying on my map properly, and I can search for my SQL data, however, I am using a recyclerview to display my SQL data, which overlays over my map, which makes the search functionality completely useless since it is covering the map.
I am really unsure how to either get recyclerview to collapse properly, or implement a different method so that my SQL data populates in the material search bar results, rather than just overlapping my map. Here is my OnCreate method, where I set up the material search bar and the recycler view. Any suggestions/help would be appreciated, since I am struggling to find guides/documentation online.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
//Code used to remove/add droplist to material search bar
recyclerView = (RecyclerView)findViewById(R.id.recycler_search);
layoutManager= new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
materialSearchBar = (MaterialSearchBar)findViewById(R.id.search_bar);
database = new Database(this);
materialSearchBar.setText("Search around The Gardens");
materialSearchBar.setCardViewElevation(10);
// loadSuggestList();
materialSearchBar.addTextChangeListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
List<String> suggest = new ArrayList<>();
for(String search:suggestList)
{
if(search.toLowerCase().contains(materialSearchBar.getText().toLowerCase()))
{
suggest.add(search);
}
}
materialSearchBar.setLastSuggestions(suggest);
}
#Override
public void afterTextChanged(Editable s) {
}
});
materialSearchBar.setOnSearchActionListener(new MaterialSearchBar.OnSearchActionListener() {
#Override
public void onSearchStateChanged(boolean enabled) {
if(!enabled)
{
recyclerView.setAdapter(adapter);
}
}
#Override
public void onSearchConfirmed(CharSequence text) {
startSearch(text.toString());
}
#Override
public void onButtonClicked(int buttonCode) {
}
});
//USED IN DATABASE CLASS
adapter = new SearchAdapter(this,database.getTrees());
recyclerView.setAdapter(adapter);
SQL data with recyclerview overlapping maps
I want to implement a setup assistant for my app which is shown when the user starts the app for the first time. I use a PageViewer for this which seems to work fine.
The first page asks the user for the default language. I want to refresh the page when the user selects its language from the RadioGroup. So I need a way to reload the fragment in the chosen language.
public class SetupAssistantLanguageFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.setup_language_fragment, container, false);
((RadioGroup) view.findViewById(R.id.setup_language_radiogroup)).setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup radioGroup, int i) {
String langcode = "";
if (i == R.id.setup_fragment1_languagechooser_en) {
langcode = "en";
} else {
langcode = "de";
}
((SetupAssistantActivity) getActivity()).changeLanguage(langcode);
SetupAssistantLanguageFragment.this.refreshView();
System.out.println("test1");
}
});
return view;
}
public void refreshView() {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.detach(this).attach(this).commit();
System.out.println("test2");
}
}
Changing the language works but only for the pages that follow the first page. This is because the fragment needs to be reloaded when the language changed. I try to reload in refreshView().
The problem is: As soon as I press one radio button, I get an endless loop printing "test1" and "test2". Why is this method called again and again?
How can I reload the fragment exactly one time?
I got it:
In my fragment I first save the current language.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
currentDisplayLang = getResources().getConfiguration().locale.getLanguage();
}
In onCreateView I only refresh the fragment when the language really changed.
((RadioGroup) view.findViewById(R.id.lecture_translator_setup_language_radiogroup)).setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup radioGroup, int i) {
String chosenLangcode = i == R.id.setup_fragment1_languagechooser_en ? "en" : "de";
if (!chosenLangcode.equals(currentDisplayLang)) {
currentDisplayLang = chosenLangcode.toString();
((SetupAssistantActivity) getActivity()).changeLanguage(chosenLangcode);
SetupAssistantLanguageFragment.this.refreshView();
}
}
});
Is this the recommended way?
I have a ViewPager inside a FragmentActivity. For each page I have a Fragment with an EditText.
I want to prevent the user leaving the screen if the EditText value has changed, showing a warning Dialog asking if he/she really wants to leave the screen.
For that I need to check the EditText value when the back Button is pressed.
I have only found how to do it but using the onBackPressed() method in the container FragmentActivity.
The problem is that I don't know how to access the EditText inside the Fragment from the parent FragmentActivity.
Is it not possible just to do it in the Fragment? I've tried the method onStop and onDetach but they are called after leaving the Fragment, so I cannot stop it.
Any ideas?
Try this in your parent Activity:
#Override
public void onBackPressed() {
super.onBackPressed();
YourFragment fragment = (YourFragment) getSupportFragmentManager().getFragments().get(viewPager.getCurrentItem());
}
Then you have access to your Fragment so you can add a parameter in your fragment textHasChanged (for example) and update it when the text changes.
You may create interface which has method onBackPressed(your fragment should implement this interface), then override method onBackPressed in your activity, then find your fragment by tag or id -> cast to this interface and call this method.
So you need BackPressed() event in fragment for you problem to check if editext is values is changed or not?
So you have create you own OnBackpressed() interface.
Create a interface OnBackPressedListener
public interface OnBackPressedListener {
public void doBack();
}
Create a new class name BaseBackPressedListener
public class BaseBackPressedListener implements OnBackPressedListener {
private final FragmentActivity activity;
public BaseBackPressedListener(FragmentActivity activity) {
this.activity = activity;
}
#Override
public void doBack() {
activity.getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
//activity.getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
Create a instance of your newly created class BaseBackPressedListener in your top base Activity where fragment is added
protected OnBackPressedListener onBackPressedListener;
Create a method in your top base activity to set newly created instance of new class above
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
you will have overide onBackPressed() method in you top base activity modify it like this
#Override
public void onBackPressed() {
if (onBackPressedListener != null)
onBackPressedListener.doBack();
else
super.onBackPressed();
}
And lastly you have add this in you fragment onCreateView()
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Activity activity = getActivity();
((BaseActivity)activity).setOnBackPressedListener(new BaseBackPressedListener(activity));
//your other stuff here
return view;
}
Now you can check on back pressed in your top base activity weather editext value change our not by modifying this methods
#Override
public void doBack() {
if(!IsEditTextChanged)
activity.getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
//activity.getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
IsEditTextChanged is global variable set its values on textchanged
mEditText.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {}
#Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
if(s.length() != 0)
IsEditTextChanged = true;
// your desired logic here?
}
});
Fragment BackPressed thread
You could create a Boolean value in the FragmentActivity and keep it updated with the EditText updated. In this way you can check the String value instead the EditText (In fact the fragment could not be loaded in the Pager).
For example:
1) create an interface in order to declare the input protocol
public interface InputInterface {
void setEditTextNotEmpty(Boolean notEmpty);
}
2) implement this interface in your FragmentActivity
public class MainActivity implements InputInterface {
private Boolean editTextNotEmpty;
...
#Override
void setEditTextNotEmpty(Boolean changed){
editTextNotEmpty=changed;
}
#Override
public void onBackPressed() {
... your custom code....
}
3) You somehow notify the Fragment when it's visualized as for in this post: How to determine when Fragment becomes visible in ViewPager
When the fragment is visualized, you update the activity boolean if necessary.
4) keep your MainActivity updated when you update the edit text:
yourEditText.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
if (getActivity instanceof InputInterface){
Boolean notEmpty = !TextUtils.isEmpty(s.toString);
((InputInterface)getActivity).setEditTextNotEmpty(notEmpty);
}
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
public void onTextChanged(CharSequence s, int start, int before, int count) {}
});
I hope it helped.
Is it possible to initialize all UI elements of certain type (like all TextViews or all LineraLayouts or ...) in a some kind of loop?
I have many layouts with a lot of the elements of the same type and it's really painful to do it all just by typing.
You can use RoboGuice .It doesn't use loops, but helps you to Inject your View, Resource, System Service, or any other object in to your code.
RoboGuice is a framework that brings the simplicity and ease of Dependency Injection to Android, using Google's own Guice library.
To give you an idea, take a look at this simple example of a typical Android activity:
class AndroidWay extends Activity {
TextView name;
ImageView thumbnail;
LocationManager loc;
Drawable icon;
String myName;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
name = (TextView) findViewById(R.id.name);
thumbnail = (ImageView) findViewById(R.id.thumbnail);
loc = (LocationManager) getSystemService(Activity.LOCATION_SERVICE);
icon = getResources().getDrawable(R.drawable.icon);
myName = getString(R.string.app_name);
name.setText( "Hello, " + myName );
}
}
This example is 19 lines of code. If you're trying to read through onCreate(), you have to skip over 5 lines of boilerplate initialization to find the only one that really matters: name.setText(). And complex activities can end up with a lot more of this sort of initialization code.
Compare this to the same app, written using RoboGuice:
class RoboWay extends RoboActivity {
#InjectView(R.id.name) TextView name;
#InjectView(R.id.thumbnail) ImageView thumbnail;
#InjectResource(R.drawable.icon) Drawable icon;
#InjectResource(R.string.app_name) String myName;
#Inject LocationManager loc;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
name.setText( "Hello, " + myName );
}
}
In this example, onCreate() is much easier to take in at a glance. All the platform boilerplate is stripped away and you're left with just your own app's business logic. Do you need a SystemService? Inject one. Do you need a View or Resource? Inject those, too, and RoboGuice will take care of the details.
RoboGuice's goal is to make your code be about your app, rather than be about all the initialization and lifecycle code you typically have to maintain in Android.
This text is from here
I have/had done something similar. Just for your reference, here's the code:
public class AbcActivity extends Activity
{
protected boolean changesPending;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.login_screen);
setViews(); //this method is created and called to take care of the buttons and edittext fields, and can probably hold a number of other fields/widgets as well
}
/** Take care of the Buttons and EditTexts here*/
private void setViews()
{
EditText userEdit = (EditText)findViewById(R.id.editText1);
EditText passwordEdit = (EditText)findViewById(R.id.editText2);
Button loginButton = (Button)findViewById(R.id.login_button);
loginButton.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
login(); // some random method
}
});
Button cancelButton = (Button)findViewById(R.id.cancel_button);
cancelButton.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
cancel(); //another random method
}
});
userEdit.addTextChangedListener(new TextWatcher()
{
public void onTextChanged(CharSequence s, int start, int before, int count)
{
changesPending = true;
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
public void afterTextChanged(Editable s) {}
});
passwordEdit.addTextChangedListener(new TextWatcher()
{
public void onTextChanged(CharSequence s, int start, int before, int count)
{
changesPending = true;
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
public void afterTextChanged(Editable s) {}
});
}
}
Hope this helps.
If you are trying to handle a large number of Views it may be worthwhile handling creation of these Views at runtime, attaching them to the relevant container. For example:
ViewGroup container = (ViewGroup) findViewById(R.id.container);
for(int i = 0; i < NUM_TEXT_VIEWS; i++){
TextView tv = new TextView(this); // where 'this' is your Activity
tv.setText("This is TextView " + i);
container.addView(tv);
}
Properties set in your xml file for a View usually have a corresponding Java method call.