I want to make my database look like this:
FirebaseDB
I am adding ingredients' ingredientName from arrayList by looping them.
My question is how can I save easily quantity too. Measure will come from another DB path, when user added ingredientName
(for example "milk") to ListView.(but this is just a future plan, first I want to solve quantity)
Do I have to add EditText to list_item.xml ? Or how can I easily get quantity then save it?
The ingredientName saving method works perfectly but I don't know how can I easily store quantity for each ingredientName.
from AddIngredients activity:
private String key;
private ArrayList<String> arrayList=new ArrayList<>();
ListView listView=(ListView) findViewById(R.id.listv);
txtInput=(EditText) findViewById(R.id.IngredientsInput);
private DatabaseReference ingDBref = FirebaseDatabase.getInstance().getReference("Ingredients");
private DatabaseReference DBref= FirebaseDatabase.getInstance().getReference("Recipes");
adapter=new ArrayAdapter<String>(this,R.layout.list_item,R.id.ingredientName,arrayList);
listView.setAdapter(adapter);
public void addIngredients(){
final String IngredientName=txtInput.getText().toString();
ingDBref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot data: dataSnapshot.getChildren()){
if(data.child("ingredientName").getValue().equals(IngredientName)){
//If ingredientName=allowed ingredientNames from DB
arrayList.add(IngredientName);
adapter.notifyDataSetChanged();
Toast.makeText(this,"Added to ListView...",Toast.LENGTH_LONG).show();
}
else{
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
public void saveIngredients(){
key=DBref.child.push().getKey();
String ingredientName;
for(int i=0;i<arrayList.size();i++){
ingredientName=arrayList.get(i);
Ingredients ingredients=new Ingredients(ingredientName);
DBref.child(key).child("Ingredients").child(ingredientName).setValue(ingredients);
}
Ingredients Class:
public class Ingredients {
String ingredientName;
// String ingredientQty;
// String measureName;
public Ingredients(){
}
public Ingredients(String IngredientName){
this.ingredientName=IngredientName;
// this.ingredientQty=IngredientQty;
//this.measureName=MeasureName;
}
#Override
public String toString() {
return super.toString();
}
public String getIngredientName(){
return ingredientName;
}
/*
public String getIngredientQty(){
return ingredientQty;
}*/
/*
public String getMeasureName(){
return measureName;
}*/
}
list_item.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/ingredientName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="24sp" />
</LinearLayout>
-KvN3vdtkelmdlemakm33kml
-Ingredients
-milk
-ingredientName: "milk"
-measure: "dl"
-quantity: "2"
-sugar
-ingredientName: "sugar"
-measure: "g"
-quantity: "50"
-recipeDescription: "asd"
-recipeID: "KvN3vdtkelmdlemakm33kml"
-recipeName: "testRecipe"
The impoartant is under Ingredients.
Related
I want to retrieve all child of my firebase database with for loop and data will be shown in recyclerview in a fragment. When I go event fragment, app crash and the error point out to the line of for looping
here is my code,
events.java(this is fragment)
FirebaseDatabase.getInstance().getReference().child("Users/" + mUser.getUid() + "/Groups/RequestedGroups").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()){
value = ds.child("GroupID").getValue().toString();
groupId.add(value);
}
retrieveGroups(groupId);
}
private void retrieveGroups(ArrayList<String> groupId) {
if(groupId != null){
for(String value : groupId){
FirebaseDatabase.getInstance().getReference().child("Events/"+value).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot d : dataSnapshot.getChildren()){
Event_Retrieve e = d.getValue(Event_Retrieve.class); // error point out this line
list.add(e);
}
adapter = new MyAdapter(events.this.getActivity(),list);
recyclerView.setAdapter(adapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(events.this.getActivity(), "oops", Toast.LENGTH_SHORT).show();
}
});
}
}
}
Event_Retrieve.java
public class Event_Retrieve {
public String eventname;
public String eventdescription;
public String eventdate;
public String eventtime;
public String eventphotourl;
public String latitude;
public String lingitude;
public ArrayList<String> acceptedmember;
public ArrayList<String> invitedmember;
public Event_Retrieve(){
}
public Event_Retrieve(String eventname, String eventdescription, String eventdate, String eventtime, String eventphotourl, String latitude, String lingitude, ArrayList<String> acceptedmember, ArrayList<String> invitedmember) {
this.eventname = eventname;
this.eventdescription = eventdescription;
this.eventdate = eventdate;
this.eventtime = eventtime;
this.eventphotourl = eventphotourl;
this.latitude = latitude;
this.lingitude = lingitude;
this.acceptedmember = acceptedmember;
this.invitedmember = invitedmember;
}
public String getEventname() {
return eventname;
}
public String getEventdescription() {
return eventdescription;
}
public String getEventdate() {
return eventdate;
}
public String getEventtime() {
return eventtime;
}
public String getEventphotourl() {
return eventphotourl;
}
public String getLatitude() {
return latitude;
}
public String getLingitude() {
return lingitude;
}
public ArrayList<String> getAcceptedmember() {
return acceptedmember;
}
public ArrayList<String> getInvitedmember() {
return invitedmember;
}
}
fragment_event.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background"
tools:context=".places">
<!-- TODO: Update blank fragment layout -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/eventID"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:text="Events"
android:textColor="#000"
android:textSize="30sp" />
<android.support.v7.widget.RecyclerView
android:id="#+id/myRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Logcat error
E/HotwordDetector: Error at creating and/or starting hotword recognition.
java.lang.IllegalArgumentException: Invalid speaker model provided
at com.google.speech.micro.GoogleHotwordRecognizer.nativeNew(Native Method)
at com.google.speech.micro.GoogleHotwordRecognizer.<init>(SourceFile:6)
at com.google.android.libraries.assistant.hotword.k.a(SourceFile:66)
at com.google.android.libraries.assistant.hotword.k.at(SourceFile:35)
at com.google.android.apps.gsa.voiceinteraction.hotword.a.dGU(SourceFile:48)
at com.google.android.voiceinteraction.GsaVoiceInteractionService.dGU(SourceFile:109)
at com.google.android.voiceinteraction.g.oa(SourceFile:13)
at com.google.android.libraries.assistant.hotword.f.a(SourceFile:30)
at com.google.android.libraries.assistant.hotword.g.run(Unknown Source)
at com.google.android.libraries.gsa.runner.a.b.run(Unknown Source)
at com.google.android.apps.gsa.shared.util.concurrent.b.cq.bsW(SourceFile:2)
at com.google.android.apps.gsa.shared.util.concurrent.b.cp.run(SourceFile:5)
at com.google.android.apps.gsa.shared.util.concurrent.b.i.run(Unknown Source)
at com.google.android.apps.gsa.shared.util.concurrent.b.bs.run(SourceFile:3)
at com.google.android.apps.gsa.shared.util.concurrent.b.bs.run(SourceFile:3)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:760)
at com.google.android.apps.gsa.shared.util.concurrent.b.o.run(SourceFile:6)
My Database Structure
this is test data
I am trying to bind a boolean through the viewmodel to the view, but Android Studio throws an error, and I can't find the problem. The viewModel.infilltype is a boolean, and android:checked should also be a boolean.
"error: '#{viewModel.infillType}' is incompatible with attribute android:checked (attr) boolean.
Message{kind=ERROR, text=error: '#{viewModel.infillType}' is incompatible with attribute android:checked (attr) boolean., sources=[E:\SportveldOnderhoud\app\src\main\res\layout\list_item_check.xml:14], original message=, tool name=Optional.of(AAPT)}"
I have the following code (I will paste snippets which are relevant)
Check.java (Model)
public class Check {
private UUID mId;
private String mTitle;
private Date mDate;
....
private boolean mInfilltype;
....
public Check() {
this(UUID.randomUUID());
}
public Check(UUID id) {
mId = id;
mDate = new Date();
}
public UUID getId() {
return mId;
}
....
public boolean isInfilltype() {
return mInfilltype;
}
public void setInfilltype(boolean infilltype) {
mInfilltype = infilltype;
}
}
ViewModel:
public class CheckViewModel extends BaseObservable {
private Check mCheck;
private Activity mActivity;
public CheckViewModel(Activity activity) {
mActivity = activity;
}
#Bindable
public String getTitle() {
return mCheck.getTitle();
}
#Bindable
public String getRenderedDate() {
return mCheck.getDate().toString();
}
#Bindable
public boolean infillType() {
return mCheck.isInfilltype();
}
public Check getCheck() {
return mCheck;
}
public void setCheck(Check crime) {
mCheck = crime;
List<String> strings;
notifyChange();
}
public void onCheckClicked() {
Intent intent = CheckPagerActivity.newIntent(mActivity, mCheck.getId());
mActivity.startActivity(intent);
}
}
View:
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable name="viewModel" type="nl.lekolkman.android.sportveldonderhoud.CheckViewModel" />
</data>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="#{() -> viewModel.onCheckClicked()}"
>
<CheckBox
android:id="#+id/solved_check_box"
android:checked="#{viewModel.infillType}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"/>
<TextView
android:id="#+id/title_text_view"
android:text="#{viewModel.title}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="#id/solved_check_box"
android:textStyle="bold"
tools:text="Crime Title"/>
<TextView
android:id="#+id/date_text_view"
android:text="#{`Date solved: ` + viewModel.renderedDate ?? `(not solved)`}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="#id/solved_check_box"
android:layout_below="#id/title_text_view"
tools:text="Check Date"/>
</RelativeLayout>
</layout>
It turned out that I had to add:
android {
...
dataBinding {
enabled = true
}
in build.gradle
Then it still didn't work however, but after adding maven to the repositories in the build.gradle files it did work
I'm not super familiar with java, but I'm pretty sure in C# your boolean needs an initial value (not null) to bind properly.
Try changing
private boolean mInfilltype;
to
private boolean mInfilltype = false;
You can use or expand Android Compound View Binding Adapter
import androidx.databinding.BindingAdapter;
import androidx.databinding.BindingMethod;
import androidx.databinding.BindingMethods;
import androidx.databinding.InverseBindingListener;
import androidx.databinding.InverseBindingMethod;
import androidx.databinding.InverseBindingMethods;
import androidx.annotation.RestrictTo;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
/**
* #hide
*/
#RestrictTo(RestrictTo.Scope.LIBRARY)
#BindingMethods({
#BindingMethod(type = CompoundButton.class, attribute = "android:buttonTint", method = "setButtonTintList"),
#BindingMethod(type = CompoundButton.class, attribute = "android:onCheckedChanged", method = "setOnCheckedChangeListener"),
})
#InverseBindingMethods({
#InverseBindingMethod(type = CompoundButton.class, attribute = "android:checked"),
})
public class CompoundButtonBindingAdapter {
#BindingAdapter("android:checked")
public static void setChecked(CompoundButton view, boolean checked) {
if (view.isChecked() != checked) {
view.setChecked(checked);
}
}
#BindingAdapter(value = {"android:onCheckedChanged", "android:checkedAttrChanged"},
requireAll = false)
public static void setListeners(CompoundButton view, final OnCheckedChangeListener listener,
final InverseBindingListener attrChange) {
if (attrChange == null) {
view.setOnCheckedChangeListener(listener);
} else {
view.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (listener != null) {
listener.onCheckedChanged(buttonView, isChecked);
}
attrChange.onChange();
}
});
}
}
}
Ref: https://android.googlesource.com/platform/frameworks/data-binding/+/refs/heads/studio-master-dev/extensions/baseAdapters/src/main/java/androidx/databinding/adapters/CompoundButtonBindingAdapter.java
I am having a problem with cardview not displaying some from the database.
My app connects to a grails back end which has a PostgreSQL db.
I have a cardview inside a recyclerview. It receives 7 values in form of JSON but on running the app, only 5 are displayed. I try doing System.out of the JSON in the stack trace and I find that all the 7 values are received so everything is okay on that front.
For clarity purposes, the fields that are not being displayed are labs("labs") and drugs administered("drugsAdministered").
Here is the main class(ClinicalHistory.java), the adapter class, the xml and the stack-trace.
ClinicalHistory.java
public class ClinicalHistory extends AppCompatActivity {
RecyclerView clinicalHistory_rv;
SwipeRefreshLayout swipeRefreshLayout;
List<com.example.user.eafya.models.ClinicalHistory> clinicalHistory_List;
com.example.user.eafya.models.ClinicalHistory clinicalHistory;
ClinicalHistoryAdapter clinicalHistoryAdapter;
private StringRequest clinicalHistoryRequest;
private LinearLayout no_data;
private LinearLayoutManager linearLayoutManager;
private RequestQueue requestQueue;
private ProgressDialog pb;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_clinical_history);
initWidgets();
fetchData();
}
private void fetchData() {
pb = new ProgressDialog(this);
pb.setIcon(R.mipmap.ic_launcher);
pb.setTitle("Please wait");
pb.setCancelable(false);
pb.setMessage("Loading data..");
pb.show();
clinicalHistoryRequest = new StringRequest(Request.Method.GET, Configs.URL_LOGIN + Configs.CLINICALHISTORY_PATH, new Response.Listener<String>() {
#Override
public void onResponse(String result) {
pb.dismiss();
System.out.print("======================================"+ result);
try {
JSONObject jsonObject = new JSONObject(result);
JSONArray jsonArray = jsonObject.getJSONArray("mVisit");
for (int i=0;i<jsonArray.length();i++){
System.out.print("----------------"+jsonArray.getJSONObject(i).getString("labs"));
}
Log.d("myError: ", String.valueOf(jsonArray.length()));
if(jsonArray.length()<1) {
clinicalHistory_List.clear();
no_data.setVisibility(View.VISIBLE);
}else if( jsonArray.length()>0){
if(no_data.getVisibility()==View.VISIBLE){
no_data.setVisibility(View.GONE);
}
for(int i=0 ; i<jsonArray.length() ; i++){
JSONObject data = jsonArray.getJSONObject(i);
clinicalHistory = new com.example.user.eafya.models.ClinicalHistory();
clinicalHistory.setDate(data.getString("dateCreated"));
clinicalHistory.setHospital(data.getString("hospitalAttended"));
clinicalHistory.setDoctor(data.getString("attendingDoctor"));
clinicalHistory.setLabs(data.getString("labs"));
clinicalHistory.setChiefComplains(data.getString("chiefComplains"));
clinicalHistory.setDrugs(data.getString("drugsAdministered"));
clinicalHistory_List.add(clinicalHistory);
}
clinicalHistoryAdapter = new ClinicalHistoryAdapter(ClinicalHistory.this, clinicalHistory_List);
linearLayoutManager = new LinearLayoutManager(ClinicalHistory.this);
clinicalHistory_rv.setLayoutManager(linearLayoutManager);
clinicalHistory_rv.setItemAnimator(new DefaultItemAnimator());
clinicalHistory_rv.setAdapter(clinicalHistoryAdapter);
clinicalHistory_rv.setSaveEnabled(true);
clinicalHistory_rv.setSaveFromParentEnabled(true);
clinicalHistoryAdapter.notifyDataSetChanged();
}
} catch (JSONException e) {
Log.d("MaeraJ",e.toString());
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
pb.dismiss();
AlertDialog.Builder dialog = new AlertDialog.Builder(ClinicalHistory.this);
dialog.setTitle("Something went wrong !!");
dialog.setCancelable(true);
dialog.setIcon(R.mipmap.ic_launcher);
dialog.setMessage("Check your data connection");
dialog.setPositiveButton("RETRY", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
//retry
dialogInterface.dismiss();
fetchData();
}
});
dialog.setNegativeButton("CANCEL", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
//cancel
dialogInterface.dismiss();
}
});
dialog.create();
dialog.show();
Log.d("Maera",volleyError.toString());
}
});
requestQueue.add(clinicalHistoryRequest);
}
private void initWidgets() {
requestQueue = Volley.newRequestQueue(this);
no_data = findViewById(R.id.nodata_LY);
clinicalHistory_rv = findViewById(R.id.clinicalHistory_RV);
clinicalHistory_List = new ArrayList<>();
swipeRefreshLayout = findViewById(R.id.swipeContainer);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
refresh();
}
});
}
private void refresh() {
try {
clinicalHistory_List.clear();
fetchData();
swipeRefreshLayout.setRefreshing(false);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case R.id.home:
onBackPressed();
break;
}
return super.onOptionsItemSelected(item);
}
}
Adapter class(ClinicalHistoryAdapter.java)
public class ClinicalHistoryAdapter extends RecyclerView.Adapter<ClinicalHistoryAdapter.myViewHolder> {
Context ctx;
List<ClinicalHistory> clinicalHistoryList;
ClinicalHistory clinicalHistoryModel;
LayoutInflater inflater;
public ClinicalHistoryAdapter(Context ctx, List<ClinicalHistory> clinicalHistoryList) {
this.ctx = ctx;
this.clinicalHistoryList = clinicalHistoryList;
inflater = LayoutInflater.from(ctx);
}
public class myViewHolder extends RecyclerView.ViewHolder {
TextView clinicalHist_date_TV,clinicalHist_hospital, clinicalHist_doctor,clinicalHist_chiefComplains, clinicalHist_labs, clinicalHist_drugs;
ImageView clinicalHist_img;
public myViewHolder(View itemView) {
super(itemView);
clinicalHist_img = itemView.findViewById(R.id.clinicalHist_image_IV);
clinicalHist_date_TV = itemView.findViewById(R.id.clinicalHist_date__TV);
clinicalHist_hospital = itemView.findViewById(R.id.clinicalHist_hospital_TV);
clinicalHist_doctor = itemView.findViewById(R.id.clinicalHist_doctor);
clinicalHist_chiefComplains = itemView.findViewById(R.id.clinicalHist_chief_complains_TV);
clinicalHist_labs = itemView.findViewById(R.id.clinicalHist_labs_TV);
clinicalHist_drugs = itemView.findViewById(R.id.clinicalHist_drugs_TV);
}
}
#Override
public ClinicalHistoryAdapter.myViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View my_view = inflater.inflate(R.layout.clinical_history_item,viewGroup,false);
return new myViewHolder(my_view);
}
#Override
public void onBindViewHolder(ClinicalHistoryAdapter.myViewHolder myViewHolder, final int position) {
clinicalHistoryModel = new ClinicalHistory();
clinicalHistoryModel = clinicalHistoryList.get(position);
myViewHolder.clinicalHist_date_TV.setText(clinicalHistoryModel.getDate());
myViewHolder.clinicalHist_hospital.setText(clinicalHistoryModel.getHospital());
myViewHolder.clinicalHist_doctor.setText(clinicalHistoryModel.getDoctor());
myViewHolder.clinicalHist_chiefComplains.setText(clinicalHistoryModel.getChiefComplains());
myViewHolder.clinicalHist_labs.setText(clinicalHistoryModel.getLabs());
myViewHolder.clinicalHist_drugs.setText(clinicalHistoryModel.getDrugs());
myViewHolder.clinicalHist_doctor.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
goToDetails(position);
}
});
myViewHolder.clinicalHist_hospital.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
goToDetails(position);
}
});
Glide.with(ctx).load(clinicalHistoryModel.getImg()).placeholder(R.drawable.loader).error(R.drawable.header).into(myViewHolder.clinicalHist_img);
}
private void goToDetails(int pos) {
clinicalHistoryModel = clinicalHistoryList.get(pos);
Intent intent = new Intent(ctx,MedicalDetailActivity.class);
intent.putExtra("dateCreated", clinicalHistoryModel.getDate());
intent.putExtra("clinicalHist_img", clinicalHistoryModel.getImg());
intent.putExtra("hospitalAttended", clinicalHistoryModel.getHospital());
intent.putExtra("attendingDoctor", clinicalHistoryModel.getDoctor());
intent.putExtra("chiefComplaints", clinicalHistoryModel.getChiefComplains());
intent.putExtra("labs", clinicalHistoryModel.getLabs());
intent.putExtra("drugs", clinicalHistoryModel.getLabs());
ctx.startActivity(intent);
}
#Override
public int getItemCount() {
return clinicalHistoryList.size();
}
}
The xml file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_margin="2dp"
android:orientation="horizontal"
android:padding="2dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/clinicalHist_image_IV"
android:layout_width="110dp"
android:layout_height="80dp"
android:layout_gravity="top"
android:scaleType="fitXY"
android:src="#drawable/header" />
<LinearLayout
android:padding="4dp"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:textAlignment="textStart"
android:layout_gravity="start"
android:id="#+id/clinicalHist_date__TV"
android:text="21/09/2012"
android:textColor="#color/colorAccent"
android:textAppearance="#android:style/TextAppearance.DeviceDefault.Medium"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:textAlignment="textStart"
android:layout_gravity="start"
android:id="#+id/clinicalHist_hospital_TV"
android:text="Hema Hospital"
android:textColor="#color/colorAccent"
android:textAppearance="#android:style/TextAppearance.DeviceDefault.Medium"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:id="#+id/clinicalHist_doctor"
android:text="Dr.Lilian"/>
<TextView
android:layout_gravity="center"
android:id="#+id/clinicalHist_labs_TV"
android:text=" Brucella "
android:textColor="#000"
android:textAppearance="#android:style/TextAppearance.DeviceDefault.Medium"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:layout_gravity="center"
android:id="#+id/clinicalHist_chief_complains_TV"
android:text=" Headache "
android:textColor="#000"
android:textAppearance="#android:style/TextAppearance.DeviceDefault.Medium"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:layout_gravity="center"
android:id="#+id/clinicalHist_drugs_TV"
android:text=" Brufen "
android:textColor="#000"
android:textAppearance="#android:style/TextAppearance.DeviceDefault.Medium"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
The stack trace
I/System.out: ======================================{"mVisit":[{"id":1,"chiefComplains":"Headache","dateCreated":"2017-08-11T21:00:00Z","labs":"Brucella","hospitalAttended":"Hema Hospital","drugsAdministered":"Tramadol","attendingDoctor":"Dr. Kisinga"
I have found the solution. The problem was in the model.
This was my previous model. Note the parameters in the
setDrugs() and setLabs().
public class ClinicalHistory {
String img;
String date;
String labs;
String hospital;
String chiefComplains;
String doctor;
String drugs;
public ClinicalHistory() {
}
public String getImg() {
return img;
}
public void setImg(String img) {
this.img = img;
}
public String getHospital() {
return this.hospital = hospital ;
}
public void setHospital(String hospital) {
this.hospital = hospital;
}
public String getChiefComplains(){return this.chiefComplains = chiefComplains;}
public void setChiefComplains(String chiefComplains){ this.chiefComplains = chiefComplains;}
public String getLabs() {
return this.labs = labs ;
}
public void setLabs(String hospital) {
this.labs = labs;
}
public String getDoctor() {
return this.doctor = doctor ;
}
public void setDoctor(String doctor) {
this.doctor = doctor;
}
public void setDrugs(String hospital) {
this.drugs = drugs;
}
public String getDrugs() {
return this.drugs = drugs ;
}
public void setDate(String date) {
this.date = date;
}
public String getDate() {
return date;
}
}
After I made this change it worked
public class ClinicalHistory {
String img;
String date;
String labs;
String hospital;
String chiefComplains;
String doctor;
String drugs;
public ClinicalHistory() {
}
public String getImg() {
return img;
}
public void setImg(String img) {
this.img = img;
}
public String getHospital() {
return this.hospital = hospital ;
}
public void setHospital(String hospital) {
this.hospital = hospital;
}
public String getChiefComplains(){return this.chiefComplains = chiefComplains;}
public void setChiefComplains(String chiefComplains){ this.chiefComplains = chiefComplains;}
public String getLabs() {
return this.labs = labs ;
}
public void setLabs(String labs) {
this.labs = labs;
}
public String getDoctor() {
return this.doctor = doctor ;
}
public void setDoctor(String doctor) {
this.doctor = doctor;
}
public void setDrugs(String drugs) {
this.drugs = drugs;
}
public String getDrugs() {
return this.drugs = drugs ;
}
public void setDate(String date) {
this.date = date;
}
public String getDate() {
return date;
}
}
I have an activity which generates a scrollable list (let's say a column) of programmatically created buttons from a List which is the result of an sqlite table read and my problem is that as the List is growing (and so the number of buttons) the initial painting of the screen is becoming slow (at the moment is taking 3 seconds with 50 buttons to draw) so I'm looking for a solution to this.
At first I thought of using a thread (runnable, handler or whatever is best), let's say creating a new thread inside the For which iterates over the list but it's not working (or at least I'm not being able to make it to work) so my question is the next:
Starting from a List<> which is the most appropiate way to create a big set of scrollable buttons so users doesn't have such delay when accesing the screen.
Paginating could be an option, but I'd like to know about other possibilities first and leave that as a last resource.
Thanks, and below is my code.
public static void createButtons(LinearLayout llContainer,
List<TestType> TestTypes, List<Test> Tests,
int buttonFontSize) {
Context oContext = llContainer.getContext();
String strTheme = TMAppearance.getThemeFromPreferences(oContext);
testMe = ((ApplicationConfiguration)oContext.getApplicationContext());
int callerActivity = TestTypes!=null ? 2 : 1;
if (TestTypes!=null || Tests!=null) {
int lCols = strTheme.equals(testMe.theme_vivid) ? 1 : 2;
//int sourceElementIndex = 0;
int originListSize = calculateOriginalListSize(callerActivity, TestTypes, Tests);
int lRows = (int) Math.ceil((double)originListSize/lCols);
List<String> aStartColors = TMUtils_ThemeVivid.generateStartColorArray(lRows, oContext);
List<String> aEndColors = TMUtils_ThemeVivid.generateEndColorArray(lRows, oContext);
for (i = 0; i < lRows; i++) {
LinearLayout outerButtonLayout = generateOuterButtonLayout(oContext);
for (j = 0; j < lCols; j++) {
final Thread r = new Thread() {
public void run() {
LinearLayout innerButtonLayout = generateInnerButtonLayout(oContext);
outerButtonLayout.addView(innerButtonLayout, j);
if (sourceElementIndex<originListSize){
final TMButton oButton = new TMButton(oContext);
if (callerActivity==1) { //testMenu
setTestMenuButtonSettings(oButton, sourceElementIndex, Tests);
} else {
if (callerActivity==2) { //testTypeMenu
setTestTypeMenuButtonSettings(oButton, sourceElementIndex, TestTypes);
}
}
if (strTheme.equals(testMe.theme_vivid)){
oButton.fontSize = buttonFontSize;
oButton.gradientStartColor = aStartColors.get(i);
oButton.gradientEndColor = aEndColors.get(i);
}else{
if (strTheme.equals(testMe.theme_purple)){
oButton.gradientStartColor = testMe.btnStartColor_purple;
oButton.gradientEndColor = testMe.btnEndColor_purple;
}
}
configureButton(oButton, callerActivity);
oButton.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Context oContext = v.getContext();
TMButton oButton = (TMButton) v;
int callerActivity = Integer.valueOf(v.getTag().toString().split("#")[0]);
String sourceId = String.valueOf(v.getTag().toString().split("#")[1]);
if(event.getAction() == MotionEvent.ACTION_DOWN) { //pressed
setButtonPressed(oButton);
TMSound.playButtonSound(oContext);
} else if (event.getAction() == MotionEvent.ACTION_UP) { //released
setButtonReleased(oButton);
startTargetActivity(callerActivity, sourceId, oContext);
}
return true;
}
});
TMAppearance.doButtonAnimation(oContext, oButton, i);
innerButtonLayout.addView(oButton);
sourceElementIndex++;
}
}
};
r.run();
}
llContainer.addView(outerButtonLayout);
}
}
}
0X0nosugar is correct. A RecycleView will provide better performance, but many beginners have more difficulty implementing it and with only 50 buttons performance shouldn't really be an issue. And although I generally like to abide by the rule 'Use the best available solution' I think it is still appropriate to learn how to implement the ListView. So...
You will need to create a custom adapter:
public class MyListDataAdapter extends ArrayAdapter<MyListData> {
private static final String TAG = "MyListDataAdapter";
public MyListDataAdapter(Context context, ArrayList<MyListData> data) {
super(context, 0, data);
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
final MyListData data = getItem(position);
if(convertView == null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.edit_list_item, parent, false);
}
// Add a TextView if you need one
final TextView tvName = (TextView) convertView.findViewById(R.id.tvName);
Button btnEditTicketHolder = (Button) convertView.findViewById(R.id.btnEdit);
btnEditTicketHolder.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
long userId = data.getUserId();
String fName = data.getFirstName();
Intent intent = new Intent(getContext(), EditActivity.class);
intent.putExtra("userId", userId);
intent.putExtra("fName", fName);
getContext().startActivity(intent);
}
});
String name = data.getFirstName();
tvName.setText(name);
return convertView;
}
}
Now you need your MyListData class to hold the data:
public class MyListData {
// Add more as you need
private long userId;
private String firstName;
public MyListData(){
}
public void setFirstName(String name){ this.firstName = name; }
public void setUserId(long id){ this.userId = id; }
public String getFirstName(){ return this.firstName; }
public long getUserId(){ return this.userId; }
}
Your custom ListView layout could look something like:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
>
<TextView
android:id="#+id/tvName"
android:text="With Whom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
>
<Button
android:id="#+id/btnEdit"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:paddingRight="10dp"
android:paddingLeft="10dp"
android:text="Edit"
android:backgroundTint="#color/colorAccent"
android:focusable="false"
/>
</LinearLayout>
</RelativeLayout>
In your Activity (eg. in the onCreate() method) where the ListView you will need to populate the data for the ListView. This should not be done on the UI Thread
ArrayList<MyListData> arrayListData = new ArrayList<MyListData>();
MyListDataAdapter adapter = new MyListDataAdapter(this, arrayListData);
for (MyListData g : result) {
adapter.add(g);
}
mLstMy.setAdapter(adapter);
Also in the activity where the ListView is to be maintained set up some onClick event handlers if you need them:
(I find that one of the small advantages of the ListView is that the onClick event is easier it implement than in the RecycleView)
mMyLst = (ListView) findViewById(lstMy);
mMyLst.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long l) {
MyListData data = (MyListData) parent.getItemAtPosition(position);
selectedName = data.getName();
Intent intent = new Intent(ShowListDataActivity.this, MainActivity.class);
startActivity(intent);
}
});
mMyLst.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
MyListData data = (MyistData) adapterView.getItemAtPosition(i);
selectedName = data.getFirstName();
selectedTicketPosition = i;
// removeValue is my own method for removing an entry from the
// list MyListData and then call adapter.notifyDataSetChanged();
removeValue(i);
return true;
}
});
I'm developing a tiny app that has a value in a textview set to 150,000 by default. Each month I reset the value back to the default. Every time I spend some of that amount, I open my app and enter the amount I spent and the details of what it was spent on.
What I did was create an offline database to store all the times I spent some of that amount, along with it's id and details. Each time I press the "spend" button, the total amount is reduced by the amount I have entered in the EditText.
I haven't implemented how I'll update the total amount yet, I believe I have to use something called sharedpreference number.
This is the main activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button spendMoney = (Button)this.findViewById(R.id.spendMoney);
Button test = (Button)this.findViewById(R.id.test);
TextView totalTxt = (TextView) this.findViewById(R.id.totalTxt);
final EditText spendAmount = (EditText)this.findViewById(R.id.spendAmount);
// int totalAmount = Integer.parseInt(totalTxt.getText().toString());
final Paid_DB db = new Paid_DB(this);
spendMoney.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
db.addPayment(new Payment(0, (Integer.parseInt(spendAmount.getText().toString())), "Test Details"));
}
});
//totalAmount = totalAmount - Integer.parseInt(spendAmount.getText().toString());
// totalTxt.setText(totalAmount);
test.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(null, DetailsActivity.class);
startActivity(i);
}
});
XML file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.user.paid.MainActivity">
<TextView
android:id="#+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="13dp"
android:layout_marginStart="13dp"
android:layout_marginTop="53dp"
android:fontFamily="sans-serif"
android:text="Total:"
android:textSize="30sp"
tools:layout_editor_absoluteX="25dp"
tools:layout_editor_absoluteY="36dp" />
<EditText
android:id="#+id/spendAmount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="number"
tools:layout_editor_absoluteX="72dp"
tools:layout_editor_absoluteY="143dp"
android:layout_marginBottom="38dp"
android:layout_above="#+id/spendMoney"
android:layout_centerHorizontal="true" />
<Button
android:id="#+id/spendMoney"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Spend Money"
tools:layout_editor_absoluteX="115dp"
tools:layout_editor_absoluteY="215dp"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
<TextView
android:id="#+id/totalTxt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/textView3"
android:layout_alignBottom="#+id/textView3"
android:layout_alignEnd="#+id/spendMoney"
android:layout_alignRight="#+id/spendMoney"
android:fontFamily="sans-serif"
android:text="150,000"
android:textSize="30sp"
tools:layout_editor_absoluteX="25dp"
tools:layout_editor_absoluteY="36dp" />
<Button
android:id="#+id/test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test"
tools:layout_editor_absoluteX="134dp"
tools:layout_editor_absoluteY="358dp"
android:layout_marginBottom="90dp"
android:layout_alignParentBottom="true"
android:layout_alignLeft="#+id/spendMoney"
android:layout_alignStart="#+id/spendMoney" />
This is the object I enter into the offline database, containing the id, the amount spent, and details of the payment:
public class Payment {
private int id;
private int amount;
private String details;
public Payment(){}
public Payment(int id, int amount, String details) {
this.id = id;
this.amount = amount;
this.details = details;
}
public Payment(int id, int amount) {
this.id = id;
this.amount = amount;
}
public Payment(int amount, String details) {
this.amount = amount;
this.details = details;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
public String getDetails() {
return details;
}
public void setDetails(String details) {
this.details = details;
} }
This is the offline database:
ublic class Paid_DB extends SQLiteOpenHelper {
// All Static variables
// Database Version
private static final int DATABASE_VERSION = 1;
// Database Name
private static final String DATABASE_NAME = "Payments_DB";
// Contacts table name
private static final String PAYMENT_TABLE = "PaymentTable";
// Contacts Table Columns names
private static final String PAY_ID = "id";
private static final String PAY_AMOUNT = "amount";
private static final String PAY_DETAILS = "details";
Paid_DB(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
String CREATE_CONTACTS_TABLE = "CREATE TABLE " + PAYMENT_TABLE + "("
+ PAY_ID + " INTEGER PRIMARY KEY," + PAY_AMOUNT + " INTEGER,"
+ PAY_DETAILS + " TEXT" + ")";
db.execSQL(CREATE_CONTACTS_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + PAYMENT_TABLE);
onCreate(db);
}
public void addPayment(Payment payment){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(PAY_AMOUNT, payment.getAmount());
values.put(PAY_DETAILS, payment.getDetails()); // Contact Phone Number
// Inserting Row
db.insert(PAYMENT_TABLE, null, values);
db.close();
}
void addListItem(ArrayList<String> listItem) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
for (int i = 0; i < listItem.size(); i++) {
Log.e("vlaue inserting==", "" + listItem.get(i));
values.put(PAY_AMOUNT, listItem.get(i));
db.insert(PAYMENT_TABLE, null, values);
}
db.close(); // Closing database connection
}
Cursor getListItem() {
String selectQuery = "SELECT * FROM " + PAYMENT_TABLE;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
return cursor;
}}
And finally, this is the details activity, it contains a list view that stores and displays all the payments that have been made:
public class DetailsActivity extends AppCompatActivity {
ArrayList<String> detailsListArrayList;
private ListView lv;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_details);
lv = (ListView) findViewById(R.id.listView);
detailsListArrayList = new ArrayList<>();
detailsListArrayList.add("Item1");
detailsListArrayList.add("Item2");
detailsListArrayList.add("Item3");
detailsListArrayList.add("Item4");
detailsListArrayList.add("Item5");
Paid_DB db = new Paid_DB(this);
db.addListItem(detailsListArrayList);
Cursor cursor = db.getListItem();
Log.e("count", " " + cursor.getCount());
if (cursor != null) {
cursor.moveToNext();
do {
Log.e("value==", "" + cursor.getString(1));
} while (cursor.moveToNext());
}
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(
this,
android.R.layout.simple_list_item_1,
detailsListArrayList );
lv.setAdapter(arrayAdapter);
}
}
XML file:
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.user.paid.DetailsActivity">
<ListView
android:id="#+id/listView"
android:layout_width="368dp"
android:layout_height="495dp"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="8dp" />
Every time I click on the "test" button, the app crashes. And every time I try to add a new entry using the "spend" button, the app also crashes. What did I do wrong?
What I can tell from here (without the error log) is:
1) your app crashes when pressing the test-button because you are starting an activity there without passing a contextobject. Try this:
public void onClick(View v) {
Intent i = new Intent(getApplicationContext(), DetailsActivity.class);
startActivity(i);
}
2) The spend button tries to add a new payment entry to your database. But in your database schema , you declare the PAY_ID as a primary key. Later in your addPayment() you are just passing the PAY_AMOUNT and PAY_DETAILS, so you are missing the PAY_ID which seems to lead to a crash.
EDIT: something like this should return all the payments as an ArrayList (may Contain bugs, just wrote it in this editor).
public ArrayList<Payment> getAllPayments() {
ArrayList<Payment> result = new ArrayList<>();
Cursor c = db.query("PAYMENTS",new String[]{"PAY_ID","PAY_AMOUNT","PAY_DETAIL"},null,null,null,null,null); ;
c.moveToFirst();
while(! c.isAfterLast())
{
int s1=c.getInt(0);
int s2=c.getInt(1);
String s3=c.getString(2);
results.add(new Payment(s1,s2,s3));
c.moveToNext();
}
return results;
}
To update your ListView, you should have a closer look a this link, that explains how to work with ListViews and a custom ListView adapter Custom Adapter for List View