I use Sugar ORM for Android Development via Android Studio.
But I think I have a quite similar question.
How can I display one/multiple result queries as String or int?
My entity looks like this:
public class PersonsDatabase extends SugarRecord<PersonsSelection>{
String adultText, childText;
int adultCount, childCount;
public PersonsDatabase()
{
}
public PersonsDatabase(String adultText, String childText, int adultCount, int childCount)
{
this.adultText = adultText;
this.childText = childText;
this.adultCount = adultCount;
this.childCount = childCount;
this.save();
}
}
It saves correctly. But when I want to display like this:
public class PersonsSelection extends Activity {
ListView list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_persons_selection);
PersonsDatabase personsDatabase = new PersonsDatabase("1 Adult","No Childs",1,0);
List<PersonsDatabase> personsList = PersonsDatabase.findWithQuery(PersonsDatabase.class,"Select adult_Text from PERSONS_DATABASE");
list = (ListView)findViewById(R.id.listView);
list.setAdapter(new ArrayAdapter<PersonsDatabase>(this, android.R.layout.simple_list_item_1, personsList));
}
}
I get something like: PACKAGENAME.PersonsDatabase#4264c038
But I want the values that I wrote in the constructor.
Thanks for help.
From the docs on ArrayAdapter:
However the TextView is referenced, it will be filled with the toString() of each object in the array. You can add lists or arrays of custom objects. Override the toString() method of your objects to determine what text will be displayed for the item in the list.
In short: just override the toString() method in your PersonsDatabase class to return the desired textual respresentation.
Alternatively:
To use something other than TextViews for the array display, for instance, ImageViews, or to have some of data besides toString() results fill the views, override getView(int, View, ViewGroup) to return the type of view you want.
(again from the docs). Plenty of examples out there on how to go about doing that.
Simply override the toString() method.
In that method, return whichever database value you want to retrieve.
In my case, I returned a variable name that I needed (i.e. message) :
#Override
public String toString() {
return message;
}
Related
What is the best practice to set text for a textview with a given string and some value from my database?
My MainActivity:
MyModel model;
TextView title = (TextView) findViewById(R.id.tvTitle);
title.setText("Username: ", model.getName());
My Model
private String name;
public String getName() {
return name;
}
I couldn't find a solution so far.
The method setText() has several signatures, but the one you need is:
public final void setText (CharSequence text)
So you could do:
title.setText("Username: " + model.getName());
but AS usually complains in these cases that you should avoid concatenating strings inside setText(),
so what you can do is:
String str = "Username: " + model.getName();
title.setText(str);
Also you should consider to store literal values like "Username: " in resources like:
<string name="username">Username:</string>
and use it like this:
String str = getResources().getString(R.string.username) + model.getName();
title.setText(str);
Creating getters and setters are a good practice, which you can automatically generate in Android Studio after defining the variables for the model. Other than that I dont know why in your getName() your method wants to return a long and you are actually returning a string. Change long to String
like this :
public String getName() {
return mName;
}
public void setName(String name) {
mName = name;
}
Everything others have said about concatenating strings outside of the setText method is valid. As far as placement in the Activity or Fragment (I'm using a Fragment in this example), I use the follow conventions:
Declare my class fields in the class body outside of my methods (for class-wide access)
public class MyFragment extends Fragment {
private TextView titleView;
public MyFragment() {
//Constructor
}
// and so on ...
}
Then, find my TextView reference once the Fragment is inflated, and if needed immediately, set its value
// ...
#override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
View view = inflater.inflate(R.layout.fragment_container, container, false);
titleView = view.findViewById(R.id.title);
String titleStr = "Username: " + model.getName();
titleView.setText(titleStr);
return view;
}
// ...
If I'm expecting the database value in question to change (for example the user updating their username in settings) then I may also wish to make use of certain lifecycle methods that trigger when a Fragment (or Activity) resumes after being suspended, but is not completely rebuilt.
// ...
#override
public void onResume() {
titleStr = "Username: " + model.getName();
titleView.setText(titleStr);
}
// ...
Here's a link regarding the Android Activity Lifecycle if you're not familiar with it, and here's a good rundown on Fragments. Hope this helps.
I have an arraylist of "Swimmer" objects and I don't want it to delete every time the app closes. I have read about serialization and using shared preferences, but I have no idea where to write that code or what it does.
The arraylist is currently stored as a public variable in the main activity class where it is accessed by the other activites.
public ArrayList<Swimmer> allSwimmers = new ArrayList<Swimmer>();
This is the activity where I use a list view to display all of the swimmers in the list and when one of the swimmers is clicked it goes to a new activity to display the swimmers info.
Everything is fine I just would like to save "MyActivity.allSwimmers" (the arraylist) somewhere where when the app closes and restarts its not blank
public class AllSwimmers extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.all_swimmers);
ListAdapter theAdapter = new ArrayAdapter<Swimmer>(this, android.R.layout.simple_list_item_1,
MyActivity.allSwimmers);
ListView theListView = (ListView) findViewById(R.id.allSwimmersList);
theListView.setAdapter(theAdapter);
theListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
Intent goToIndiv = new Intent(AllSwimmers.this, IndivSwimmer.class);
final int result = 1;
goToIndiv.putExtra("position", position);
startActivityForResult(goToIndiv, result);
}
});
}
}
To do this, you would have to save the data in a SQLiteDatabase. Here is a great tutorial on how to do it:
http://www.androidhive.info/2011/11/android-sqlite-database-tutorial/
Normally what you would want to do in order to be able to store custom data objects into memory, is to make them serializable.
You have to remember that persistent data outside the scope of a running application needs to be mapped into physical memory. In other words:
(As for) Serializing your data structure / object, means decomposing it into a format which can be stored.
Of course the other aspect of serialization is the ability to pick up this serialized data from memory into your enviroment as volatile objects / structure again.
In Java this is all done by adhering your custom data to Serializable interface. However since we are discussing for Android, it is much more recomended to adhere to Parcelable interface (better speed, efficiency and security managing data)
So, at first, there really seems to be no other reasonable way of acomplishing what you're asking than by the serialization (using Parcelable interface) of Swimmer in one way or another...
Here is a simple example of data modelling POJO with Parcelable:
public class Profile implements Parcelable {
private String id;
private String name;
private String category;
public Profile(String id, String name, String category){
this.id = id;
this.name = name;
this.category = category;
}
public Profile(Parcel in){
String[] data = new String[3];
in.readStringArray(data);
this.id = data[0];
this.name = data[1];
this.category = data[2];
}
#Оverride
public int describeContents(){
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStringArray(new String[] {this.id,this.name,this.category});
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public Profile createFromParcel(Parcel in) {
return new Profile(in);
}
public Profile[] newArray(int size) {
return new Profile[size];
}
};
}
The "problem" is that if you want to make use of SharedPreferences, it doesn't feature built in support for Parcelable, nor any other form of Serialized data mapping protocol since it is meant only for primitive key/value mapping by design. (SharedPreferences was built as means to store app configuration values that need persistance such as sound on/off, credentials, etc.., and not large data heaps).
However there is a rather neat "workaround" into using SharedPreferences out of convenience for storing custom Data objects with JSON. Of course the big advantage being JSON data easily serialized into String primitive.
Using default JSON api (org.json) you can make your own parse/convert functions valid for any type of POJO data. There is many different api for JSON data management and endless ways of manipulating it easily. Here is a basic example with nested json arrays:
SharedPreferences prefs = this.getSharedPreferences("MyCustomDataPreferences", Context.MODE_PRIVATE);
/* Assuming this JSON from SharedPreferences: "{animals : [{familyKey:Dogs},
{familyKey:Cats}, {familyKey:Lizards}]}" */
//Notice how JSONObject just takes a String as an argument:
JSONObject obj = new JSONObject(prefs.getString("animalsJSON", null));
List<String> list = new ArrayList<String>();
JSONArray array = obj.getJSONArray("animals");
//Store into list all values with key "familyKey":
for(int i = 0 ; i < array.length() ; i++){
list.add(array.getJSONObject(i).getString("familyKey"));
}
As you can see, this way you can simply store string values composed as JSON objects, then restore them back into java objects for use, using built in SharedPreferences.
I am trying to make some helper method in my Android project - method to set background with outline. I would like to method accepts different types of object (minimum is different Layouts) and call setBackground() on them. My code:
#SuppressLint("NewApi")
#SuppressWarnings("deprecation")
private static <I> void setBackgroundOutlined(Context context,
I item,
String backgroundColor,
String outlineColor, int outlineThickness,
Boolean setStatesPressed) {
GradientDrawable shapeDrawable = new GradientDrawable();
shapeDrawable.setStroke(CF.floatToPixels(context, outlineThickness),
Color.parseColor(outlineColor));
shapeDrawable.setColor(Color.parseColor(backgroundColor));
StateListDrawable states = new StateListDrawable();
states.addState(new int[] {android.R.attr.state_pressed,
android.R.attr.state_enabled},
context.getResources().getDrawable(R.drawable.textview_pressed_color));
states.addState(StateSet.WILD_CARD, shapeDrawable);
if (item instanceof RelativeLayoutWithContextMenuInfo) {
RelativeLayoutWithContextMenuInfo item2= (RelativeLayoutWithContextMenuInfo)item;
if (android.os.Build.VERSION.SDK_INT < 16) {
item2.setBackgroundDrawable(states);
} else {
item2.setBackground(states);
}
} else if (item instanceof LinearLayout) {
LinearLayout item2= (LinearLayout)item;
if (android.os.Build.VERSION.SDK_INT < 16) {
item2.setBackgroundDrawable(states);
} else {
item2.setBackground(states);
}
}
}
I really dislike repeating code in condiditons. Any suggestion to make it more clearly? Thanks, J.
addition to jacobhyphenated answer :
You don't need a generic method as you would only need to pass a parameter of ViewGroup type or its subclasses :
private static void setBackgroundOutlined(Context context,
/* you can pass any layout as item -> */ ViewGroup item,
String backgroundColor,
String outlineColor,
int outlineThickness,
Boolean setStatesPressed) {
// apply you logic on a item based on OS runtime API
}
The setBackgroundDrawable and setBackground methods exist in the ViewGroup class. You can enforce that any item must be or extend ViewGroup in your generic.
private static <I extends ViewGroup> void setBackgroundOutlined(Context context,
I item,
String backgroundColor,
String outlineColor, int outlineThickness,
Boolean setStatesPressed) {
....
if (android.os.Build.VERSION.SDK_INT < 16) {
item.setBackgroundDrawable(states);
} else {
item.setBackground(states);
}
}
But this will only work if you are always using the ViewGroup parent class.
I wouldn't make it as generic as it is now, since you're trying to do something quite specific, still.
You'd better be off swapping I to ViewGroup or View (although this might be too vague, still), or something like that.
It's not very generic to check for the object type in generic code, but using the right superclass for the objects you're trying to support (such that this superclass contains the methods you intent to call on the object) is a better approach.
I am new to Android development and I am trying to create a ListFragment that can create a ListView from 3 ArrayList objects each containing 30 Strings. Each row would contain a string from each array.
In my reading, I have found that a ListView is essentially created from an ArrayAdapter. The only examples I've seen of this however only show 1 String[] array being used (http://goo.gl/Yrkn0k, http://goo.gl/hqkdl).
How can I pass the three arrays to ArrayAdapter to create this ListView?
ArrayAdapters can work on lists of any sort. If you need to have an ArrayAdapter operate on three separate lists at once, you will need to do two things:
Create a new object class that is the combination of the three lists, eg. an Item class that has three fields: Title, Description, Price. Once you have a suitable object, turn your three lists into a single list of your object.
Then you will need to create a custom adapter class that extends ArrayAdapter, overriding the getView method in order to properly display your items.
Edit
Example:
public class Item {
private String title, desc, price;
public Item(String title, String desc, String price) {
this.title = title;
...
}
*provide standard getters and setters*
}
...
ArrayList<Item> items = new ArrayList<Item>();
for(int i = 0; i < titles.length; i++) {
items.add(new Item(titles[i], descriptions[i], prices[i]);
}
Then new adapter should take the form of
private class CustomAdapter extends ArrayAdapter<Item> {
public CustomAdapter(ArrayList<Item> items) {
super(getActivity(), 0, items);
}
...
The ArrayAdapter<T> class is generic, so you can use it with java Collections. To do what you're trying to do, you could use an ArrayList<ArrayList<String>> or just build model objects that contain your 3 string fields and use ArrayList<YourModel>.
For Example:
public class MyAdapter extends ArrayAdapter<ArrayList<ArrayList<String>>>{
//Constructor
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ArrayList<String> current = getItem(position);
//Do Something
}
}
I know this a pretty basic question, and already found another ones like mine, but I honestly don't know what I'm doing wrong.
public class InteractiveArrayAdapter extends ArrayAdapter<Model> {
private final List<Model> list;
private final Activity context;
public int teste;
public InteractiveArrayAdapter(Activity context, List<Model> list) {
super(context, R.layout.rowbuttonlayout, list);
this.context = context;
this.list = list;
}
public int getTest()
{
return teste;
}
static class ViewHolder {
protected TextView text;
protected CheckBox checkbox;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
teste = 2;
....
}
}
and other class:
try{
InteractiveArrayAdapter adapt = new InteractiveArrayAdapter(this,
getAPPS(0));
int test = adapt.getTest();
Toast.makeText(this, Integer.toString(test), Toast.LENGTH_LONG).show();
Log.v("TAG",Integer.toString(test));
}catch(Exception e)
{
Log.v("EXCEPTION",e.toString());
}
EDIT: I was getting null for a stupid mistake, and now I'm getting the primitive and expected 0 as most of you say.
At some point of my app, everytime a checkboxes is clicked that method getView is executed. I want to store that to an array[] of strings progressively (i+1) (i just put int to be easier to understand - realize now it was a mistake), and then when users inputs ok I want to access the whole array. Wondering if it's possible the way I want.
So when I do this
InteractiveArrayAdapter adapt = new InteractiveArrayAdapter(this,
getAPPS(0));
This is meaningless, because I don't need to execute anything again, I just want to retrieve the created array - if possible!
Your code won't even compile. return this.teste; should be return this.test;.
Well, this isn't a direct copy/paste, since this obviously wouldn't compile. Whenever you're dealing with an actual error or issue, it's really best to paste the actual code. We're all programmers, so we can read it.
But based on the structure you've shown above, either the typo you've put in the line return this.teste (should be return this.test) is in your code, or you didn't initialize the instance variable test in your constructor.
Without showing us the actual code you're writing, it's impossible to say (especially the section that initializes the test variable, and the part that returns its value are missing - we're not mind readers, I'm afraid).
So, those are two potential candidates. On another note, however, if you mark the test variable as public, then you don't need to have getter/setter methods for them, since any class can access them without going through a method call. That's what public does.
But that is what should happen according to your code. You don't call B method to update teste variable.