When I bind data in Adapter, I use Model to do this.
class ModelA{
ModelB b;
......
geters and setters
}
class ModelB{
ModelC c;
......
geters and setters
}
class ModelC{
String name;
......
geters and setters
}
when I want to use name, I need to do this:
bindData(ModelA a) {
String name = a.getModelB().getModelC().getName();
mTextView.setText(name);
}
but model may be null,so I added this:
bindData(ModelA a) {
if(a != null && a.getModelB() != null
&& a.getModelC() != null
&&!TextUtils.isempty(a.getModelB().getModelC().getName())) {
String name = a.getModelB().getModelC().getName();
mTextView.setText(name);
}
}
However I think use try catch may be easier,so I changed this:
bindData(ModelA a) {
try{
String name = a.getModelB().getModelC().getName();
mTextView.setText(name);
}catch (NullPointerException e) {
......
}
}
Is there a better way to judge model is null? if not, "if" and "try catch" which is better?
In my case, I checked if model is null in advance and I don't check variable from getter(). Because if it's null, we don't need to render views. (It's one of the reason why I want to move Java to Kotlin because I don't like checking NULL)
initViews() {
// handle your default data for Views
}
renderViews(ModelA a) {
ModelB modelB = a.getModelB;
if (modelB == null {
return;
}
// bind data of ModelB to Views
ModelC modelC = modelB.getModelC();
if (modelC == null) {
return;
}
// bind data of ModelC to Views
String name = modelC.getName();
mTextView.setText(name);
}
Related
I have 2 live data, I add them as sources to a mediator live data, I expose this from a view model for a fragment to observe.
When either of the live data changes it triggers the onChanged method of the mediator live data, which means my observer gets triggered twice, what I want is to combine the two and observe just one stream that only triggers once, is there something I'm missing or do I need to roll my own method for this? currently I do this, which triggers twice
SOME CODE REMOVED FOR BREVITY
public CardViewModel(#NonNull Application application , int clicks, String[] cardArgs){
sentenceRepository = new SentenceRepository(application);
cards = Transformations.switchMap(search, mySearch -> sentenceRepository.searchLiveCardListByWordTypeAndWordDescriptionAndSearchWord(cardArgs[0],cardArgs[1],mySearch));
groupRepository = new GroupRepository(application);
groups = groupRepository.getGroupsByWordDescriptionAndWordType(cardArgs[0],cardArgs[1]);
sentencesAndGroups = new MediatorLiveData<>();
sentencesAndGroups.addSource(cards, sentences -> {
Log.d(TAG,"addSource cards");
sentencesAndGroups.setValue(combineLatest(sentences, groups.getValue()));
});
sentencesAndGroups.addSource(groups, groupsWithSentences -> {
Log.d(TAG,"addSource groups");
sentencesAndGroups.setValue(combineLatest(cards.getValue(), groupsWithSentences));
});
}
private List<Visitable> combineLatest(List<Sentence> sentenceList, List<GroupsWithSentences> groupsWithSentences) {
List<Visitable> visitableList = new ArrayList<>();
if (sentenceList != null){
visitableList.addAll(sentenceList);
}
if (groupsWithSentences != null){
visitableList.addAll(groupsWithSentences);
}
return visitableList;
}
any help?
You can use a BiFunction. In my project I have a class which contains this:
public class MultipleLiveDataTransformation {
#MainThread
public static <X, Y, O> LiveData<O> biMap(LiveData<X> data1, LiveData<Y> data2, final BiFunction<X, Y, O> biFun) {
final MediatorLiveData<O> result = new MediatorLiveData<>();
result.addSource(data1, x -> result.setValue(biFun.apply(x, data2.getValue())));
result.addSource(data2, y -> result.setValue(biFun.apply(data1.getValue(), y)));
return result;
}
}
You can use it like this:
public LiveData<Visitable> getVisitables() {
return MultipleLiveDataTransformation.biMap(groups, sentences, (gro, sen) -> {
List<Visitable> visitableList = new ArrayList<>();
if (gro != null) {
visitableList.addAll(gro);
}
if (sen != null) {
visitableList.addAll(sen);
}
return visitableList;
});
}
I do not fully understand what lists you have and what you want to observe. The example I gave here can observe two LiveData objects and triggers when one of them needs to update. It will always give you the most up to date version of the Visitable objects.
If I don't understand the problem, can you explain what LiveData objects need to be combined and what the result needs to be?
In the case, that an extra LiveData object needs to be observed in the MultipleDataTransformation, it is possible to make a triMap.
Edit:
You can try this:
public LiveData<Visitable> getVisitables() {
return MultipleLiveDataTransformation.biMap(groups, sentences, (gro, sen) -> {
List<Visitable> visitableList = new ArrayList<>();
if (gro != null && !gro.isEmpty() && sen != null && !sen.isEmpty()) {
visitableList.addAll(gro);
visitableList.addAll(sen);
}
return visitableList;
});
}
I have to implement the multiple search query, how to achieve it , I know the basic idea of filtering the text with the search view but not getting the idea how to search with multiple string ,I am attaching the snapshot show it will make you feel better to get an idea.
I am loading the data from the webserver.
TruckInfo columns are:
Name of the truck
Total capacity (is the capacity of the truck)
Status Free/Busy (is the status of the truck which is currently all truck is free)
Free location (is the where truck is going to free).
Now as in snapshot second i have to filter this data , I had searched in the capacity column --> 10 tonnes to 45 tonnes, status is--> free , free location is -->CV , from 7wed2016 to 20 Fri 2016 and then i hit search button .
Expected output should not show any result because:
10 tonnes to 45 tonnes there is 2 truck ..which is right. as data coming from server
status of both the truck is free, which is right
Free location is CV that I searched, but as you can see both truck have free location mumbais, chandigarh, so this condition is false so overall search should show no data
My Try:
filter_search.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.e("filter_search","filter_search");
Localytics.tagEvent("Trucks Search Screen");
if(frmcap.getText().toString().length()==0){
frmcap_val=0;
cap_bool=1;
}
else
{
frmcap_val=Integer.parseInt(frmcap.getText().toString());
cap_bool=0;
}
if(tocap.getText().toString().length()==0) {
tocap_val=0;
cap_bool = 1;
}
else {
tocap_val=Integer.parseInt(tocap.getText().toString());
cap_bool=0;
}
if(from_loc_text.getText().length()==0)
loc_bool=1;
else
loc_bool=0;
if(frm_date_value.length()==0 || to_date_value.length()==0)
date_bool=1;
else
date_bool=0;
if(free.isChecked())
status_value="true";
if(busy.isChecked())
status_value="false";
if(any.isChecked())
status_value="any";
if(!any.isChecked()&&!free.isChecked()&&!busy.isChecked()){
Log.e("##inside","inside");
status_value="-default value";
}
if(!any.isChecked()&&!free.isChecked()&&!busy.isChecked())
status_bool=1;
if(search.getText().length()==0)
loc_search_info=1;
else
loc_search_info=0;
try {
if(status_value!=null && status_value.length()>0 && !status_value.equalsIgnoreCase("any")){
truckadapter.advanceSearchFilter(status_value,"checkBox");
list_mytrucks.setVisibility(View.VISIBLE);
}else if(status_value!=null && status_value.equalsIgnoreCase("any")){
list_mytrucks.setVisibility(View.VISIBLE);
}else if(frmcap.getText().toString()!=null && frmcap.getText().toString().length()>0){
truckadapter.advanceSearchFilter(frmcap_val+"","capacity");
list_mytrucks.setVisibility(View.VISIBLE);
}else if(tocap.getText().toString()!=null && tocap.getText().toString().length()>0){
truckadapter.advanceSearchFilter(tocap_val+"","capacity");
list_mytrucks.setVisibility(View.VISIBLE);
}else if(current_location.getText().length()>=0){
truckadapter.advanceSearchFilter(current_location.getText().toString(),"freeLocation");
list_mytrucks.setVisibility(View.VISIBLE);
}else if(fromdt.getText().length()>=0){
truckadapter.advanceSearchFilter(current_location.getText().toString(),"dateStamp");
list_mytrucks.setVisibility(View.VISIBLE);
}else if(todt.getText().length()>=0){
truckadapter.advanceSearchFilter(current_location.getText().toString(),"dateStamp");
list_mytrucks.setVisibility(View.VISIBLE);
}
view_advance_search.setVisibility(View.GONE);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
Here is searchFiletring in getViewMethod:
public void advanceSearchFilter(String constraint,String tag) throws JSONException {
items.clear();
if(constraint.isEmpty()){
items.addAll(advanceSearchArrayList);
} else{
constraint = constraint.toUpperCase();
for(int i=0;i<advanceSearchArrayList.size();i++){
JSONObject jsonData = new JSONObject(String.valueOf(advanceSearchArrayList.get(i).getVehicle()));
if(tag.equalsIgnoreCase("capacity")){
int truckCapacity=Integer.parseInt(constraint);
if(Integer.parseInt(jsonData.getJSONObject("type").getString("capacity").toUpperCase())>=truckCapacity){
items.add(advanceSearchArrayList.get(i));
}
}
if(tag.equalsIgnoreCase("checkBox")){
if(advanceSearchArrayList.get(i).getFree().toUpperCase().contains(constraint)){
items.add(advanceSearchArrayList.get(i));
}
}
if(tag.equalsIgnoreCase("freeLocation")){
if(advanceSearchArrayList.get(i).getFree().toUpperCase().equalsIgnoreCase("true")){
Log.e("getFree_loc",""+advanceSearchArrayList.get(i).getFree_loc());
if(advanceSearchArrayList.get(i).getFree_loc().toUpperCase().contains(constraint)){
items.add(advanceSearchArrayList.get(i));
}
}
}
if(tag.equalsIgnoreCase("dateStamp")){
SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy");
Date date = null;
try {
date = formatter.parse(constraint);
} catch (ParseException e) {
e.printStackTrace();
}
try {
if(formatter.parse(advanceSearchArrayList.get(i).getFree().toUpperCase()).before(date) ){
items.add(advanceSearchArrayList.get(i));
}
} catch (ParseException e) {
e.printStackTrace();
}
}
}
}
notifyDataSetChanged();
}
You need to still explicitly compare each filter to property of each object to see if it matches or not.
Just an idea for flow:
Make a class for filter input. when user clicks search button, assign all filter values to that class.
Make a method inside model class, that returns true if any of the filter value matches. That takes filter class object as argument.
Now when user clicks search button, iterate over each object in array. Call this method. If it returns true, add this object in new filter array.
Use that filter array to show search results.
Example Code
///////// Filter class
class FilterTrucks {
String location;
int capacityStart;
int capacityEnd;
Arraylist<String> availability;
}
////// You model class
class Mytrucks {
String name;
String location;
int capacity;
String availability;
boolean matchFilter(FilterTrucks filter) {
boolean locationMatch = filterMatchesLocation(filter);
if(locationMatch)
return true;
boolean matchCapacity = filterMatchesCapacity(filter);
if(matchCapacity)
return true;
return false;
}
boolean filterMatchesLocation(FilterTrucks filter) {
return location.contains(filter.location);
}
boolean filterMatchesCapacity(FilterTrucks filter) {
return (capacity >= filter.capacityStart || capacity <= filter.capacityEnd)
}
////////// Your activity
Arraylist<Mytrucks> filterArray = new Arraylist<>();
filter_search.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//create filter object from user selected fields
FilterTrucks filter = new FilterTrucks();
filter.location = txtLocation.getText().toString(); //for example
for(Mytrucks truck : arraylist) {
if(truck.matchFilter(filter))
filterArray.add(truck);
}
}
});
//use filter array to populate recycler view
Hope this helps!
I want to get value from several variables for example user1, user2, user3, user4.
how to check if variables are empty otherwise get the value and ignore variables that empty.
how I achieve this?, and sorry for newbie question...
if I do this
if(user1 != null && user2!= null && user3 != null && user4 != null){
user1.getText(); // or v1 = user1.value();
user2.getText(); // or v2 = user2.value();
user3.getText(); // or v3 = user3.value();
user4.getText(); // or v4 = user4.value();
}
which I dont want to do that, I just want to get the variable which had value in it and save it in array
Try with the following code.
ArrayList<String> listItems=new ArrayList<String>();
if(user1!=null)
{
listItems.add(user1.getText());
}
if(user2!=null)
{
listItems.add(user2.getText());
}
if(user3!=null)
{
listItems.add(user3.getText());
}
if(user4!=null)
{
listItems.add(user4.getText());
}
String [] arrayData = listItems.toArray(new String[listItems.size()]);
Note:You can also use isEmpty() method instead of checking for not a null value.
You mean a null check?
Value v1;
Value v2;
if (user1 != null) {
v1 = user1.value();
}
if (user2 != null) {
v2 = user2.value();
}
...etc
If you are dealing with String values then you may want to check the empty or null using TextUtils.isEmpty(str) API
public static boolean isEmpty (CharSequence str) Returns true if the string is null or 0-length.
if(user1!=null && !TextUtils.isEmpty(user1.getText()){
//not empty or null
}
Been struggling with this all day. I feel like I am one annotation away from the right solution.
I am getting an JSON from an API, and parsing it using Gson inside Volley request into a object.
Then I want to store the object in DB, using ORMLite.
The problem is that my JSON has lists of other objects. So I have decided that ForeignCollection are required.
Here is simplified version of what I am getting as JSON:
{
"b": [
{"title"="abc","id="24sfs"},
{"title"="def", "id="532df"}
],
"c": [
{"description"="abc","id="34325"},
{"description"="def", "id="34321"}
],
"id"="ejsa"
}
Lets call this whole object class A. The objects inside "b", are B, inside "c", class C.
B and C are the similar. This leads to the following class definitions:
class A {
#DatabaseField(index = true, unique = true, id = true)
private String id;
#ForeignCollectionField(eager = true)
public Collection<B> bCollection;
public ArrayList<B> b;
#ForeignCollectionField(eager = true)
public Collection<C> cCollection;
public ArrayList<C> c;
}
class B {
#DatabaseField(foreign=true)
public A a;
#DatabaseField(id = true, index = true, unique = true)
public String id;
#DatabaseField
public String title;
}
The reason we need the ArrayList b and c, is so that gson can parse it correctly. So once I have class A in memory, here is what I do to store it
private void storeA(A a) {
if (a.b != null) {
getHelper().getDao(B.class).callBatchTasks(new Callable<Void>() {
#Override
public Void call() throws Exception {
for (B b : a.b) {
b.a = a;
try {
getHelper().getDao(B.class).createOrUpdate(b);
} catch (Exception e) {
}
}
return null;
}
});
}
/*
Here we start running into problems. I need to move the data from the ArrayList to the Collection
*/
a.bCollection = a.b; // but this seems to work, since bCollection is a Collection
a.cCollection = a.c;
getHelper().getDao(A.class).createOrUpdate(a);
}
So it seems to store correctly, no errors as far as I can tell. But when I try to retrieve as follows, I can't retrieve anything out of bCollection:
private void load() {
try {
List<A> as = getHelper().getDao(A.class).queryForEq("id", "ejsa");
if (as != null && as.size() > 0) {
A a = as.get(0);
CloseableWrappedIterable<B> cwi = a.bCollection.getWrappedIterable();
try {
for (B b : cwi) {
Log.e(b.title);
}
} finally {
cwi.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
What am I doing wrong? Do I need to specify foreignColumnName for some of these things? I can't tell if the things are not being stored correctly or if I am just failing to retrieve them correctly?
I would try removing the following two lines:
a.bCollection = a.b;
a.cCollection = a.c;
A's ForeignCollection's should be auto-magically populated for you by ORMLite when you query for A, you do not need to set them yourself.
This question already has answers here:
How to remove duplicates from a list?
(15 answers)
Closed 8 years ago.
I want to remove duplicates from ArrayList of type Alerts where Alerts is a class.
Class Alerts -
public class Alerts implements Parcelable {
String date = null;
String alertType = null;
String discription = null;
public Alerts() {
}
public Alerts(String date, String alertType, String discription) {
super();
this.date = date;
this.alertType = alertType;
this.discription = discription;
}
}
Here is how I added the elements -
ArrayList<Alerts> alert = new ArrayList<Alerts>();
Alerts obAlerts = new Alerts();
obAlerts = new Alerts();
obAlerts.date = Date1.toString();
obAlerts.alertType = "Alert Type 1";
obAlerts.discription = "Some Text";
alert.add(obAlerts);
obAlerts = new Alerts();
obAlerts.date = Date2.toString();
obAlerts.alertType = "Alert Type 1";
obAlerts.discription = "Some Text";
alert.add(obAlerts);
What I want to remove from them-
I want all alerts which have unique obAlerts.date and obAlerts.alertType. In other words, remove duplicate obAlerts.date and obAlerts.alertType alerts.
I tried this -
Alerts temp1, temp2;
String macTemp1, macTemp2, macDate1, macDate2;
for(int i=0;i<alert.size();i++)
{
temp1 = alert.get(i);
macTemp1=temp1.alertType.trim();
macDate1 = temp1.date.trim();
for(int j=i+1;j<alert.size();j++)
{
temp2 = alert.get(j);
macTemp2=temp2.alertType.trim();
macDate2 = temp2.date.trim();
if (macTemp2.equals(macTemp1) && macDate1.equals(macDate2))
{
alert.remove(temp2);
}
}
}
I also tried-
HashSet<Alerts> hs = new HashSet<Alerts>();
hs.addAll(obAlerts);
obAlerts.clear();
obAlerts.addAll(hs);
You need to specify yourself how the class decides equality by overriding a pair of methods:
public class Alert {
String date;
String alertType;
#Override
public boolean equals(Object o) {
if (this == 0) {
return true;
}
if ((o == null) || (!(o instanceof Alert)))
return false;
}
Alert alert = (Alert) o;
return this.date.equals(alert.date)
&& this.alertType.equals(alert.alertType);
}
#Override
public int hashCode() {
int dateHash;
int typeHash;
if (date == null) {
dateHash = super.hashCode();
} else {
dateHash = this.date.hashCode();
}
if (alertType == null) {
typeHash = super.hashCode();
} else {
typeHash = this.alertType.hashCode();
}
return dateHash + typeHash;
}
}
You can then loop through your ArrayList and add elements if they aren't already there as Collections.contains() makes use of these methods.
public List<Alert> getUniqueList(List<Alert> alertList) {
List<Alert> uniqueAlerts = new ArrayList<Alert>();
for (Alert alert : alertList) {
if (!uniqueAlerts.contains(alert)) {
uniqueAlerts.add(alert);
}
}
return uniqueAlerts;
}
However, after saying all that, you may want to revisit your design to use a Set or one of its family that doesn't allow duplicate elements. Depends on your project. Here's a comparison of Collections types
You could use a Set<>. By nature, Sets do no include duplicates. You just need to make sure that you have a proper hashCode() and equals() methods.
In your Alerts class, override the hashCode and equals methods to be dependent on the values of the fields you want to be primary keys. Afterwards, you can use a HashSet to store already seen instances while iterating over the ArrayList. When you find an instance which is not in the HashSet, add it to the HashSet, else remove it from the ArrayList. To make your life easier, you could switch to a HashSet altogether and be done with duplicates per se.
Beware that for overriding hashCode and equals, some constraints apply.
This thread has some helpful pointers on how to write good hashCode functions. An important lesson is that simply adding together all dependent fields' hashcodes is not sufficient because then swapping values between fields will lead to identical hashCodes which might not be desirable (compare swapping first name and last name). Instead, some sort of shifting-operation is usually done before adding the next atomic hash, eg. multiplying with a prime.
First store your datas in array then split at as one by one string,, till the length of that data execute arry and compare with acyual data by if condition and retun it,,
HashSet<String> hs = new HashSet<String>();
for(int i=0;i<alert.size();i++)
{
hs.add(alert.get(i).date + ","+ alert.get(i).alertType;
}
alert.clear();
String alertAll[] = null;
for (String s : hs) {
alertAll = s.split(",");
obAlerts = new Alerts();
obAlerts.date = alertAll[0];
obAlerts.alertType = alertAll[1];
alert.add(obAlerts);
}