I'm almost done making my app and I'm stuck trying to solve this last issue. I made an activity that displays data gotten from Firestore using FirestoreRecyclerAdapter and It works perfectly when running on my emulator. But after I generate a signed APK with minifyEnabled:true and Install it on my device, the RecyclerView just shows Blank. when I set minifyEnabled:false it works perfectly. Below are my codes
For TransactionRecycler class
public class TransactionRecycler {
private String payment_date;
private String status;
private String meternumber;
public String reference;
private String amount_formatted;
private Double PurchasedUnits;
private Double FreeUnits;
private Double Vat;
public String id;
private String payment_time;
// public String state;
private String token;
public String address;
private String account_name;
public TransactionRecycler(String payment_date, String status, String meternumber, String reference, String id, String amount_formatted, String payment_time, String token, Double PurchasedUnits,
Double FreeUnits, Double Vat, String account_name, String address){
this.payment_date = payment_date;
this.status = status;
this.meternumber = meternumber;
this.reference = reference;
this.amount_formatted = amount_formatted;
this.PurchasedUnits = PurchasedUnits;
this.Vat = Vat;
// this.state = state;
this.FreeUnits = FreeUnits;
this.id = id;
this.payment_time = payment_time;
this.token = token;
this.account_name = account_name;
this.address = address;
}
public TransactionRecycler(){};
public void setDate(String payment_date){this.payment_date = payment_date;}
public void setId(String id){this.id =id;}
// public void setState(String id){this.state =state;}
public String getPayment_date(){return payment_date;}
public String getStatus(){return status;}
public String getMeternumber(){return meternumber;}
public String getReference(){return reference;}
public String getAddress(){return address;}
public String getAmount_formatted(){return amount_formatted;}
public Double getPurchasedUnits(){return PurchasedUnits;}
public Double getFreeUnits(){return FreeUnits;}
public Double getVat(){return Vat;}
public String getId(){return id;}
// public String getstate(){return state;}
public String getPayment_time(){return payment_time;}
public String getToken(){return token;}
public String getAccount_name(){return account_name;}
}
And for TRansactionActivity
public class TransactionActivity extends AppCompatActivity {
private static final String TAG = "TransactionActivity";
private final static String strUrlId= "https://www.eliminateramp.com?exmen=";
private static final int SERVICE_CHARGE = 100;
private static final String PLEASE_CHECK_YOUR_METER_NUMBER_AND_TRY_AGAIN = "Please check your meter number and try again";
private static final String COULDN_T_CONNECT_AT_THIS_TIME_PLEASE_TRY_AGAIN = "Couldn't connect at this time, Please try again";
private static final String FAILLED = "failled";
private static final String NOT_FOUND = "NOT FOUND";
private FirebaseAuth mAuth;
private String userID;
private RecyclerView mTransactionList;
protected LinearLayoutManager linearLayoutManager;
public FirestoreRecyclerAdapter adapter;
private SlidingUpPanelLayout mLayout;
private NavigationView navigation;
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mToggle;
private static final String SPACE = " ";
private static String phone;
private Button charname;
private TextView emailview;
private TextView fullnameview;
private TextView priceidrc;
private static TextView post_meterno;
private static String aamount;
public boolean onCreateOptionsMenu(Menu menu){
getMenuInflater().inflate(R.menu.top_menu, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_transaction);
mTransactionList = findViewById(R.id.friend_listinc);
mLayout = findViewById(R.id.sliding_layout);
mAuth = FirebaseAuth.getInstance();
userID = mAuth.getCurrentUser().getUid();
Log.d("Error","The UID is: "+userID);
Toolbar mToolbar = findViewById(R.id.nav_actionbar);
setSupportActionBar(mToolbar);
mDrawerLayout = findViewById(R.id.drawerlayout);
navigation = findViewById(R.id.navigationview);
mToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.open, R.string.close);
View headerView = navigation.getHeaderView(0);
emailview = headerView.findViewById(R.id.emailviewraw);
fullnameview = headerView.findViewById(R.id.fullnameviewid);
charname = headerView.findViewById(R.id.charnameid);
mDrawerLayout.addDrawerListener(mToggle);
mToggle.syncState();
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
try{
getUserData();
}catch (Exception e){
Log.d(TAG, "Failed to get user Data at this time coz: "+e);
}
ImageView imgview = findViewById(R.id.closeid);
imgview.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mLayout.animate();
mLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
}
});
charname.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(TransactionActivity.this,UpdateActivity.class));
}
});
init();
inTrans();
initInstances();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return mToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
}
private void initInstances() {
// getSupportActionBar().setHomeButtonEnabled(true);
// getSupportActionBar().setDisplayHomeAsUpEnabled(true);
navigation = findViewById(R.id.navigationview);
navigation.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
int id = menuItem.getItemId();
switch (id) {
case R.id.nav_home:
//Do some thing here
// add navigation drawer item onclick method here
Intent intent2 = new Intent(TransactionActivity.this, HomePageActivity.class);
startActivity(intent2);
break;
case R.id.nav_estimate:
mDrawerLayout.closeDrawer(GravityCompat.START);
break;
//Do some thing here
// add navigation drawer item onclick method here
case R.id.nav_Settings:
//Do some thing here
// add navigation drawer item onclick method here
Intent intent3 = new Intent(TransactionActivity.this, HelpActivity.class);
startActivity(intent3);
break;
case R.id.nav_hc:
//Do some thing here
// add navigation drawer item onclick method here
Intent intent = new Intent(TransactionActivity.this, HelpCenterActivity.class);
startActivity(intent);
break;
}
return false;
}
});
}
private void init(){
linearLayoutManager = new LinearLayoutManager(getApplicationContext(), LinearLayoutManager.VERTICAL, false);
mTransactionList.setLayoutManager(linearLayoutManager);
}
private void inTrans(){
Query query = FirebaseFirestore.getInstance().collection("user-orders").document(userID).collection("successful-orders").orderBy("RequestedOn");
FirestoreRecyclerOptions<TransactionRecycler> response = new FirestoreRecyclerOptions.Builder<TransactionRecycler>()
.setQuery(query, TransactionRecycler.class)
.build();
adapter = new FirestoreRecyclerAdapter<TransactionRecycler, TransactionRecyclerHolder>(response){
#Override
public TransactionRecyclerHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.transaction_list, parent, false);
return new TransactionRecyclerHolder(view);
}
#Override
public void onError(#NonNull FirebaseFirestoreException e) {
Log.e("error", e.getMessage());
}
#Override
protected void onBindViewHolder(#NonNull TransactionRecyclerHolder holder, int position, #NonNull final TransactionRecycler model) {
//progressBar.setVisibility(View.GONE);
holder.setDate(model.getPayment_date());
holder.setStatus(model.getStatus());
holder.setReference(model.getId());
holder.setMeterno(model.getMeternumber());
holder.setPrice(model.getAmount_formatted());
mLayout.setFadeOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mLayout.animate();
mLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
}
});
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mLayout.setPanelHeight(4);
mLayout.animate();
// mLayout.setAnchorPoint(2.0f);
mLayout.setPanelState(SlidingUpPanelLayout.PanelState.EXPANDED);
priceidrc = findViewById(R.id.priceidsc);
TextView dateidrc = findViewById(R.id.dateidsc);
TextView referenceidrc = findViewById(R.id.refidsc);
TextView statusidrc = findViewById(R.id.statusidsc);
TextView meternoidrc = findViewById(R.id.meternoidsc);
TextView paymenttimeidrc = findViewById(R.id.paymenttimeidsc);
TextView tokenidrc = findViewById(R.id.tokenidsc);
TextView creditidrc = findViewById(R.id.creditidsc);
TextView freeunitsrc = findViewById(R.id.freeunitsidsc);
TextView vatrc = findViewById(R.id.vatidsc);
TextView accountnameidrc = findViewById(R.id.namesidsc);
TextView address = findViewById(R.id.addressidsc);
dateidrc.setText(model.getPayment_date());
statusidrc.setText(model.getStatus());
meternoidrc.setText(model.getMeternumber());
priceidrc.setText(model.getAmount_formatted());
referenceidrc.setText(model.getId());
paymenttimeidrc.setText(model.getPayment_time());
tokenidrc.setText(model.getToken());
creditidrc.setText(String.valueOf(model.getPurchasedUnits()));
freeunitsrc.setText(String.valueOf(model.getFreeUnits()));
vatrc.setText(String.valueOf(model.getVat()));
accountnameidrc.setText(model.getAccount_name());
address.setText(model.getAddress());
}
});
}
};
adapter.notifyDataSetChanged();
mTransactionList.setAdapter(adapter);
}
#Override
public void onStart() {
super.onStart();
adapter.startListening();
}
#Override
public void onStop() {
super.onStop();
adapter.stopListening();
}
public static class TransactionRecyclerHolder extends RecyclerView.ViewHolder {
View mView;
TransactionRecyclerHolder(View itemView) {
super(itemView);
mView = itemView;
}
public void setDate(String payment_date) {
TextView post_date = mView.findViewById(R.id.dateid);
post_date.setText(payment_date);
}
public void setStatus(String status) {
TextView post_status = mView.findViewById(R.id.statusid);
post_status.setText(status);
}
public void setMeterno(String meterno) {
post_meterno = mView.findViewById(R.id.meternoid);
post_meterno.setText(meterno);
}
public void setReference(String reference) {
TextView post_ref = mView.findViewById(R.id.refid);
post_ref.setText(reference);
}
public void setPrice(String price) {
TextView post_price = mView.findViewById(R.id.priceid);
post_price.setText(price);
aamount=price;
}
}
public void getUserData() {
mAuth= FirebaseAuth.getInstance();
try{
userID = mAuth.getCurrentUser().getUid();
}catch(Exception e){
Log.d(TAG, "Failled somehow");
}
Log.d(TAG, "ur uid => "+userID);
DocumentReference mDocRef = FirebaseFirestore.getInstance().collection("users").document(userID);
mDocRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if(task.isSuccessful()){
DocumentSnapshot doc = task.getResult();
String firstname = doc.get("firstName").toString();
String lastname = doc.get("lastName").toString();
phone = doc.get("phone").toString();
String fullname = firstname+SPACE+lastname;
fullnameview.setText(fullname);
try{
emailview.setText(mAuth.getCurrentUser().getEmail());
}catch(Exception e){
Log.d(TAG,"oops");
}
charname.setText(firstname.substring(0,1));
}
}
});
}
public void buyAgain(View view){
final Dialog dialog = new Dialog(TransactionActivity.this);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
dialog.setCanceledOnTouchOutside(false);
dialog.setContentView(R.layout.progressbar);
String price = aamount.replaceAll("\\D","");
final int amount = Integer.parseInt(price) + SERVICE_CHARGE;
final String mn = post_meterno.getText().toString();
final String ml = "amstadam";
final String ref = String.valueOf(Calendar.getInstance().getTimeInMillis());
#SuppressLint("StaticFieldLeak") AsyncTask<String, String, String> jesgetnames = new AsyncTask<String, String, String>() {
#Override
protected String doInBackground(String... params) {
String geMtName;
String urlMtName = strUrlId+post_meterno.getText().toString().trim();
Log.d(TAG, "The string:" + urlMtName);
try {
URL url = new URL(urlMtName);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.connect();
BufferedReader bf = new BufferedReader(new InputStreamReader(con.getInputStream()));
String value = bf.readLine();
Log.d(TAG, "Value of value is: " + value);
if(value.equals("not found")){
geMtName = "NOT FOUND";
}else{
JSONObject parentJson = new JSONObject(value);
String meternumber = parentJson.getString("xmen");
String metername = parentJson.getString("x_name");
String address = parentJson.getString("address");
geMtName = metername+"/"+meternumber+"/"+address;
}
Log.d(TAG, "meter name after get is: " + geMtName);
} catch (Exception e) {
// Log.d(TAG, "Faiiled coz: "+ e);
geMtName = "failled";
e.printStackTrace();
}
Log.d(TAG, "I dont know if this works " + geMtName);
return geMtName;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Log.d(TAG, "pnPostExecute value: " + s);
String nameSubString;
String numberSubString;
String addressSubString;
// date and time creation
String stringDate = String.valueOf(DateFormat.getDateTimeInstance());
Date stringTime = Calendar.getInstance().getTime();
SimpleDateFormat curFormater = new SimpleDateFormat("dd/MM/yyyy", Locale.ENGLISH);
SimpleDateFormat timeFormat = new SimpleDateFormat("h:mm a", Locale.ENGLISH);
Date dateObj = new Date();
Date timeObj = new Date();
try {
dateObj = curFormater.parse(stringDate);
timeObj = timeFormat.parse(String.valueOf(stringTime));
} catch (ParseException e) {
e.printStackTrace();
}
SimpleDateFormat postFormater = new SimpleDateFormat("d MMMM yyyy", Locale.ENGLISH);
SimpleDateFormat postTimeFormater = new SimpleDateFormat("h:mm a", Locale.ENGLISH);
String newDateStr = postFormater.format(dateObj);
String newtimeStr = postTimeFormater.format(timeObj);
switch (s) {
case FAILLED:
nameSubString = FAILLED;
numberSubString = FAILLED;
addressSubString = FAILLED;
break;
case NOT_FOUND:
nameSubString = FAILLED;
numberSubString = FAILLED;
addressSubString = FAILLED;
break;
default:
String[] split = s.split("/");
nameSubString = split[0];
numberSubString = split[1];
addressSubString = split[2];
break;
}
switch (s) {
//TODO: Change toast message to reflect Json in future
case FAILLED:
//TODO: after creating layout, go back to previous layout and display toast message
Toast.makeText(TransactionActivity.this, COULDN_T_CONNECT_AT_THIS_TIME_PLEASE_TRY_AGAIN, Toast.LENGTH_SHORT).show();
dialog.dismiss();
break;
case NOT_FOUND:
Toast.makeText(TransactionActivity.this, PLEASE_CHECK_YOUR_METER_NUMBER_AND_TRY_AGAIN, Toast.LENGTH_SHORT).show();
dialog.dismiss();
break;
default:
Intent meterIntent = new Intent(TransactionActivity.this, MeterNumActivity.class);
meterIntent.putExtra("meternum", mn);
meterIntent.putExtra("meterprice", amount);
meterIntent.putExtra("meterlocation", ml);
meterIntent.putExtra("reference", ref);
meterIntent.putExtra("meteracctname", nameSubString);
meterIntent.putExtra("meteracctnumber", numberSubString);
meterIntent.putExtra("meteracctaddress", addressSubString);
meterIntent.putExtra("uuid", userID);
meterIntent.putExtra("date_created", newDateStr);
meterIntent.putExtra("time_created", newtimeStr);
meterIntent.putExtra("phone", phone);
meterIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(meterIntent);
break;
}
}
};
dialog.show();
jesgetnames.execute();
}
#Override
public void onBackPressed() {
Intent i= new Intent(this,HomePageActivity.class);
startActivity(i);
finish();
}
}
and my Gradle is
android {
compileSdkVersion 26
defaultConfig {
applicationId "com.example.menofx.xmen"
minSdkVersion 21
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support:cardview-v7:26.1.0'
implementation 'com.firebaseui:firebase-ui-firestore:3.1.3'
implementation 'com.firebaseui:firebase-ui-auth:3.1.3'
implementation 'com.firebaseui:firebase-ui-database:3.1.3'
implementation "com.google.firebase:firebase-firestore:11.8.0"
implementation "com.android.support:recyclerview-v7:26.1.0"
implementation "com.google.android.gms:play-services-auth:11.8.0"
implementation 'co.paystack.android:paystack:3.0.9'
implementation 'br.com.simplepass:loading-button-android:1.8.4'
implementation 'com.github.faruktoptas:FancyShowCaseView:1.0.0'
implementation 'com.sothree.slidinguppanel:library:3.4.0'
implementation 'com.android.support:design:26.1.0'
implementation 'com.android.support:support-v4:26.1.0'
implementation 'com.android.support:support-vector-drawable:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:0.5'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:2.2.2'
implementation project(':library')
}
apply plugin: 'com.google.gms.google-services'
my proguard rules are empty if needed. This is my first time working with firebase UI so I dont even know how to diagnose the problem. Thanks for the help.
You need to put your POJOs (model classes) in a single package and add that package to your proguard rules, or you can add all of the packages where those classes are (I just personally use a single package for them). Firebase uses reflection in serialization and deserialization process so it can't use obfuscated class names. Once you've put all of them in one package add this rule to your proguard file to prevent obfuscation:
-keep class package.to.pojos.** { *; }
If you wish to keep them where they are just add a rule for each model class with the -keep class keywords followed by the complete path (packagewise) of the class.
Reason of your problem
When you set minifyEnabled to true, R8 compiler optimizes your code by removing unnecessary parameters, methods and other parts of your code, which R8 think is not usable and, also, shrinks the class name and other parameter's name to reduce app size. But sometimes R8 can not determine correctly, which code is useful and which code is not. That is why R8 removes useful code too. Maybe, in your case, R8 changed the keys of your data. You can find it by pushing different data from your signed app. For example, some input data from the user while setting up a user profile. Now go back to your firebase firestore console and check the keys the data you just pushed. You will find that the keys are different now. Similarly, as R8 has changed the calling keys when you try to fetch the data, you are unable to find that key-pair values. That is why, your recycler view is empty.
Solution
1. Add the following library to your module's build.gradle file.
implementation 'androidx.annotation:annotation:1.1.0'
Now add #keep annotation at all the concerned classes. If not the whole class, then only the methods concerned with pushing or pulling the data.
Regards,
Ramesh
Related
I have a MainAtivity which has some EditText and 2 button. Save button will save user input to ListView and List button to show ListView (which I display in second activity).
Is there anyway to collect data from multiple inputs then pass it to other activity. And after get that data how to combine it to a List item.
Please show me some code and explain cause I'm a beginner.
I have read some post and they suggest use startActivityForResult, intent, bundles but I still don't understand.
This is my Main class:
public class MainActivity extends AppCompatActivity {
String str, gender, vaccine, date;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button okay = (Button) findViewById(R.id.btnOk);
Button list = (Button) findViewById(R.id.btnList);
EditText name = (EditText) findViewById(R.id.inputName);
EditText address = (EditText) findViewById(R.id.inputAdd);
EditText phone = (EditText) findViewById(R.id.inputPhone);
RadioGroup radioGroup = (RadioGroup) findViewById(R.id.radioGroup);
RadioButton female = (RadioButton) findViewById(R.id.inputFemale);
RadioButton male = (RadioButton) findViewById(R.id.inputMale);
CheckBox first = (CheckBox)findViewById(R.id.inputFirst);
CheckBox second = (CheckBox)findViewById(R.id.inputSecond);
CheckBox third = (CheckBox)findViewById(R.id.inputThird);
EditText datefirst = (EditText) findViewById(R.id.dateFirst);
EditText datesecond = (EditText) findViewById(R.id.dateSecond);
EditText datethird = (EditText) findViewById(R.id.dateThird);
TextView result = (TextView)findViewById(R.id.textResult);
okay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(female.isChecked()) gender = female.getText().toString();
if(male.isChecked()) gender = male.getText().toString();
if(first.isChecked()) {
vaccine = first.getText().toString();
date = datefirst.getText().toString();
}
if(second.isChecked()) {
vaccine = second.getText().toString();
date = datesecond.getText().toString();
}
if(third.isChecked()) {
vaccine = third.getText().toString();
date = datethird.getText().toString();
}
str = name.getText().toString() + "\n" + address.getText().toString() + "\n" + phone.getText().toString() + "\n" +
gender + "\n" + vaccine + "\n" + date;
result.setText(str);
Toast.makeText(getApplicationContext(),result.getText().toString(),Toast.LENGTH_SHORT).show();
Intent intent = new Intent(MainActivity.this, PersonView.class);
intent.putExtra("NAME",name.getText().toString());
startActivity(intent);
}
});
list.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, PersonView.class);
startActivity(intent);
}
});
}
}
This is my ListView class:
public class PersonView extends AppCompatActivity {
ArrayList<Person> listPerson;
PersonListViewAdapter personListViewAdapter;
ListView listViewPerson;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
Intent intent = getIntent();
String message = intent.getStringExtra("NAME");
Button back = (Button) findViewById(R.id.btnBack);
back.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(PersonView.this, MainActivity.class);
//startActivityForResult(intent,2);
}
});
listPerson = new ArrayList<>();
listPerson.add(new Person("Lieu Mai","25 Mac Dinh Chi", "0786867073", "female","3 injection", "24/07/2000"));
personListViewAdapter = new PersonListViewAdapter(listPerson);
listViewPerson = findViewById(R.id.listPerson);
listViewPerson.setAdapter(personListViewAdapter);
}
class Person {
String name, address, phone, gender, vaccine, date;
public Person( String name, String address, String phone, String gender, String vaccine, String date) {
this.name = name;
this.address = address;
this.phone = phone;
this.gender = gender;
this.vaccine = vaccine;
this.date = date;
}
}
class PersonListViewAdapter extends BaseAdapter {
final ArrayList<Person> listPerson;
PersonListViewAdapter(ArrayList<Person> listPerson) {
this.listPerson = listPerson;
}
#Override
public int getCount() {
return listPerson.size();
}
#Override
public Object getItem(int position) {
return listPerson.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View viewPerson;
if (convertView == null) {
viewPerson = View.inflate(parent.getContext(), R.layout.person_view, null);
} else viewPerson = convertView;
Person person = (Person) getItem(position);
((TextView) viewPerson.findViewById(R.id.txtName)).setText(String.format("Name: %s", person.name));
((TextView) viewPerson.findViewById(R.id.txtAddress)).setText(String.format("Address : %s", person.address));
((TextView) viewPerson.findViewById(R.id.txtPhone)).setText(String.format("Phone number: %s", person.phone));
((TextView) viewPerson.findViewById(R.id.txtGender)).setText(String.format("Gender: %s", person.gender));
((TextView) viewPerson.findViewById(R.id.txtVaccine)).setText(String.format("Vaccine: %s", person.vaccine));
((TextView) viewPerson.findViewById(R.id.txtDate)).setText(String.format("Date: %s", person.date));
return viewPerson;
}
}
}
You should look into the Singleton pattern. It is very simple as there is no external DB. What it essentially is a class that manages the data and lets other classes and activities use the data while not allowing duplication.
You have a model Person
public class Person {
private String name;
public String address;
...
constructors and getters and setters
Create a class PersonsSingelton something like this.
public class PersonManagerSingleton {
private PersonManagerSingleton() {
loadPersonsDataSet();
}
private static PersonManagerSingleton instance = null;
public static PersonManagerSingleton getInstance() {
// if there is a instance already created use that instance of create new instance
// instance created in MainActivity and you try to create a new instance in Details
// should not happen as that will cause data duplication.
if (instance == null) {
instance = new PersonManagerSingleton();
}
return instance;
}
private ArrayList<Person> personList = new ArrayList<Person>();
private void loadPersonsDataSet() {
this.personList.add(new Person(...));
this.personList.add(new Person(...));
this.personList.add(new Person(...));
this.personList.add(new Person(...));
}
public ArrayList<Person> getpersonList() {
return personList;
}
public Person getPersonByID(int PersonNumber) {
for (int i = 0; i < this.personList.size(); i++) {
Person curPerson = this.personList.get(i);
if (curPerson.getNumber() == PersonNumber) {
return curPerson;
}
}
return null;
}
// methods for adding a new person used in Activity with the form.
// other methods ...
}
This would be like a state in React. of the State Manager.
Your person adapter constructor has to accept an ArrayList<Person> listPerson. So modify the activity passing the data to pass only the position of the ListView clicked. You need to modify your Adapter for that.
Use the Singleton created to access the data.
PersonManagerSingleton personSingelton = PersonManagerSingleton.getInstance();
ArrayList<Person> listPerson = personSingelton.getPersonList();
PersonAdapter Person = new PersonAdapter(listPerson);
So now only things left is to modify the Persons adapter to pass position using Intent and nothing else. and then you can use the instance of Singleton in other files to access the data using the listPerson.get(position) and using getters and setters.
Link to a project like this.
https://github.com/smitgabani/anroid_apps_using_java/tree/main/pokemon_app
I tried to make a covid-19 tracking app by watching Youtube tutorials.
My app shows the country list with flags and when you click on any country it opens an activity and shows the details of that country i.e total cases, deaths, recovered, etc. The video on Youtube uses ListView and I am using recyclerView
I fetched the country list successfully and set onClickListener on the view and it opens second activity which shows the case in detail. But I don't know how to show the data.
my adapter class:
class Countries_adapter extends RecyclerView.Adapter<Countries_adapter.MyViewHolder> {
Context ct;
List<Countries_data> list;
public Countries_adapter(Context context,List<Countries_data> country)
{
ct=context;
list=country;
}
#Override
public MyViewHolder onCreateViewHolder( ViewGroup parent, int viewType) {
View v = LayoutInflater.from(ct).inflate(R.layout.countries_row,parent,false);
return new MyViewHolder(v);
}
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
holder.tvCountryName.setText(list.get(position).getCountry());
holder.tvtotal.setText(list.get(position).getActive());
Glide.with(ct).load(list.get(position).getFlag()).into(holder.imageView);
holder.linearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i = new Intent(ct,CountriesDetails.class);
i.putExtra("Country",list.get(position).getCountry());
ct.startActivity(i);
}
});
}
#Override
public int getItemCount() {
return list.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView tvCountryName,tvtotal;
ImageView imageView;
LinearLayout linearLayout;
public MyViewHolder( View itemView) {
super(itemView);
tvCountryName = itemView.findViewById(R.id.tvCountryName);
tvtotal=itemView.findViewById(R.id.tvCountrytotalcaese);
imageView = itemView.findViewById(R.id.imageFlag);
linearLayout=itemView.findViewById(R.id.linear_layout);
}
}
my AffectedCoutries class activity is as follows:
public class AffectedCountries extends AppCompatActivity {
EditText edtSearch;
RecyclerView recyclerView;
SimpleArcLoader simpleArcLoader;
public static ArrayList countryList = new ArrayList<>();
Countries_data countryData;
Countries_adapter CountriesAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_affected_countries);
edtSearch = findViewById(R.id.edtSearch);
recyclerView=findViewById(R.id.recyclerAffectedCountries);
simpleArcLoader = findViewById(R.id.loader);
fetchData();
}
private void fetchData() {
String url = "https://corona.lmao.ninja/v2/countries/";
simpleArcLoader.start();
StringRequest request = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONArray jsonArray = new JSONArray(response);
for(int i=0;i<jsonArray.length();i++){
JSONObject jsonObject = jsonArray.getJSONObject(i);
String countryName = jsonObject.getString("country");
String cases = jsonObject.getString("cases");
String todayCases = jsonObject.getString("todayCases");
String deaths = jsonObject.getString("deaths");
String todayDeaths = jsonObject.getString("todayDeaths");
String recovered = jsonObject.getString("recovered");
String active = jsonObject.getString("active");
String critical = jsonObject.getString("critical");
JSONObject object = jsonObject.getJSONObject("countryInfo");
String flagUrl = object.getString("flag");
countryData = new Countries_data(flagUrl,countryName,cases,todayCases,deaths,todayDeaths,recovered,active,critical);
countryList.add(countryData);
}
CountriesAdapter = new Countries_adapter(AffectedCountries.this,countryList);
recyclerView.setLayoutManager(new LinearLayoutManager(AffectedCountries.this));
recyclerView.setAdapter(CountriesAdapter);
simpleArcLoader.stop();
simpleArcLoader.setVisibility(View.GONE);
} catch (JSONException e) {
e.printStackTrace();
simpleArcLoader.start();
simpleArcLoader.setVisibility(View.GONE);
Toast.makeText(AffectedCountries.this,"catch response", Toast.LENGTH_SHORT).show();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
simpleArcLoader.stop();
simpleArcLoader.setVisibility(View.GONE);
Toast.makeText(AffectedCountries.this,"error response", Toast.LENGTH_SHORT).show();
}
});
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(request);
}
}
my Countries_data class(model class)
public class Countries_data {
public String country;
public String cases;
public String todayCases;
public String deaths;
public String todayDeaths;
public String recovered;
public String active;
public String critical;
public String flag;
public Countries_data(String flag, String country, String cases, String
todayCases, String deaths, String todayDeaths, String recovered,
String active, String critical) {
this.country = country;
this.cases = cases;
this.todayCases = todayCases;
this.deaths = deaths;
this.todayDeaths = todayDeaths;
this.recovered = recovered;
this.active = active;
this.critical = critical;
this.flag = flag;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getCases() {
return cases;
}
public void setCases(String cases) {
this.cases = cases;
}
public String getTodayCases() {
return todayCases;
}
public void setTodayCases(String todayCases) {
this.todayCases = todayCases;
}
public String getDeaths() {
return deaths;
}
public void setDeaths(String deaths) {
this.deaths = deaths;
}
public String getTodayDeaths() {
return todayDeaths;
}
public void setTodayDeaths(String todayDeaths) {
this.todayDeaths = todayDeaths;
}
public String getRecovered() {
return recovered;
}
public void setRecovered(String recovered) {
this.recovered = recovered;
}
public String getActive() {
return active;
}
public void setActive(String active) {
this.active = active;
}
public String getCritical() {
return critical;
}
public void setCritical(String critical) {
this.critical = critical;
}
public String getFlag() {
return flag;
}
public void setFlag(String flag) {
this.flag = flag;
}
}
my Country_details class
public class CountriesDetails extends AppCompatActivity {
TextView tvCountry, tvCases, tvRecovered,tvdeaths;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_countries_details2);
tvCountry = findViewById(R.id.tvCountry);
tvCases = findViewById(R.id.tvCases);
tvRecovered = findViewById(R.id.tvRecovered);
tvdeaths=findViewById(R.id.tvTotalDeaths);
String positionCountry = getIntent().getStringExtra("Country");
Log.i("country name", positionCountry);
}
}
How to set the data in tvcases?
How can I show the data? Do I have to create a separate recycler view and then fetch the data from the API or can I use my main activity to show the data?
I have some sad information for you: Google Play policy restricts such apps from being published in store... especially when you are showing deaths count. Been there, done that, my app was blocked...
besides above:
you are passing country name in intent:
i.putExtra("Country",list.get(position).getCountry());
but trying to read "position" in details Activity - it will be always 0 (default)
edit due to comments:
pass position of clicked View
holder.linearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i = new Intent(ct,CountriesDetails.class);
i.putExtra("position", position);
ct.startActivity(i);
}
});
in CountriesDetailss onCreate method receive this position and restore proper Countries_data object from your static countryList array in AffectedCountries
int position = getIntent().getIntExtra("position", 0);
Countries_data country = AffectedCountries.countryList.get(position);
tvCountry.setText(country.getCountry());
that should work, but this isn't best way to store data, in fact its very weak... after downloading data (list of countries) you should store it somehow, e.g. SQLite/Room lib or at least SharedPreferences... then in details activity you should restore int position and using it take proper object from database or preferences, instead of stright from static array
it may be also useful to implement Parcelable inteface to your Countries_data - this will allow to put whole Countries_data object into Intents extras, not only primitive int with position in array. in this case details activity won't even need access to whole array or sql database/preferences, it will get whole object straight from Intents extras
I am developing an android app which shows a list of countries affected by Coronavirus , the total number of confirmed cases and total Deaths. I am using a JSON API to get the data and displaying it using a RecyclerView . The app works fine , and i get a list of all the countries with their respective case counts. I want to add a search option so that the users can filter the list and find a specific country. How do i do that? I am new to programming , if someone could help with this that would be awesome.
Here is the code snippet
MainActivity.java
private RecyclerView mRecyclerView;
private Corona_Stats_Adapter mCorona_Stats_Adapter;
private TextView mErrorDisplay;
private ProgressBar mProgressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.corona_stats);
mRecyclerView = (RecyclerView)findViewById(R.id.Corona_stats_recycler);
mErrorDisplay = (TextView) findViewById(R.id.tv_error_message_display);
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setHasFixedSize(true);
mCorona_Stats_Adapter = new Corona_Stats_Adapter();
mRecyclerView.setAdapter(mCorona_Stats_Adapter);
mProgressBar = (ProgressBar)findViewById(R.id.pb_loading_indicator) ;
loadCoronaData();
}
private void loadCoronaData(){
showCoronaDataView();
//String Country = String.valueOf(mSearchQuery.getText());
new Fetch_data().execute();
}
private void showCoronaDataView(){
mErrorDisplay.setVisibility(View.INVISIBLE);
mRecyclerView.setVisibility(View.VISIBLE);
}
private void showErrorMessage(){
mRecyclerView.setVisibility(View.INVISIBLE);
mErrorDisplay.setVisibility(View.VISIBLE);
}
public class Fetch_data extends AsyncTask<Void,Void,String[]> {
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressBar.setVisibility(View.VISIBLE);
}
#Override
protected String[] doInBackground(Void... voids) {
URL covidRequestURL = NetworkUtils.buildUrl();
try {
String JSONCovidResponse = NetworkUtils.getResponseFromHttpUrl(covidRequestURL);
String[] simpleJsonCovidData = CovidJSON_Utils.getSimpleStringFromJson(MainActivity.this, JSONCovidResponse);
return simpleJsonCovidData;
} catch (IOException | JSONException e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(String[] coronaData) {
mProgressBar.setVisibility(View.INVISIBLE);
if(coronaData !=null){
showCoronaDataView();
mCorona_Stats_Adapter.setCoronaData(coronaData);
} else{
showErrorMessage();
}
}
}
}
RecyclerView Adapter class Corona_stats_Adapter.java
public class Corona_Stats_Adapter extends RecyclerView.Adapter<Corona_Stats_Adapter.Corona_Stats_AdapterViewHolder>
{
private Context context;
// private List<Country> countryList;
// private List<Country> countryListFiltered;
private String[] mCoronaData;
public Corona_Stats_Adapter(){
}
#NonNull
#Override
public Corona_Stats_AdapterViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int viewType) {
Context context = viewGroup.getContext();
int LayoutIdForListItem =R.layout.corona_stats_list_item;
LayoutInflater inflater =LayoutInflater.from(context);
boolean ShouldAttachToParentImmediately = false;
View view = inflater.inflate(LayoutIdForListItem,viewGroup,ShouldAttachToParentImmediately);
return new Corona_Stats_AdapterViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull Corona_Stats_AdapterViewHolder corona_stats_adapterViewHolder, int position) {
String coronaStats = mCoronaData[position];
corona_stats_adapterViewHolder.mCoronaTextView.setText(coronaStats);
}
#Override
public int getItemCount() {
if(null == mCoronaData) return 0;
return mCoronaData.length;
// return countryListFiltered.size();
}
public class Corona_Stats_AdapterViewHolder extends RecyclerView.ViewHolder {
public final TextView mCoronaTextView;
public Corona_Stats_AdapterViewHolder(#NonNull View view) {
super(view);
mCoronaTextView = (TextView) view.findViewById(R.id.tv_corona_data);
}
}
public void setCoronaData(String[] coronaData){
mCoronaData = coronaData;
notifyDataSetChanged();
}
}
Parsing the JSON data in CovidJSON_Utils.java
public final class CovidJSON_Utils {
public static String[] getSimpleStringFromJson(Context context, String codivJsonString)
throws JSONException {
final String COV_COUNTRY = "Countries";
final String COV_CONFIRMED = "confirmed";
final String COV_DEATHS = "deaths";
final String COV_MESSAGE_CODE = "code";
String[] parsedCovidData = null;
JSONObject covidJsonObject = new JSONObject(codivJsonString);
if (covidJsonObject.has(COV_MESSAGE_CODE)) {
int errorCode = covidJsonObject.getInt(COV_MESSAGE_CODE);
switch (errorCode) {
case HttpURLConnection.HTTP_OK:
break;
case HttpURLConnection.HTTP_NOT_FOUND:
return null;
default:
return null;
}
}
JSONArray countryCovidArray = covidJsonObject.getJSONArray(COV_COUNTRY);
parsedCovidData = new String[countryCovidArray.length()];
for (int i = 0; i < countryCovidArray.length(); i++) {
JSONObject countryJSONObject = countryCovidArray.getJSONObject(i);
String Country = countryJSONObject.getString("Country");
String Confirmed = String.valueOf(countryJSONObject.getInt("TotalConfirmed"));
String Deaths = String.valueOf(countryJSONObject.getInt("TotalDeaths"));
parsedCovidData[i] = Country + "- Cases " + Confirmed + "- Deaths " + Deaths;
}
return parsedCovidData;
}
}
The problem is with below initialization in the MainActivity.Oncreate method
mCorona_Stats_Adapter = new Corona_Stats_Adapter(this,countries);
Initialize the adapter in onPostExecute method with updated countries data.
Hope this will help you.
You have to set arraylist to update country data in adapter after getting data from the server.
Public void setCoronaData (Arraylist coronaData) {
countryList = coronaData;
notifyDataSetChanged ();
}
I am not sure why, I have explored both .setValue() and .updateChildren() methods, but for whatever reason when I read data from firebase it is returning null. Here is how I write to Firebase:
Model Poll Class:
#IgnoreExtraProperties
public class Poll {
private String question;
private String image_URL;
public Poll() {
}
public Poll(String Question, String Image_URL) {
this.question = Question;
this.image_URL = Image_URL;
}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public String getImage_URL() {
return image_URL;
}
public void setImage_URL(String image_URL) {
this.image_URL = image_URL;
}
#Exclude
public Map<String, Object> toMap(){
HashMap<String, Object> result = new HashMap<>();
result.put("question", question);
result.put("image_URL", image_URL);
return result;
}
}
*I am following the documentation here with my .toMap() method and use of .updateChildren()
Here is where I create my Firebase references and write to the database:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create);
mStorage = FirebaseStorage.getInstance();
mStorageRef = mStorage.getReferenceFromUrl("gs://firebase-fan-polls.appspot.com");
mBaseRef = FirebaseDatabase.getInstance().getReference();
mPollsRef = mBaseRef.child("Polls");
mAddImageButton = (FloatingActionButton) findViewById(R.id.add_image_button);
mAddAnswersButton = (ImageView) findViewById(R.id.add_answers_button);
mImagePreview = (ImageView) findViewById(R.id.preview_image);
mCreatePollQuestion = (EditText) findViewById(R.id.create_poll_question_editText);
mCreatePollAnswerCounter = (TextView) findViewById(R.id.create_poll_answer_counter_TextView);
mEditTextAnswerLayout = (ViewGroup) findViewById(R.id.create_poll_questions_answer_layout);
mSubmitPollCreation = (FloatingActionButton) findViewById(R.id.submit_poll_FAB);
mNumberOfPollAnswersCreatedByUser = 2;
mAnswerChoices = new ArrayList<>();
mCreatePollAnswerCounter.setText(String.valueOf(mNumberOfPollAnswersCreatedByUser));
for (int i = 0; i < mNumberOfPollAnswersCreatedByUser; i++) {
createAnswerChoice(i + 1);
}
mAddAnswersButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mNumberOfPollAnswersCreatedByUser++;
if (mNumberOfPollAnswersCreatedByUser > 5) {
Toast.makeText(getApplicationContext(), R.string.max_create_answers, Toast.LENGTH_SHORT).show();
return;
}
createAnswerChoice(mNumberOfPollAnswersCreatedByUser);
mCreatePollAnswerCounter.setText(String.valueOf(mNumberOfPollAnswersCreatedByUser));
}
});
mSubmitPollCreation.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//TODO: Need to check if poll requirements are added, i.e. Question, Answer, ......
//check if image has been loaded first
if (resultImageURL == null) {
Toast.makeText(getApplicationContext(), getResources().getString(R.string.no_image_selected), Toast.LENGTH_LONG).show();
return;
}
Poll poll = new Poll(mCreatePollQuestion.getText().toString(), resultImageURL);
Map <String, Object> pollMap = poll.toMap();
String key = mBaseRef.child("Polls").push().getKey();
Map<String, Object> childUpdates = new HashMap<String, Object>();
childUpdates.put("/Polls/" + key, pollMap);
mBaseRef.updateChildren(childUpdates);
if (mNumberOfPollAnswersCreatedByUser > 5) {
Toast.makeText(getApplicationContext(), getResources().getText(R.string.poll_answers_greater_than_five), Toast.LENGTH_LONG).show();
mNumberOfPollAnswersCreatedByUser = 5;
}
Intent toHomeActivity = new Intent(CreateActivity.this, HomeActivity.class);
toHomeActivity.putExtra("viewpager_position", 2);
startActivity(toHomeActivity);
}
});
Everything is writing to Firebase correctly, as I can see it in the database in my console. I try and read it from this activity:
public class PollFragment extends Fragment {
#Bind(R.id.comment_label_counter)
TextView mCommentCounter;
#Bind(R.id.comments_label_icon)
ImageView mCommentsLabelIcon;
private DatabaseReference mBaseRef;
private DatabaseReference mPollsRef;
private DatabaseReference mSelectedPollRef;
private RadioGroup mPollQuestionRadioGroup;
private RadioGroup.LayoutParams mParams;
//static
private TextView mCommentsLabel;
private TextView mTotalVoteCounter;
private TextView mSelectedVote;
private TextView mYourVotelabel;
private ViewPager mViewPager;
private int mPagerCurrentPosition;
private static final String VOTE_COUNT_LABEL = "Vote_Count";
private static final String QUESTION_LABEL = "question";
private static final String ANSWERS_LABEL = "Answers";
private static final String POLL_LABEL = "Poll";
private static final String IMAGE_URL = "image_URL";
//all date items; dynamic
private DateFormat mDateFormat;
private Date mDate;
private String mCurrentDateString;
private TextView mPollQuestion;
private ArrayList<RadioButton> mPollAnswerArrayList;
private HorizontalBarChart mPollResults;
ArrayList<BarEntry> pollResultChartValues;
private BarDataSet data;
private ArrayList<IBarDataSet> dataSets;
private ValueEventListener valueEventListener;
private String pollID;
private int mPollIndex;
private ProgressBar mProgressBar;
private OnFragmentInteractionListener mListener;
public PollFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #return A new instance of fragment PollFragment.
*/
// TODO: Rename and change types and number of parameters
// TODO: Decide where to add comments button;
public static PollFragment newInstance(String pollIndex) {
PollFragment fragment = new PollFragment();
Bundle args = new Bundle();
args.putString("POLL_ID", pollIndex);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//TODO: check navigation to see if there are different ID's being generated from trending, following, and new fragments
Bundle args = getArguments();
String pollID = args.getString("POLL_ID");
Log.v("TAG", "THE PASSED ID Is " + pollID);
mBaseRef = FirebaseDatabase.getInstance().getReference();
mPollsRef = mBaseRef.child(POLL_LABEL);
mSelectedPollRef = mPollsRef.child(pollID);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO: Add Fragment Code to check if savedInstanceState == null; add at Activity Level?
// Inflate the layout for this fragment
final ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_poll, container, false);
ButterKnife.bind(this, rootView);
getActivity().setTitle(R.string.todays_polls_title);
//Initialize Poll Results Bar Chart and set to Invisible
mPollResults = (HorizontalBarChart) rootView.findViewById(R.id.poll_results_chart);
mPollResults.setBackgroundColor(getResources().getColor(R.color.white));
mPollResults.setNoDataTextDescription(getResources().getString(R.string.no_results_description));
mPollResults.setVisibility(View.INVISIBLE);
mTotalVoteCounter = (TextView) rootView.findViewById(R.id.total_vote_counter);
mCommentCounter = (TextView) rootView.findViewById(R.id.comment_label_counter);
mCommentCounter = (TextView) rootView.findViewById(R.id.comment_label_counter);
mProgressBar = (ProgressBar) rootView.findViewById(R.id.progress_bar_white);
mPollQuestion = (TextView) rootView.findViewById(R.id.poll_question);
mPollQuestion.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimension(R.dimen.poll_question_text_size));
mPollQuestionRadioGroup = (RadioGroup) rootView.findViewById(R.id.poll_question_group);
mSelectedPollRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.v("TAG", dataSnapshot.getKey());
//add question
String pollQuestion = (String) dataSnapshot.child(QUESTION_LABEL).getValue();
Log.v("TAG", "THE POLL QUESTION IS " + pollQuestion);
mPollQuestion.setText(pollQuestion);
mPollQuestion.setTypeface(null, Typeface.BOLD);
//add image
String pollImageURL = (String) dataSnapshot.child(IMAGE_URL).getValue();
Log.v("TAG", "THE POLL IMAGE URL IS" + pollImageURL);
Picasso.with(getActivity())
.load(pollImageURL)
.fit()
.placeholder(R.drawable.loading_spinner_white)
.into((ImageView) rootView.findViewById(R.id.poll_image));
Finally, here is my Firebase Database:
Careless mistake:
private static final String POLL_LABEL = "Poll";
Should be:
private static final String POLL_LABEL = "Polls";
The first choice was not the correct Firebase referencing thus causing the error.
Im new to Android Developement and currently working on an app that should give me the time between first time clicking a button and second time clicking the button and add it to a currently selected customer.
Current Status of App:
I established a connection to da mySql Database using Volley and a local webservice.
It works to insert my customers and time stamps to the table, but when loading times for a specific customer i get a strange result in one case. I tried debugging it but the app keeps crashing on debugging without a message. When not debugging it doesnt crash but shows weird data.
To the problem:
In my main activity called "ZeitErfassen" i have a button to get an overview of all customers display in a ListView.
I create the Listview with a custom ArrayAdapter because i want to pass my objects to the next Activity where my customers are displayed.
So onCreate of the overview of customers i create a new arraylist and fill it with all customers from my database. this list i pass to my customadapter and then set it as my adapter of the Listview.
Now, when i click on an item, i call a php script and pass the customer_id to the query to fetch all times from database where customer_id = customer_id.
Now the part where i get "strange" data...
1.(Source:ZeitErfassen;Destination:AddCustomer) I create a new customer,example xyz, in the app, data gets passed to the database.
2.(Source:ZeitErfassen;Destination:DisplayCustomer) I call my overview for all customers where the ListView is filled with data as described above. At the end ob the List I see the customer i just created,xyz.
3.Go back to Main Activity(ZeitErfassen)
4.(Source:ZeitErfassen;Destination:DisplayCustomer)I open the overview for all customers again, and it shows my last created user two times! so last entry, xyz, entry before last, xyz!
After that, i can open the view as many times as i want, the customer never gets duplicated again!
The debugger stopps after step 2.
Now when i click on the new customers, it calls the script to fetch the times by customer_id.
One of the xyz entrys display the correct times from database.
The second one, i just found out, display the times where customer_id="". In the database the value for "" is 0.
I have no clue where the second customer suddenly appears from and debugging didnt help me either -.-
When i close the app an open it again, there ist just one entry for the user that was visible twice before closing the app. It doesnt duplicate on opening view...
Here is my code..
Main Activity ZeitErfassen
public class ZeitErfassen extends AppCompatActivity {
public static LinkedList<Kunde> kunden = new LinkedList<Kunde>();
boolean running = false;
long startTime,endTime,totalTime;
private SharedPreferences app_preferences;
private SharedPreferences.Editor editor;
private TextView displayTime;
public Button startEndButton;
private ArrayAdapter<String> adapter;
private Spinner spinner;
public static Kunde selectedCustomer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_zeit_erfassen);
//Einstellungen laden
app_preferences = getApplicationContext().getSharedPreferences("MyPref", MODE_PRIVATE);
startTime= app_preferences.getLong("startTime", 0);
endTime = app_preferences.getLong("endTime", 0);
running = app_preferences.getBoolean("running", false);
displayTime = (TextView)findViewById(R.id.zeit_bei_Kunde);
displayTime.setText((CharSequence) app_preferences.getString("zeitAnzeige", "Zeit bei Kunde"));
startEndButton = (Button)findViewById(R.id.start_Timer);
startEndButton.setText((CharSequence) app_preferences.getString("timerButton", "Start Timer"));
DatabaseHelper.customerFromDatabaseToList(this);
editor = app_preferences.edit();
editor.commit();
}
public void onDestroy() {
super.onDestroy();
editor.putLong("startTime", startTime);
editor.putString("zeitAnzeige", (String) displayTime.getText());
editor.putString("timerButton", (String) startEndButton.getText());
editor.putLong("endTime", endTime);
editor.putLong("totalTime", totalTime);
editor.putBoolean("running", app_preferences.getBoolean("running", false));
editor.commit();
this.finish();
}
public void onResume() {
super.onResume();
// saveCustomers();
// createDropDown();
}
public void startTimer(View view) {
editor = app_preferences.edit();
if(running == false) {
startTime = getTime();
running = true;
editor.putLong("startTime", startTime);
startEndButton.setText("End Timer");
displayTime.setText("Zeitstoppung läuft");
editor.putString("zeitAnzeige", (String) displayTime.getText());
editor.putString("timerButton", (String) startEndButton.getText());
editor.putBoolean("running", true);
editor.commit();
} else {
setSelectedCustomer();
endTime = getTime();
editor.putLong("endTime",endTime);
totalTime = endTime - startTime;
editor.putLong("totalTime", totalTime);
displayTime.setText(formatTime(totalTime));
editor.putString("zeitAnzeige", (String) displayTime.getText());
startEndButton.setText("Start Timer");
editor.putString("timerButton", (String) startEndButton.getText());
running = false;
editor.putBoolean("running", false);
editor.commit();
DatabaseHelper.timeToDatabase(String.valueOf(selectedCustomer.getId()),formatTime(totalTime),this);
// selectedCustomer.saveTimeToCustomer(selectedCustomer, formatTimeForCustomer(totalTime));
}
}
public String formatTime(Long totalTime) {
int hours = (int) ((totalTime / (1000*60*60)) % 24);
int minutes = (int) ((totalTime / (1000*60)) % 60);
int seconds = (int) (totalTime / 1000) % 60;
String time = (String.valueOf(hours) + ":" + String.valueOf(minutes) + ":" + String.valueOf(seconds));
return time;
}
public String formatTimeForCustomer(Long totalTime) {
StringBuilder time = new StringBuilder();
Calendar cal = Calendar.getInstance();
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH);
int day = cal.get(Calendar.DAY_OF_MONTH);
time.append((String.valueOf(year) + "." + String.valueOf(month) + "." + String.valueOf(day))).append(formatTime(totalTime));
return time.toString();
}
public void neuerKunde(View view) {
Intent intent = new Intent(this, AddKunde.class);
startActivity(intent);
}
public void kundenĂbersicht(View view) {
// setSelectedCustomer();
Intent intent = new Intent(this, DisplayCustomer.class);
startActivity(intent);
}
public long getTime() {
long millis = System.currentTimeMillis();
return millis;
}
public void setSelectedCustomer() {
if(kunden.size() > 0) {
if (spinner.getSelectedItem().toString() != null) {
String tempCustomer = spinner.getSelectedItem().toString();
for (Kunde k : kunden) {
if (k.getName().equals(tempCustomer)) {
selectedCustomer = k;
}
}
}
}
}
public void createDropDown() {
/*File file = new File(this.getFilesDir(),"kunden.ser"); NOT USED BECAUSE DATABASE WORKS
if(file.exists()) {
Kunde.importFromFile(this);
}*/
if (kunden.size() > 0) {
spinner = (Spinner) findViewById(R.id.chooseCustomer);
// Create an ArrayAdapter using the string array and a default spinner layout
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, DisplayCustomer.namesOfCustomers());
// Specify the layout to use when the list of choices appears
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// Apply the adapter to the spinner
spinner.setAdapter(adapter);
}
}
}
DisplayCustomer(Where all customers are displayed with data from Database)
public class DisplayCustomer extends AppCompatActivity {
CustomerAdapter customerAdapter;
public ArrayAdapter<String> adapterCustomerView;
private ListView listCustomerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_customer);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
ArrayList<Kunde> customerList = getCustomerObjects();
customerAdapter = new CustomerAdapter(this,customerList);
listCustomerView = (ListView)findViewById(R.id.list_View_Customers);
// adapterCustomerView = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, namesOfCustomers());
listCustomerView.setAdapter(customerAdapter);
openCustomerDetails();
}
public static ArrayList<String> namesOfCustomers() {
ArrayList<String> customerNames = new ArrayList<>();
if(ZeitErfassen.kunden.size() > 0 ) {
for (Kunde k : ZeitErfassen.kunden) {
customerNames.add(k.getName());
}
}
return customerNames;
}
public static ArrayList<Kunde> getCustomerObjects() {
ArrayList<Kunde> customerList = new ArrayList<>();
if(ZeitErfassen.kunden.size() > 0 ) {
for (Kunde k : ZeitErfassen.kunden) {
customerList.add(k);
}
}
return customerList;
}
public void openCustomerDetails() {
listCustomerView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Kunde kunde = new Kunde();
kunde = (Kunde)listCustomerView.getItemAtPosition(position);
Intent intent = new Intent(DisplayCustomer.this, DisplayDetailedCustomer.class);
intent.putExtra("selectedCustomerObject",(Parcelable)kunde);
startActivity(intent);
}
});
}
}
My CustomerAdapter to pass data from one intent to another.
public class CustomerAdapter extends ArrayAdapter<Kunde> {
public CustomerAdapter(Context context, ArrayList<Kunde> customerList) {
super(context,0,customerList);
}
public View getView(int position, View convertView, ViewGroup parent) {
//Data for this position
Kunde kunde = getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.items_customer_layout, parent, false);
}
// Lookup view for data population
TextView tvName = (TextView) convertView.findViewById(R.id.tvCustomerName);
// Populate the data into the template view using the data object
tvName.setText(kunde.getName());
// Return the completed view to render on screen
return convertView;
}
}
DatabaseHelper Class
public class DatabaseHelper {
public static RequestQueue requestQueue;
public static String host = "http://192.168.150.238/";
public static final String insertUrl = host+"insertCustomer.php";
public static final String showUrl = host+"showCustomer.php";
public static final String insertTimeUrl = host+"insertTime.php";
public static final String showTimeUrl = host+"showTimes.php";
public static void customerFromDatabaseToList(final Context context) {
//Display customer from database
requestQueue = Volley.newRequestQueue(context);
final ArrayList<String> customerNames = new ArrayList<>();
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, showUrl, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray customers = response.getJSONArray("customers");
if(customers.length() > 0) {
for (int i = 0; i < customers.length(); i++) {
JSONObject customer = customers.getJSONObject(i);
String customerName = customer.getString("cus_name");
String customerAddress = customer.getString("cus_address");
int customerID = Integer.valueOf(customer.getString("cus_id"));
if (customerName != null && customerAddress != null) {
try {
Kunde k = new Kunde(customerName, customerAddress, customerID);
if (!listContainsObject(k)) {
ZeitErfassen.kunden.add(k);
}
} catch (Exception e) {
showAlert("Fehler in customerFromDatabaseToListn!", "Fehler", context);
}
} else {
showAlert("Fehler in customerFromDatabaseToListn!", "Fehler", context);
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
});
requestQueue.add(jsonObjectRequest);
}
public static boolean listContainsObject(Kunde cust) {
for(Kunde k : ZeitErfassen.kunden) {
if(k.getId() == cust.getId()) {
return true;
}
}
return false;
}
public static void timeToDatabase(final String customer_id, final String time_value, final Context context) {
requestQueue = Volley.newRequestQueue(context);
StringRequest request = new StringRequest(Request.Method.POST, DatabaseHelper.insertTimeUrl, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
showAlert("Fehler","Fehler bei Verbindung zur Datenbank",context);
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> parameters = new HashMap<String,String>();
parameters.put("customerid",customer_id);
parameters.put("timevalue",time_value);
return parameters;
}
};
requestQueue.add(request);
};
public static void showAlert(String title, String message, Context context) {
// 1. Instantiate an AlertDialog.Builder with its constructor
AlertDialog.Builder builder = new AlertDialog.Builder(context);
// 2. Chain together various setter methods to set the dialog characteristics
builder.setMessage(message)
.setTitle(title);
// 3. Get the AlertDialog from create()
AlertDialog dialog = builder.create();
}
public static ArrayList<String> timesFromDataBaseToList(final Context context,final int customer_id) {
requestQueue = Volley.newRequestQueue(context);
final String cus_id = String.valueOf(customer_id) ;
final ArrayList<String> customerTimes = new ArrayList<>();
StringRequest jsonObjectRequest = new StringRequest(Request.Method.POST, showTimeUrl, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject object = new JSONObject(response.toString());
JSONArray times = object.getJSONArray("customertimes");
if (times.length() > 0) {
for (int i = 0; i < times.length(); i++) {
JSONObject jsonObject = times.getJSONObject(i);
String timeValue = jsonObject.getString("time_value");
if (timeValue != null) {
customerTimes.add(timeValue);
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(context,"Fehler beim Holen der Zeiten",Toast.LENGTH_LONG).show();
error.printStackTrace();
}
}){
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> parameters = new HashMap<String,String>();
parameters.put("cus_id",cus_id);
return parameters;
}
};
requestQueue.add(jsonObjectRequest);
return customerTimes;
};
}
DisplayDetailedCustomer / Display the times
public class DisplayDetailedCustomer extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_detailed_customer);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Intent getCustomerParcable = getIntent();
Kunde customer = getCustomerParcable.getExtras().getParcelable("selectedCustomerObject");
TextView displayCustomerNameDetailed =(TextView) findViewById(R.id.detailedCustomerViewName);
TextView displayCustomerAddressDetailed =(TextView) findViewById(R.id.detailedCustomerAddress);
ListView timeListView = (ListView)findViewById(R.id.detailedTimeListView);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, DatabaseHelper.timesFromDataBaseToList(this,customer.getId()));
timeListView.setAdapter(adapter);
displayCustomerNameDetailed.setText(customer.getName());
displayCustomerAddressDetailed.setText(customer.getAdresse());
}
}
Kunde Class / Customer Class with interface Parcelable
public class Kunde implements Serializable,Parcelable {
private String name;
private String adresse;
private int id;
public LinkedList<String> zeiten;
public Kunde(String name, String adresse) throws Exception{
setName(name);
setAdresse(adresse);
zeiten = new LinkedList<String>();
}
public Kunde(String name, String adresse,int id) throws Exception{
setName(name);
setAdresse(adresse);
setId(id);
zeiten = new LinkedList<String>();
}
public Kunde(){};
public void setId(int id) {
this.id = id;
}
public int getId(){
return id;
}
public void setName(String name) throws Exception {
if(name != null) {
this.name = name;
} else throw new Exception("Name ist ungueltig! in setName");
}
public void setAdresse(String adresse) throws Exception{
if(adresse != null) {
this.adresse = adresse;
}else throw new Exception("Adresse ist ungueltig! in setAdresse");
}
public String getName() {
return name;
}
public String getAdresse() {
return adresse;
}
public void saveZeit(Long totalTime) {
zeiten.add(String.valueOf(totalTime));
}
public void saveTimeToCustomer(Kunde customer,String time){
customer.zeiten.add(time);
}
//------------------------------------Parcelable Methods to pass Daata from one Intent to another----------------------------------------
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.id);
dest.writeString(this.name);
dest.writeString(this.adresse);
// dest.writeList(this.zeiten);
}
// this is used to regenerate your object. All Parcelables must have a CREATOR that implements these two methods
public static final Parcelable.Creator<Kunde> CREATOR = new Parcelable.Creator<Kunde>() {
public Kunde createFromParcel(Parcel in) {
return new Kunde(in);
}
public Kunde[] newArray(int size) {
return new Kunde[size];
}
};
// example constructor that takes a Parcel and gives you an object populated with it's values
private Kunde(Parcel in) {
LinkedList<String> zeiten = null;
id = in.readInt();
name = in.readString();
adresse = in.readString();
}
}
Thanks for taking your time!!