I've made a list made of TextViews and Buttons, made that when a person clicks on a button, a fragment opens and there is a list of values he can select. The problem is when i press on another button to select a value again for a different field, the previous value disappears. So the question would be how to save the fragments values, and keep it saved until the app is closed ?
priceButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
PriceFragment priceFragment = new PriceFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.fragmentContainer, priceFragment).commit();
setToHideElements();
}
});
yearButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
YearFragment yearFragment = new YearFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.fragmentContainer, yearFragment).commit();
setToHideElements();
}
});
this is the year fragment
yearEndListView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Intent intent = new Intent(getActivity().getBaseContext(), MainMenuActivity.class);
String yearTo = yearList[i].toString();
int yearTint = Integer.valueOf(yearTo);
if (combinedYear != null) {
combinedYear = combinedYear + " " + yearTo;
intent.putExtra("Years", combinedYear);
getActivity().startActivity(intent);
} else {
combinedYear = null;
combinedYear = yearTo;
}
}
});
this is the method to retrive data
private void retriveDataFromFragment(){
Intent intent = getIntent();
String fragmentDataPrice = intent.getStringExtra("PriceData");
String fragmentDataYear = intent.getStringExtra("Years");
if(fragmentDataPrice != null){
priceButton.setText(fragmentDataPrice);
} else {}
if (fragmentDataYear != null){
yearButton.setText(fragmentDataYear);
} else {}
}
I use RetriveDataFromFragment method in OnResume method.
Thank you, for your time.
you are initiating every time a new fragment so it will never retain its state. you have to use listener while closing the fragment so you can get back your data.
I got the anwser if someone else needs a similar menu, all you have to do is create a class that extends Application, and include into your manifest (the part with application tags). From there you just use getters and setters and all is well.
Related
Hello (First of all excuse my English if something is wrong, it's not my first language), I'm developing an app with the IMDB API to keep up to date with your favorite series (no links or anything illegal).
I'm gonna focus on the two activities in which the problem is: The first Activity, ActivitySerieJson contains a recycled view filled with all the seasons in card view. Each card view contains season thumbnail, season number and the users completed view percentage:
ActivitySerieJson.
The second activity, ActivityTemporadaJSON contains another recyclerview, this one is filled with chapters name, thumbnail and an eye-shaped button that, when pressed, marks the chapter as seen on DB. The problem is that when I go back to previous activity the completed view percentage TextView is not being refreshed.
ActivityTemporadaJSon
This is my code:
RecyclerAdapterTemporada
public void bindPhoto(Temporada mtemporada, String idSerie, String tipo) {
temporada = mtemporada;
String Nombre = temporada.getNombreTemporada();
if(Nombre.length() >= 25)
{
Nombre = Nombre.substring(0,22);
Nombre = Nombre + "...";
}
AQuery androidAQuery=new AQuery(mItemImage.getContext());
androidAQuery.id(mItemImage).image(temporada.getPoster(), true, true, 150,0);
//Picasso.with(mItemImage.getContext()).load(mserie.getPoster()).into(mItemImage);
mItemDate.setText(Nombre);
mItemidTMDB.setText(idSerie);
mItemNumTemp.setText(Integer.toString(temporada.getNumeroTemporada()));
mItemNumEps.setText(Integer.toString(temporada.getNumeroEpisodios()));
//THIS CODE SECTION CALCULATES PERCENTAGE
if(tipo.equalsIgnoreCase("SQL"))
{
int porcen=1;
int numEps = temporada.getNumeroEpisodios();
if(numEps == 0){
numEps = 1;
}
porcen = (temporada.getEpisodiosVsitos() * 100) / numEps;
mNumEpsVistoVal.setText(Integer.toString(porcen) + "%");
}
else
{
mNumEpsVisto.setVisibility(View.INVISIBLE);
mNumEpsVistoVal.setVisibility(View.INVISIBLE);
}
}
}
}
RecyclerAdapterEpisodio
public class RecyclerAdapterEpisodio extends
RecyclerView.Adapter<RecyclerAdapterEpisodio.EpisodioHolder> {
private ArrayList<Episodio> mEpisodio;
private int IdSerie;
private RecyclerAdapterEpisodio miAdaptador;
private String Tipo;
private View v;
//5
#Override
public void onClick(View v) {
/*Context context = itemView.getContext();
Intent showPhotoIntent = new Intent(context, Pelicula.class);
showPhotoIntent.putExtra(PHOTO_KEY, peli);
context.startActivity(showPhotoIntent);*/
}
public void bindPhoto(final Episodio mEpisodio, final int mIdSerie, String tipo) {
episodio = mEpisodio;
if (tipo.equalsIgnoreCase("SQL")) {
if(episodio.isVisto()){
mBoton.setBackgroundResource(R.drawable.ojoabierto);
}else{
mBoton.setBackgroundResource(R.drawable.ojocerrado);
}
mBoton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (episodio.isVisto()) {
//mBoton.setBackgroundResource(R.drawable.ojoabierto);
DBHelper mydb = new DBHelper(v.getContext());
mydb.CancelVerEpisodio(episodio.getIdEpisodio());
v.setBackgroundResource(R.drawable.ojocerrado);
episodio.setVisto(false);
} else//else
{
//mBoton.setBackgroundResource(R.drawable.ojocerrado);
DBHelper mydb = new DBHelper(v.getContext());
mydb.VerEpisodio(episodio.getIdEpisodio());
mBoton.setBackgroundResource(R.drawable.ojoabierto);
episodio.setVisto(true);
}
}
});
}
else
{
mBoton.setVisibility(View.INVISIBLE);
}
in your fist activity do the loading inside OnResume(). so that when you comeback to the activity . onResume() method will be first called and you will get the updated data. This is when you have all your other block codes functioning well but you have problem with refreshing your page.
move your loading method from onCreate() to onResume() in the first activity
I have listview with setOnItemClickListener() method, when clicked I want it to open new activity and give it 2 extras, the number of the item and the user that logged in (back in home screen), the problem is that the activity starts twice, one with good extras and one with "0" in the position extra...
this code is supposed to check if Firebase server has place in it (no more than 5 players) and if so add the user to the server and join the room (launch ServerActivity).
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
myRef = database.getReference("Servers/S"+position);
myRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int i = 0;
while (dataSnapshot.child("player"+i).child("username").getValue() != null)
i++;
if (i < 5) {
Log.d("Implementing Child","player"+i);
CustomUser customUser = new CustomUser(false,currentUser.getUsername(),"",0,currentUser.getWins());
myRef.child("player" + i).setValue(customUser);
Intent intent = new Intent(GameActivity.this,ServerActivity.class);
intent.putExtra("serverNum",position);
intent.putExtra("currentUser",currentUser);
Log.d("position", position + "");
startActivity(intent);
finish();
}
else{
Toast.makeText(getApplicationContext(), "Server Full", Toast.LENGTH_SHORT).show();
myRef.child("isJoinable").setValue(false);
}
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Toast.makeText(getApplicationContext(), "" +
"Internet Error", Toast.LENGTH_SHORT).show();
}
});
Intent intent = new Intent(GameActivity.this,ServerActivity.class);
intent.putExtra("currentUser",currentUser);
startActivity(intent);
finish();
//TODO FIX: activity probebly launches twice
}
});
I tried modifing LaunchMode in the manifest but it resulted with fail causing the "serverNum" extra to be 0 instead of the position.
Why have you added this code :
Intent intent = new Intent(GameActivity.this,ServerActivity.class);
intent.putExtra("currentUser",currentUser);
startActivity(intent);
finish();
This would cause your ServerActivity to launch as soon as the listener is added. Have you tried commenting this code and use only the code in onDataChange?
In my projects I kept different images for categories. When I click on each category image I am passing its category id to other page statically and setting the drawable image of that category in the new page.
My Code:
Firstpage.java
public static String categoryid;
category1.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
categoryid="0";
Intent myIntent = new Intent(view.getContext(),Nextpage.class);
startActivityForResult(myIntent, 0);
}
});
category2.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
categoryid="1";
Intent myIntent = new Intent(view.getContext(),Nextpage.class);
startActivityForResult(myIntent, 0);
}
});
category3.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
categoryid="2";
Intent myIntent = new Intent(view.getContext(),Nextpage.class);
startActivityForResult(myIntent, 0);
}
});
Nextpage.java
public static String catid = Firstpage.categoryid;
ImageView categorytype=(ImageView)findViewById(R.id.imageView1);
if(catid=="0")
{
categorytype.setBackgroundResource(R.drawable.image1);
}
else if(catid=="1")
{
categorytype.setBackgroundResource(R.drawable.image2);
}
else if(catid=="2")
{
categorytype.setBackgroundResource(R.drawable.image3);
}
First time when I am clicking on the category image it is passing the category id to the next page and that particular image is setting in the nextpage. After that I clicked the back button(android back button) and went to Firstpage.java and again clicked on other image. But this time also the same image stored. The category id didnt changed. The category id is not refreshing...How to refresh the category id? Any suggestion will be thankful.....
You are comparing two strings by == operator, instead you should compare by equals method, try following:
if(catid.equals("0"))
{
categorytype.setBackgroundResource(R.drawable.image1);
}
else if(catid.equals("1"))
{
categorytype.setBackgroundResource(R.drawable.image2);
}
else if(catid.equals(2"))
{
categorytype.setBackgroundResource(R.drawable.image3);
}
Don't use static variables for this. Pass the category ID to your Nextpage activity through the intent. In Firstpage.java:
public static final String CATEGORY_KEY = "category";
category1.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
Intent myIntent = new Intent(this,Nextpage.class);
myIntent.putExtra(CATEGORY_KEY, "0");
startActivityForResult(myIntent, 0);
}
});
Then retrieve it in the onCreate(Bundle) method of Nextpage.java:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
String categoryid = intent.getStringExtra(Firstpage.CATEGORY_KEY);
. . .
}
The reason your method doesn't work is that Nextpage.catid is initialized when the class is loaded, but the assignment statement is not executed again unless the class is unloaded and needs to be reloaded.
I think problem is here you are comparing String values using this if(catid=="0") Which you should be compare it using if(catid.trim().equals("0"))
Update this change in your code and check it.
I'm trying to put the contents of List mCartList; into a the sms_body below, eg: Cheeseburger, Hamburger, Fries (so it can be sent through sms). I can pass a string so I know it works. I'm not a programmer at all and it's been a month of me doing trial & error.
Below the activity calls the contents of mCartList into a List so they can be removed. Tell me whatever else you need to help me solve this. Thank you in advance.
private ProductAdapter mProductAdapter;
// This List into the order button below
private List<Product> mCartList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.shoppingcart);
mCartList = ShoppingCartHelper.getCart();
// Make sure to clear the selections
for(int i=0; i<mCartList.size(); i++) {
mCartList.get(i).selected = false;
}
// Create the list
final ListView listViewCatalog = (ListView) findViewById(R.id.ListViewCatalog);
mProductAdapter = new ProductAdapter(mCartList, getLayoutInflater(), true);
listViewCatalog.setAdapter(mProductAdapter);
listViewCatalog.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Product selectedProduct = mCartList.get(position);
if(selectedProduct.selected == true)
selectedProduct.selected = false;
else
selectedProduct.selected = true;
mProductAdapter.notifyDataSetInvalidated();
}
});
Button orderButton = (Button) findViewById(R.id.orderButton);
orderButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Uri uri = Uri.parse("smsto:1234567890");
Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
// The above List<Product> mCartList ia displayed in the window of the app
intent.putExtra("sms_body", "mCartList"); // I want the results of List<Product> mCartList to go here - I can not just insert the variable I just get errors and can't compile
startActivity(intent);
}
});
Button removeButton = (Button) findViewById(R.id.ButtonRemoveFromCart);
removeButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// Loop through and remove all the products that are selected
// Loop backwards so that the remove works correctly
for(int i=mCartList.size()-1; i>=0; i--) {
if(mCartList.get(i).selected) {
mCartList.remove(i);
}
}
mProductAdapter.notifyDataSetChanged();
}
});
}
Here is how this works. It's a 4 tab list with different items in each tab, 3 of which or products. Customer clicks on the item and they see a description, click add to cart, then your back at the menu. The 4th tab is a the order of what was just selected that is to populate the sms body. I have been able to pass a variable with the text "Hello World". I'm figuring the result of List mCartList can populate the sms body. I'm assuming the List can not just be inserted into the body of a forn without being converter. Let me know if you need anymore info. I'm not a programmer, I have seen similar but nothing that doesn't work without writing other files I got from a tutorial. Thank you in advance.
If all the products are added to your mCartList, it's just a matter of concatenating the String output of the Products together as follows:
orderButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Uri uri = Uri.parse("smsto:1234567890");
Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
StringBuilder builder = new StringBuilder();
for(Product p : mCartList){
builder.append(p.toString());
builder.append('\n');
}
intent.putExtra("sms_body", builder.toString());
startActivity(intent);
}
});
make sure your Product has a toString() method defined as follows (example Product guess):
public class Product{
String productName;
public String toString(){
return productName;
}
}
I am making a date picker activity that looks like a scrolling 30 day month/calendar (think Outlook calendar). The date picker contains a ListView (for scrolling) of MonthView views each of which is a TableView of the individual days. Each individual day in the MonthView is a button. When the MonthView is instantiated I walk each of the days (buttons) and attach a click listener:
final Button b = getButtonAt(i);
b.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v) {
setSelectedDate(buttonDayClosure, b);
}
});
setSelectedDate does a variety of things, but it also turns the button's background to yellow to signify the date is selected.
On my emulator, everything works as you would expect. Activity comes up, you press a day, the day turns yellow. No problems.
However, on some of my peer's emulators and on physical devices when you touch a day nothing happens... until you scroll the ListView... and then all of a sudden the selected day turns yellow. So, for example, you touch "the 3rd" and then nothing happens. Wait a few seconds and then scroll the ListView (touching an area of the calendar that is NOT the 3rd) and as soon as ListView scrolls the 3rd magically turns yellow.
On my peer emulators that show this behavior, I can set a breakpoint on the fist line of onClick and I see that the BP is in fact not hit until the ListView is scrolled.
This behavior doesn't make any sense to me. I would expect the onClick behavior to be unrelated to the encapsulating View's scrolling efforts.
Any thoughts on why this might be the case and how I can rectify the situation so that onClicks always happen immediately when the button is touched?
Thanks.
Post Scriptus: ArrayAdapter and ListView code requested:
public class MonthArrayAdapter extends ArrayAdapter<Date> {
private MonthView[] _views;
private Vector<Procedure<Date>> _dateSelectionChangedListeners = new Vector<Procedure<Date>>();
public MonthArrayAdapter(Context context, int textViewResourceId, Date minSelectableDay, Date maxSelectableDay) {
super(context, textViewResourceId);
int zeroBasedMonth = minSelectableDay.getMonth();
int year = 1900 + minSelectableDay.getYear();
if(minSelectableDay.after(maxSelectableDay))
{
throw new IllegalArgumentException("Min day cannot be after max day.");
}
Date prevDay = minSelectableDay;
int numMonths = 1;
for(Date i = minSelectableDay; !sameDay(i, maxSelectableDay); i = i.addDays(1) )
{
if(i.getMonth() != prevDay.getMonth())
{
numMonths++;
}
prevDay = i;
}
_views = new MonthView[numMonths];
for(int i = 0; i<numMonths; i++)
{
Date monthDate = new Date(new GregorianCalendar(year, zeroBasedMonth, 1, 0, 0).getTimeInMillis());
Date startSunday = findStartSunday(monthDate);
this.add(monthDate);
_views[i] = new MonthView(this.getContext(), startSunday, minSelectableDay, maxSelectableDay);
zeroBasedMonth++;
if(zeroBasedMonth == 12)
{
year++;
zeroBasedMonth = 0;
}
}
for(final MonthView a : _views)
{
a.addSelectedDateChangedListener(new Procedure<MonthView>()
{
#Override
public void execute(MonthView input) {
for(final MonthView b: _views)
{
if(a != b)
{
b.clearCurrentSelection();
}
}
for(Procedure<Date> listener : _dateSelectionChangedListeners)
{
listener.execute(a.getSelectedDate());
}
}
});
}
}
void addSelectedDateChangedListener(Procedure<Date> listener)
{
_dateSelectionChangedListeners.add(listener);
}
private boolean sameDay(Date a, Date b)
{
return a.getYear() == b.getYear() && a.getMonth() == b.getMonth() &&
a.getDate() == b.getDate();
}
#Override
public View getView (int position, View convertView, ViewGroup parent)
{
return _views[position];
}
private Date findStartSunday(Date d)
{
return d.subtractDays(d.getDay());
}
public void setSelectedDate(Date date)
{
for(MonthView mv : _views)
{
mv.setSelectedDate(date);
}
}
}
and
public class DatePicker extends ActivityBase {
public static final String CHOSEN_DATE_RESULT_KEY = "resultKey";
public static final String MIN_SELECTABLE_DAY = DatePicker.class.getName() + "MIN";
public static final String MAX_SELECTABLE_DAY = DatePicker.class.getName() + "MAX";
private static final String SELECTED_DATE = UUID.randomUUID().toString();
private long _selectedDate = -1;
private MonthArrayAdapter _monthArrayAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Date now = new Date();
Bundle inputs = this.getIntent().getExtras();
long min = inputs.getLong(MIN_SELECTABLE_DAY, 0);
Date minSelectableDate;
if(min == 0)
{
minSelectableDate = new Date(now);
}
else
{
minSelectableDate = new Date(min);
}
Log.i(DatePicker.class.getName(), "min date = " + minSelectableDate.toString());
long max = inputs.getLong(MAX_SELECTABLE_DAY, 0);
Date maxSelectableDate;
if(max == 0)
{
maxSelectableDate = new Date(now.addDays(35).getTime());
}
else
{
maxSelectableDate = new Date(max);
}
setContentView(R.layout.date_picker);
Button doneButton = (Button) findViewById(R.id.DatePickerDoneButton);
if(doneButton == null)
{
Log.e(this.getClass().getName(), "Could not find doneButton from view id.");
finish();
return;
}
doneButton.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v) {
Intent result = new Intent();
result.putExtra(CHOSEN_DATE_RESULT_KEY, _selectedDate);
setResult(RESULT_OK, result);
finish();
}
});
Button cancelButton = (Button) findViewById(R.id.DatePickerCancelButton);
if(cancelButton == null)
{
Log.e(this.getClass().getName(), "Could not find cancelButton from view id.");
finish();
return;
}
cancelButton.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v) {
setResult(RESULT_CANCELED, null);
finish();
}
});
ListView lv = (ListView)findViewById(R.id.DatePickerMonthListView);
lv.setDividerHeight(0);
_monthArrayAdapter =
new MonthArrayAdapter(this, android.R.layout.simple_list_item_1, minSelectableDate, maxSelectableDate);
_monthArrayAdapter.addSelectedDateChangedListener(new Procedure<Date>()
{
#Override
public void execute(Date input) {
_selectedDate = input.getTime();
}
});
lv.setAdapter(_monthArrayAdapter);
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState)
{
if(savedInstanceState.containsKey(SELECTED_DATE))
{
_selectedDate = savedInstanceState.getLong(SELECTED_DATE);
_monthArrayAdapter.setSelectedDate(new Date(_selectedDate));
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
savedInstanceState.putLong(SELECTED_DATE, _selectedDate);
}
}
Having the same problem, looking for an answer. I totally didn't believe it when I didn't get my onClick method until I scrolled my list. I'll post the answer here if I find it.
Right now, my best guess is to try different events besides click (because the scroll space is eating the complex touch events that turn into a click event):
"downView" is a static variable to track the element being clicked.
view.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
downView = v;
return true;
} else if (event.getAction() == MotionEvent.ACTION_UP) {
if (downView == v) {
handleClick(v);
return true;
}
downView = null;
}
return false;
}
});
The main reason is that ListView doesn't like an adapter having an array of views.
So the problem is triggered by
public View getView (int position, View convertView, ViewGroup parent)
{
return _views[position];
}
When looking at the ListView code (or rather it's parents AbsListView.obtainView method) you'll see code like
if (scrapView != null) {
...
child = mAdapter.getView(position, scrapView, this);
...
if (child != scrapView) {
mRecycler.addScrapView(scrapView);
It can happen that getView(position,...) is called with scrapView != _views[position] and hence scrapView will be recycled. On the other hand, it is quite likely that the same view is also added again to ListView, resulting in views having a weird state (see this issue)
Ultimately, this should be fixed in ListView IMO, but temporarily, I advise against using an adapter containing an array of views.
So I'll add a completely separate answer to this outside of manually composing your own click events from touch events.
I traded some emails with the Android Team (there's a few perks from being consumed by the googly) and they suggested that my attempt to implement ListAdapter by hand was inefficient and that if I don't correctly hook up the data observer methods of the adapter it can cause "funny problems with event handling."
So I did the following:
1) Replaced my implementation of ListAdapter with a subclass of BaseAdapter that overrode the necessary functions.
2) Stopped using list.invalidateViews() and started using adapter.notifyDataChanged()
and the bug seems to have gone away.
That's more work than manually composing a click event, but it's also more correct code in the long run.
Aswer is:
public View getView(int position, View convertView, ViewGroup parent) {
View v=makeMyView(position);
v.setFocusableInTouchMode(false);
return v;
}