I have a From designed in ViewPager with 5 fragments which consists of all type of inputs(radio group, text, date, drop down) in it. I have to save and submit the form data on submit button click on last fragment.
Now I want to how to keep data saved while traversing between pages of view pager and send a post request at end of view pager? because in view pager i can store state of only 3 pages, while when I traverse to 4th page I will loose data of 1st page. Please let me know how to solve this issue.
I think for your problem the best solution is to create a singleton that contains your object
and at each transition from one fragment to another you update the object in the singleton
Singleton class is the answer for answer. Singleton - Only one instance of the class at a time.
Example :
Your singleton will be like this,
public class AddProductSingleton {
private static AddProductSingleton instance = null;
private String Category;
private String Title;
private String SubTitle;
private String Description;
private AddProductSingleton(){ }
public static AddProductSingleton getInstance(){
if (instance == null)
instance = new AddProductSingleton();
return instance;
}
public String getCategory() {
return Category;
}
public void setCategory(String category) {
Category = category;
}
public String getTitle() {
return Title;
}
public void setTitle(String title) {
Title = title;
}
public String getSubTitle() {
return SubTitle;
}
public void setSubTitle(String subTitle) {
SubTitle = subTitle;
}
public String getDescription() {
return Description;
}
public void setDescription(String description) {
Description = description;
}
And your fragments will be this,
First Fragment
public class Fragment1 extends Fragment {
AddProductSingleton objAddProductDetails = AddProductSingleton.getInstance();
objAddProductDetails.setCategory("Fragment1")
}
Second Fragment,
public class Fragment2 extends Fragment {
ddProductSingleton objAddProductDetails = AddProductSingleton.getInstance();
objAddProductDetails.setTitle("Fragment2")
}
Third Fragment,
public class Fragment3 extends Fragment {
ddProductSingleton objAddProductDetails = AddProductSingleton.getInstance();
objAddProductDetails.setSubTitle("Fragment3")
}
Fourth Fragment,
public class Fragment4 extends Fragment {
ddProductSingleton objAddProductDetails = AddProductSingleton.getInstance();
objAddProductDetails.setDescription("Fragment4")
}
After this your singleton object posses all the values sets in different fragments.
objAddProductDetails.getCategory() // Fragment1
objAddProductDetails.getTitle() // Fragment2
objAddProductDetails.getSubTitle() // Fragment3
objAddProductDetails.getDescription() // Fragment4
I hope this will be best proper solution to your query, Happy coding.
Related
I have an app on production, so changes has to be applied with a RealmMigration
I've looked the documentation and this example but I didn't find how to do the following.
In current version I have items of type Foo that has a boolean property called favorite.
Now I want to generalize that and create user custom Foo lists, so the users will be able to create their custom lists and add as many objects as they want.
I want to implement this with a new class called UserFooList with basically name and a RealmList<Foo>of elements.
In migration process I'm creating this new class with its fields.
That's easy, but here comes the difficult part:
I want to add all previous Foo items flagged with favorite to a new UserFooList and then remove the now unused Foo's field favorite
Some code to help to clarify:
Current class
public class Foo extends RealmObject{
private String title;
private boolean favorite;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public boolean isFavorite() {
return favorite;
}
public void setFavorite(boolean favorite) {
this.favorite = favorite;
}
}
Changed class
public class Foo extends RealmObject{
//favorite field will be removed
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
New class
public class UserFooList extends RealmObject{
private String name;
private RealmList<Foo> items;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public RealmList<Foo> getItems() {
return items;
}
public void setItems(RealmList<Foo> items) {
this.items = items;
}
}
I want to insert a UserFooList instance and populate it with:
name: "favorites"
items: all existing Foo instances with favorite == true
And I want to do it during Migration because in that way I will be able to remove favorite field after inserting all elements in the new created list.
Rely on the power of the DynamicRealm API.
public class MyMigration implements Realm.Migration {
#Override
public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
RealmSchema schema = realm.getSchema();
if(oldVersion == 0) {
RealmObjectSchema foo = schema.get("Foo");
RealmObjectSchema userFooList = schema.create("UserFooList");
userFooList.addField("name", String.class);
userFooList.addRealmListField("items", foo);
DynamicRealmObject userList = realm.createObject("UserFooList");
userList.setString("name", "favorites");
RealmList<DynamicRealmObject> listItems = userList.getList("items");
RealmResults<DynamicRealmObject> favoriteFoos = realm.where("Foo").equalTo("favorite", true).findAll();
for(DynamicRealmObject fooObj: favoriteFoos) {
listItems.add(fooObj);
}
foo.removeField("favorite");
oldVersion++;
}
}
#Override public boolean equals(Object object) {
return object != null && object instanceof MyMigration;
}
#Override public int hashCode() {
return MyMigration.class.hashCode();
}
}
I am currently building an app to retrieve information for a remote server. the data received are JSON and I am build a list of Data using the class below :
public class RedditData {
private RedditTopic data;
public RedditTopic getData() {
return data;
}
}
and RedditTopic class is defined as below:
public final class RedditTopic {
private static final String TAG = RedditTopic.class.getSimpleName();
private String author;
private String thumbnail;
private String title;
private String num_comments;
private long created_utc;
private String data;
private String name;
public RedditTopic(){};
public String getData() {
return data;
}
public String getAuthor() {
return author;
}
public String getThumbnail(){
return thumbnail;
}
public String getTitle(){
return title;
}
public String getComments(){
return num_comments + " comments";
}
public long getCreated_utc(){
return created_utc;
}
public String getRedditName(){
return name;
}
}
both of these classes are used to translate a JSON into an Object formatted data.
I do not want to really change them to make them Parceable to avoid impacting the extraction of JSON.
I have added :
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
Log.d(TAG, ">>>>>>>>>>>>>>>>>>>>>>>> SAVE");
savedInstanceState.putParcelableArrayList("RedditList", myListOfData );
super.onSaveInstanceState(savedInstanceState);
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.d(TAG, ">>>>>>>>>>>>>>>>>>>>>>>> RESTORE");
List<RedditData> myListOfData = savedInstanceState.getParcelableArrayList("RedditList");
}
Android complain because I need to implement Parceable in my class RedditData and I assume probably in the RedditTopic Class as well because RedditData returned a List of RedditTopic.
Is there a better way to do it? keep the List as I have it without requiring the Parceable option.
I do not have a List of String, it's a list of object.
Any idea?
Regards
Make your model objects parcleable.
There is a great extension, https://plugins.jetbrains.com/plugin/7332-android-parcelable-code-generator that will generate the neccesary parcelable methods for your class.
I highly recommend it.
I have a POJO class. It holds some Strings and I want to pass values from RecyclerView to an Activity. I tried something and failed. How do I do that?
Model
public class DetailModel {
String title;
public DetailModel() {
}
public DetailModel(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
Adapter, onClick
holder.cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
detailModel=new DetailModel();
detailModels= new ArrayList<>();
detailModel.setTitle(holder.headerText.getText().toString());
Intent detailIntent = new Intent(context.getApplicationContext(), DetailActivity.class);
context.startActivity(detailIntent);
}
});
Another Activity
DetailModel detailModel=new DetailModel();
detailBody.setText(detailModel.getTitle());
There is several ways to do that, but I will show you simplest one :
In your onBindViewHolder :
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder,final int position) {
final MyView myHolder = (MyView) holder;
myHolder.cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
detailModel.setTitle(holder.headerText.getText().toString());
Intent detailIntent = new Intent(context, DetailActivity.class);
//To pass your class:
intent.putExtra("mypojo", details.get(position));
context.startActivity(detailIntent);
}
});
}
In this way you must implement Serializable in your POJO class :
public class DetailModel implements Serializable{
String title;
public DetailModel() {
}
public DetailModel(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
And in second Activity use this code to get class :
getIntent().getExtras().getSerializable("mypojo");
//also you can cast extra
DetailModel detailmodel=(Detailmodel) getIntent().getExtras().getSerializable("mypojo");
//if you implemented Parcelable
DetailModel detailmodel=(Detailmodel) getIntent().getExtras().getParcelable("mypojo");
This is the first way, in another and faster way is using Parcelable , checkout this answer but you must make some effort in Parcelable : how-to-send-an-object-from-one-android-activity-to-another-using-intent
I suggest you to use Parcelable maybe you need some time to learn it but you can feel speed difference in bigger classes.
Also if you have small amounts of Strings in your POJO, try to use intent extras instead of sending class like that :
intent.putExtra("model_name",pojo.getName());
//then get
getIntent().getExtras().getString("model_name");
A recycler view by itself doesn't hold any data. That is the job of your adapter. The recyclerview' a job is to display that data and intercept touch events. So on your click listener get a hold of the data(POJO object) and pass that to your activity.
I have a list with articles taken from an List and want to show the selected article in a PagerActivity so the user can easily flip to the article before and after when finished reading.
In iOS I can just pass the List (or a reference) with article objects to the PagerActivity. In Android however, calling on an Intent does not allow Lists to be passed on. So what would be the best way of doing it? Do I need to reload the array in the next Activity and then pass the position as an argument to the Intent?
(Reloading the List would be expensive, but should work if the DB hasn't changed since loading, otherwise the order might be different and the wrong item might be shown).
In Android
Used ParecleObjectif you have Custom Object ArrayList and if your have simple String ArrayList then pass directly in Intent
If you have Simple String ArrayList then refer below
Passing ArrayList of string arrays from one activity to another in android
and If you have Custom Object ArrayList then refer below
How to pass ArrayList<CustomeObject> from one activity to another?
Passing arraylist of objects between activities
Considering your list of type Department here:
public class Department implements Parcelable {
int department_id;
String title;
public Department() {
this.department_id = 0;
this.title = null;
}
public Department(int department_id, String title) {
this.department_id = department_id;
this.title = title;
}
public int getDepartmentId() {
return department_id;
}
public void setDepartmentId(int department_id) {
this.department_id = department_id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int flag) {
parcel.writeInt(department_id);
parcel.writeString(title);
}
public static final Creator<Department> CREATOR = new Creator<Department>(){
#Override
public Department createFromParcel(Parcel parcel) {
Department department = new Department();
department.setDepartmentId(parcel.readInt());
department.setTitle(parcel.readString());
return department;
}
#Override
public Department[] newArray(int size) {
return new Department[size];
}
};
}
List<Department> departments = new ArrayList<>();
Now you simply have to put this list in Intent Bundle like this
bundle.putParcelableArrayList("Departments_KEY", departments);
and receive the list in your child activity like this
List<Department> departments = getIntent() or getArguments().getParcelable("Departments_KEY");
I'm working on an application for Android that downloads RSS data from given URLs to a ListView where I can sort items in a number of ways (alphabetically, by date, by title etc.).
I'd like to be able to remove all items that were downloaded from a given URL.
Sorting changes original item positions, so I can't simply remove items by position.
Here I explain in detail how it's working:
In fragment A I have an EditText in which you type URLs.
Once you press ENTER:
the URL is passed on through an interface to fragment B where it uses the URL to download XML data and loads "item"s into it's ListView through an ArrayAdapter of 'item' class type.
fragment A has it's own ListView where it stores accepted URLs along with >delete< buttons next to them.
Each RSS item that's loaded into fragment's B ListView has unique title, link, and description, and publish date.
That means there are no common values in the loaded items.
I do download the "channel" part, which is the parent of all "item"s which were downloaded from the given URL, but I am not using it in the fragment's B adapter.
Here is the code for the POJO:
#Root(name = "rss", strict = false)
public class RSS {
#Element
private Channel channel;
#Attribute
private String version;
public Channel getChannel() {
return channel;
}
}
#Root(name = "channel", strict = false)
public class Channel {
#ElementList(name = "item", inline = true)
List<Article> articleList;
#Element
private String title;
#Element
private String link;
#Element
private String description;
// setters and getters
}
#Root(name = "item", strict = false)
public class Article {
#Element
private String title;
#Element
private String description;
#Element
private String link;
#Element(required = false)
private String author;
#Element(required = false)
private String pubDate;
// setters and getters
}
This is the URL class used for storing URLs in fragment A's ListView adapter.
public class URL {
private String url;
URL(String url) {
this.url = url;
}
public String getUrl() {
return url;
}
public void setUrl(String title) {
this.url = title;
}
}
Now, fragment B downloads the RSS object (called 'articles' here) and this is how I load the items to the other ListView adapter:
previewList = articles.getChannel().articleList;
adapter.addTop(previewList);
adapter.notifyDataSetChanged();
And finally, the Fragment B's ListView adapter:
public class ArticlePreviewAdapter extends ArrayAdapter<Article> {
List<Article> articlePreviewItems;
public ArticlePreviewAdapter(Activity activity, List<Article> articlePreviewItems) {
super(activity, R.layout.item_article_preview, articlePreviewItems);
this.articlePreviewItems = articlePreviewItems;
}
private static class ViewHolder {
TextView articlePreviewTitle;
TextView articlePreviewLink;
TextView articlePreviewDescription;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
Article articlePreviewItem = getItem(position);
if (convertView == null) {
viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.item_article_preview, parent, false);
viewHolder.articlePreviewTitle = (TextView) convertView.findViewById(R.id.articleTitle);
viewHolder.articlePreviewLink = (TextView) convertView.findViewById(R.id.articleLink);
viewHolder.articlePreviewDescription = (TextView) convertView.findViewById(R.id.articleDescription);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.articlePreviewTitle.setText(articlePreviewItem.getTitle());
viewHolder.articlePreviewLink.setText(articlePreviewItem.getLink());
viewHolder.articlePreviewDescription.setText(articlePreviewItem.getDescription());
return convertView;
}
public void removeChannelItems(what do) {
what do?
}
public void addTop(List<Article> articles) {
articlePreviewItems.addAll(0, articles);
}
}
Thanks for help in advance.
If your Article object (or RSS, or Channel) can hold references to many URLs, you can implement the association like below (Article taken as example)
public class URL {
private String url;
private ArrayList<String> articleTitles;
public class URL(){
this.articleTitles = new ArrayList<String>();
}
public void setArticleTitles(String articleTitle){
this.articleTitle.add(articleTitle);
}
public ArrayList<String> getAarticleTitles(){
return this.articleTitles;
}
URL(String url) {
this.url = url;
}
public String getUrl() {
return url;
}
public void setUrl(String title) {
this.url = title;
}
}
Then you would have your URL reference your object. When you delete the URL, you remove all Articles from the respective adapter, finally calling notifyDataSetChanged(); on the adapter.