RealmObject not saving data - android

I am saving data to a RealmObject then adding it to my Realm. After leaving the activity and returning the RealmObject is retrieved and the EditText are loaded with the appropriate data. All the EditText but one, Company Address, are loading correctly and I can't figure out why when all save and loading information is the same. Any ideas?
Activity
public class NewLocation extends ActionBarActivity {
public EditText editCoName;
public EditText editCoAddress;
public EditText editCoContact;
public EditText editSqFt;
public EditText editTaxed;
public EditText editConcerns;
private Realm realm;
public CompanyInfo companyInfo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new_location);
findViewById(R.id.button3).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SaveInfo();
Intent i = new Intent(NewLocation.this, RoomList.class);
startActivity(i);
}
});
editCoName = (EditText) findViewById(R.id.CoName);
editCoAddress = (EditText) findViewById(R.id.CoAddress);
editCoContact = (EditText) findViewById(R.id.CoContact);
editSqFt = (EditText) findViewById(R.id.SqFt);
editTaxed = (EditText) findViewById(R.id.Taxed);
editConcerns = (EditText) findViewById(R.id.Concerns);
//initialize realm and make CompanyInfo object if there is not already one
realm = Realm.getInstance(this);
CompanyInfo result = realm.where(CompanyInfo.class).findFirst();
if (result == null){
realm.beginTransaction();
companyInfo = realm.createObject(CompanyInfo.class);
companyInfo.setName(editCoName.getText().toString());
companyInfo.setAddress(editCoAddress.getText().toString());
companyInfo.setContact(editCoContact.getText().toString());
companyInfo.setTaxed(editTaxed.getText().toString());
companyInfo.setSqFt(editSqFt.getText().toString());
companyInfo.setConcerns(editConcerns.getText().toString());
realm.commitTransaction();
}
else {
editCoName.setText(result.getName());
editCoAddress.setText(result.getAddress());
editCoContact.setText(result.getContact());
editTaxed.setText(result.getTaxed());
editSqFt.setText(result.getSqFt());
editConcerns.setText(result.getConcerns());
}
}
#Override
protected void onResume() {
super.onResume();
LoadInfo();
}
#Override
protected void onPause() {
super.onPause();
SaveInfo();
}
#Override
protected void onDestroy() {
super.onDestroy();
realm.close();
}
public void SaveInfo() {
//save all info from the page
companyInfo = realm.where(CompanyInfo.class).findFirst();
realm.beginTransaction();
companyInfo.setName(editCoName.getText().toString());
companyInfo.setAddress(editCoAddress.getText().toString());
companyInfo.setContact(editCoContact.getText().toString());
companyInfo.setTaxed(editTaxed.getText().toString());
companyInfo.setSqFt(editSqFt.getText().toString());
companyInfo.setConcerns(editConcerns.getText().toString());
realm.copyToRealmOrUpdate(companyInfo);
realm.commitTransaction();
}
public void LoadInfo() {
//load info fom the CompanyInfo and put it into EditTexts
companyInfo = realm.where(CompanyInfo.class).findFirst();
if (companyInfo != null) {
editCoName.setText(companyInfo.getName());
editCoAddress.setText(companyInfo.getAddress());
editCoContact.setText(companyInfo.getContact());
editTaxed.setText(companyInfo.getTaxed());
editSqFt.setText(companyInfo.getSqFt());
editConcerns.setText(companyInfo.getConcerns());
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_new_location, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
switch(item.getItemId())
{
case R.id.home:
startActivity(new Intent(getApplicationContext(), MainPage.class));
break;
}
return super.onOptionsItemSelected(item);
}
}
CompanyInfo class
public class CompanyInfo extends RealmObject{
#PrimaryKey
private String Name;
#Ignore
private String Address;
private String Contact;
private String sqFt;
private String taxed;
private String concerns;
private RealmList<Rooms> rooms = new RealmList<>();
public RealmList<Rooms> getRooms() {
return rooms;
}
public void setRooms(RealmList<Rooms> rooms) {
this.rooms = rooms;
}
public String getName() {
return Name;
}
public String getAddress() {
return Address;
}
public String getContact() {
return Contact;
}
public String getSqFt() {
return sqFt;
}
public String getTaxed() {
return taxed;
}
public String getConcerns() {
return concerns;
}
public void setName(String coName) {
this.Name = coName;
}
public void setAddress(String coAddress) {
this.Address = coAddress;
}
public void setContact(String coContact) {
this.Contact = coContact;
}
public void setSqFt(String sqFt) {
this.sqFt = sqFt;
}
public void setTaxed(String taxed) {
this.taxed = taxed;
}
public void setConcerns(String concerns) {
this.concerns = concerns;
}
}

You have an #Ignore annotation on CompanyInfo#Adresse, remove it and Realm will save the adress.

Related

Passing firebase data to another activity in form of ArrayList (Android)

The problem is that it always gives "List:NULL" Toast in MainActivity and list is not passed I suppose. Please help, trying for 2 days. Help me!!
I am confused as to how I should pass the ArrayList from Firebase database to my MainActivity.
Before doing the below thing, I tried to pass ArrayList in onCreate of Splash activity after it fetched from firebase but myWebLinks always came null when I used in onCreate except on onDataChange of ValueEventListener so I couldn't pass in next activity.
This is my SplashActivity.class
public class SplashActivity extends AppCompatActivity {
private static final String TAG = "abcd";
//1 Firebase database object
//entry point for the app to access our database
private FirebaseDatabase mFirebaseDatabase;
//2 is a class that reference a specific part of the database, references 'link' portion of DB
private DatabaseReference mDatabaseReference;
//To read from DB, attach ChildEventListener object to the reference. Allows to listen and have code triggered whenever
//changes occur on the node.
private ValueEventListener mValueEventListener;
private AVLoadingIndicatorView aviIV;
private ArrayList<WebLinks> mywebLinks;
public GenericTypeIndicator<ArrayList<WebLinks>> genericTypeIndicator;
private long seed;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
aviIV = findViewById(R.id.avi);
aviIV.smoothToShow();
mFirebaseDatabase = FirebaseDatabase.getInstance();
mDatabaseReference = mFirebaseDatabase.getReference().child("weblinks");
if (mValueEventListener == null) {
valueEventListener();
}
}
#Override
protected void onPause() {
super.onPause();
Log.i(TAG, "onPause: ");
//14 Removing
if (mValueEventListener != null) {
mDatabaseReference.removeEventListener(mValueEventListener);
mValueEventListener = null;
}
}
#Override
protected void onResume() {
super.onResume();
if (mValueEventListener == null) {
valueEventListener();
mDatabaseReference.addValueEventListener(mValueEventListener);
}
}
void valueEventListener() {
final long[] value = {0};
mValueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
/* This method is called once with the initial value and again whenever data at this location is updated.*/
value[0] = dataSnapshot.getChildrenCount();
genericTypeIndicator = new GenericTypeIndicator<ArrayList<WebLinks>>() {
};
mywebLinks = dataSnapshot.getValue(genericTypeIndicator);
seed = System.nanoTime();
Collections.shuffle(mywebLinks, new Random(seed));
Toast.makeText(SplashActivity.this, "" + mywebLinks.get(0).getName(), Toast.LENGTH_SHORT).show();
Log.i(TAG, "getWebLinksFirebaseeee: on");
Intent intent = new Intent(SplashActivity.this, MainActivity.class);
intent.putParcelableArrayListExtra("web_links", mywebLinks);
startActivity(intent);
SplashActivity.this.finish();
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
}
};
mDatabaseReference.addValueEventListener(mValueEventListener);
}
}
This is my MainActivity.class
public class MainActivity extends AppCompatActivity {
private WebView myWebView;
private WaveSwipeRefreshLayout mWaveSwipeRefreshLayout;
private Toolbar mtoolBar;
private ShineButton mFavBtn;
private BoomMenuButton leftBmb;
public static final String TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
leftBmb = (BoomMenuButton) findViewById(R.id.action_bar_left_bmb);
mFavBtn = (ShineButton) findViewById(R.id.favBtn);
mFavBtn.init(this);
mtoolBar = (Toolbar) findViewById(R.id.toolBar);
setSupportActionBar(mtoolBar);
if (getSupportActionBar() != null) {
getSupportActionBar().setElevation(0);
}
ArrayList<WebLinks> myList = getIntent().getParcelableExtra("web_links");
if(myList==null)
Toast.makeText(this, "LIST:NULL", Toast.LENGTH_SHORT).show();
else
Toast.makeText(this, "LIST:"+myList.get(1).getName(), Toast.LENGTH_SHORT).show();
myWebView = findViewById(R.id.webView);
initWebSettings();
initSwipeRefresh();
initLeftBtn();
}
This is my class
public class WebLinks implements Parcelable {
private String name;
private String link;
public WebLinks() {
}
public WebLinks(String webName, String webLink) {
this.name = webName;
this.link = webLink;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public static final Parcelable.Creator<WebLinks> CREATOR = new Creator<WebLinks>() {
public WebLinks createFromParcel(Parcel source) {
WebLinks fields = new WebLinks();
fields.name = source.readString();
fields.link = source.readString();
return fields;
}
public WebLinks[] newArray(int size) {
return new WebLinks[size];
}
};
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(name);
parcel.writeString(link);
}
}

retrieving firebase data to listview with a unique ID using android studio

How can I retrieve my data from firebase to android studio listview? I watch many tutorials on youtube. I use the codes of what did the tutorial gave, but it doesn't work on mine and also every data in my firebase has a unique ID to separate each data.
Here are the codes that I used:
public class ExisActivity extends AppCompatActivity {
private DatabaseReference mdatabase;
private ListView mListView;
private ArrayList<String> marralist = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_exis);
mdatabase = FirebaseDatabase.getInstance().getReference();
mListView = (ListView)findViewById(R.id.lvexist);
final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,marralist);
mListView.setAdapter(arrayAdapter);
}
}
and this is the other code that i used to get the data:
public class SaveData {
public String getEtOwnername() {
return etOwnername;
}
public void setEtOwnername(String etOwnername) {
this.etOwnername = etOwnername;
}
public String getEtAnimalname() {
return etAnimalname;
}
public void setEtAnimalname(String etAnimalname) {
this.etAnimalname = etAnimalname;
}
public String getEtAddress() {
return etAddress;
}
public void setEtAddress(String etAddress) {
this.etAddress = etAddress;
}
public String getEtContactNo() {
return etContactNo;
}
public void setEtContactNo(String etContactNo) {
this.etContactNo = etContactNo;
}
public String getEtDobAge() {
return etDobAge;
}
public void setEtDobAge(String etDobAge) {
this.etDobAge = etDobAge;
}
public String getEtEmail() {
return etEmail;
}
public void setEtEmail(String etEmail) {
this.etEmail = etEmail;
}
public String getEtClinicalNotes() {
return etClinicalNotes;
}
public void setEtClinicalNotes(String etClinicalNotes) {
this.etClinicalNotes = etClinicalNotes;
}
public String getEtMedication() {
return etMedication;
}
public void setEtMedication(String etMedication) {
this.etMedication = etMedication;
}
public String getEtPayMent() {
return etPayMent;
}
public void setEtPayMent(String etPayMent) {
this.etPayMent = etPayMent;
}
public SaveData(String etOwnername, String etAnimalname, String etAddress, String etContactNo, String etDobAge, String etEmail, String etClinicalNotes, String etMedication, String etPayMent) {
this.etOwnername = etOwnername;
this.etAnimalname = etAnimalname;
this.etAddress = etAddress;
this.etContactNo = etContactNo;
this.etDobAge = etDobAge;
this.etEmail = etEmail;
this.etClinicalNotes = etClinicalNotes;
this.etMedication = etMedication;
this.etPayMent = etPayMent;
}
this is my DB structure of my fire base i'm also new to fire base
{
"rules":{
".read": true,
".write": true,
}
}
Can any help me? please provide some link
PLEASE RESPECT MY POST

How to retrieve web service values through Retrofit to text view?

I'm developing an app and in first activity it has card view layout. I'm retrieving data from a webservice and relevant data are showed in card view. It's working well. Now when a user clicks a particular card view I need to go for another activity. I'm getting relevant ID for that card view and passing it to the second activity. In second activity I need to show the content according to that unique Id. But I'm not getting any thing. This is what I tried.
Pojo class
public class PromoDetails {
String PromoId;
String PromoName;
String PromoImg;
String promoDetails;
String promoValidty;
public PromoDetails(String PromoId, String PromoName, String PromoImg , String promoDetails , String promoValidity) {
this.PromoId = PromoId;
this.PromoName = PromoName;
this.PromoImg = PromoImg;
this.promoDetails = promoDetails;
this.promoValidty = promoValidity;
}
public String getPromoId() {
return PromoId;
}
public void setPromoId(String promoId) {
PromoId = promoId;
}
public String getPromoName() {
return PromoName;
}
public void setPromoName(String promoName) {
PromoName = promoName;
}
public String getPromoImg() {
return PromoImg;
}
public void setPromoImg(String promoImg) {
PromoImg = promoImg;
}
public String getPromoDetails() {
return promoDetails;
}
public void setPromoDetails(String promoDetails) {
this.promoDetails = promoDetails;
}
public String getPromoValidty() {
return promoValidty;
}
public void setPromoValidty(String promoValidty) {
this.promoValidty = promoValidty;
}}
ApiInterface
public interface ApiInterface {
#POST("ap/promotions.php")
Call<List<Promotions>> getPromotions();
#GET("test.php/promotions/{PromoId}")
Call<List<PromoDetails>> getPromotDetails(#Path("PromoId") String PromoId) ;}
New Activity class
public class PromotionsInside extends Activity {
private ApiInterface apiInterface;
private List<PromoDetails> promoDetails;
TextView prDescription;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.promo_inside);
Bundle extras = getIntent().getExtras();
String promoId = "";
if (extras != null) {
promoId = extras.getString("PROMO_ID");
getPromotionUpdate(promoId);
}
}
private void getPromotionUpdate(String myPromoId) {
apiInterface = ApiClient.getApiClient().create(ApiInterface.class);
Call<List<PromoDetails>> call = apiInterface.getPromotDetails(myPromoId);
call.enqueue(new Callback<List<PromoDetails>>() {
#Override
public void onResponse(Call<List<PromoDetails>> call, Response<List<PromoDetails>> response) {
promoDetails = response.body();
runOnUiThread(new Runnable() {
#Override
public void run() {
prDescription = (TextView)findViewById(R.id.promoDescriptionsss) ;
prDescription.setText(promoDetails.get(0).getPromoName());
}
});
}
#Override
public void onFailure(Call<List<PromoDetails>> call, Throwable t) {
}
});
}}
I have similar case. Try to use this to start second activity:
Intent intent = new Intent(this, PromotionsInside.class);
//Make sure that you put String id in intent
intent.putExtra("PROMO_ID", id);
startActivity(intent);
And this in second activity:
if (getIntent().hasExtra("PROMO_ID")) {
String id = getIntent().getStringExtra("PROMO_ID", null);
//next steps that you need
}
Hope it will help you

Firebase database error : Found conflicting getters for name: isAccessibilityFocusable

I am getting this error:
Caused by: com.google.firebase.database.DatabaseException: Found conflicting getters for name: isAccessibilityFocusable
while trying to update my User.
The User class is like this
public class User {
#PrimaryKey
String userName;
String groupName;
int totalMoney;
boolean turn;
boolean hapyo;
boolean blind;
#Exclude
TextView textView;
#Exclude
Button bHapdiye,bChale,bShow,bHeram;
public Button getbHapdiye() {
return bHapdiye;
}
public void setbHapdiye(Button bHapdiye) {
this.bHapdiye = bHapdiye;
}
public Button getbChale() {
return bChale;
}
public void setbChale(Button bChale) {
this.bChale = bChale;
}
public Button getbShow() {
return bShow;
}
public void setbShow(Button bShow) {
this.bShow = bShow;
}
public Button getbHeram() {
return bHeram;
}
public void setbHeram(Button bHeram) {
this.bHeram = bHeram;
}
public TextView getTextView() {
return textView;
}
public void setTextView(TextView textView) {
this.textView = textView;
}
public boolean isBlind() {
return blind;
}
public void setBlind(boolean blind) {
this.blind = blind;
}
public boolean isHapyo() {
return hapyo;
}
public void setHapyo(boolean hapyo) {
this.hapyo = hapyo;
}
public boolean isTurn() {
return turn;
}
public void setTurn(boolean turn) {
this.turn = turn;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
public int getTotalMoney() {
return totalMoney;
}
public void setTotalMoney(int totalMoney) {
this.totalMoney = totalMoney;
}
}
I am trying to update the User like this
final User user1 = userList.get(0);
user1.setTextView(tvUser1);
user1.setbChale(bChaleP1);
user1.setbHapdiye(bHapdiyeP1);
user1.setbHeram(bHeramP1);
user1.setbShow(bShowP1);
user1.setTurn(true);
setUsersTurn(user1.isTurn(),bHapdiyeP1,bChaleP1,bShowP1,bHeramP1);
setTurnInFirebase(user1);
The setTurnInFirebase method is like this
public void setTurnInFirebase(User user){
myRef.child("users").setValue(user);
}
So when I run the project, I get the above mentioned error. What could be the reason for this. Thankyou
Your user contains a TextView, which is a class that Firebase won't be able to serialize/deserialize.
To allow writing a class to the Firebase Database, make sure that it only contains properties of simple types or objects that you created: so called POJOs - Plain Old Java Objects.
Alternatively you can exclude the non-supported properties (such as the TextView) by annotating them:
#Exclude
public TextView getTextView() {
return textView;
}
#Exclude
public void setTextView(TextView textView) {
this.textView = textView;
}

Android Persistent caching: using ModelCache from ignition

I have used ignition in my app to cache my composite object,let say mStudentObject. I have cached my data successfully, the issue is , when i retrieve my object after killing app from recently running apps button(from currently running tasks button) ,i haven't fount any data against key(cached clear automatically).When i re-launch app (with out killing app from recent tasks) object retrieved properly.
i don't know what is wrong with code.I want to cache my object permanently for 2 days. when ever i launch my app,app should get data from cached object either i kill app from currently running tasks or not. Any idea,please share.Here is my complete code:
public class MainActivity extends Activity {
Button[] buttons = null;
// ObjectLRUCache objectLRUCache = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttons = new Button[2];
buttons[0] = (Button) findViewById(R.id.button1);// to save data
buttons[1] = (Button) findViewById(R.id.button2); // to get data
// final Student s = new Student("imran", 23, 16);
buttons[0].setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (IgnetionHelper.getInstance()!= null) {
Log.d("test", "key contains, updating");
Student s = new Student("imran", 23, 16);
IgnetionHelper.getInstance().putData(s);
} else{
Log.d(""test),"instance is null..");
}
});
buttons[1].setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
IgnetionHelper ddd = IgnetionHelper.getInstance();
if (IgnetionHelper.getInstance().getData()!= null) {
Student s = (Student) IgnetionHelper.getInstance().getData();
Log.d("test", "key contains, age is: " + s.age);
} else {
Log.d("test", "data is null...");
}
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
and My Person class is as:
public abstract class Person extends CachedModel implements Serializable{
public String name = "";
public int age = 0;
public Person(){};
public Person (String name,int age) {
this.name=name;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Student class is as:
public class Student extends Person{
public String name = "";
public int age = 0;
public int rollNo = 0;
public Student(){
}
public Student(String name, int age, int rollno) {
this.rollNo = rollno;
this.name=name;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getRollNo() {
return rollNo;
}
public void setRollNo(int rollNo) {
this.rollNo = rollNo;
}
#Override
public boolean reloadFromCachedModel(ModelCache modelCache,
CachedModel cachedModel) {
Student student = (Student) cachedModel;
name = student.name;
age = student.age;
rollNo = student.rollNo;
return false;
}
#Override
public String createKey(String id) {
// TODO Auto-generated method stub
return id;
}
}
And finally, ignition helper class is as:
public class IgnetionHelper {
private static final String KEY_FOR_MYOBJECT = "MY_TEST_KEY";
private static ModelCache cache;
private final static int initialCapacity = 1000;
private final static int maxConcurrentThreads = 3;
private final static long expirationInMinutes = 60 * 24 * 2;
private static IgnetionHelper mIgnetionHelper = null;
public static IgnetionHelper getInstance() {
if (cache == null)
cache = new ModelCache(initialCapacity, expirationInMinutes,
maxConcurrentThreads);
if (mIgnetionHelper == null)
mIgnetionHelper = new IgnetionHelper();
return mIgnetionHelper;
}
public boolean putData(CachedModel model) {
model.setId(KEY_FOR_MYOBJECT);
if (model.save(cache)) {
Log.d("IgnetionHelper", "saved.....");
return true;
} else {
Log.d("IgnetionHelper", "saved.....");
return false;
}
// CachedModel model = Feed.find(cache, key, Feed.class);
// if (model != null) {
// Log.d("test", "key contains, updating");
// Feed s = (Feed) model;
// return s.save(cache);
// }
}
public CachedModel getData() {
return Student.find(cache, KEY_FOR_MYOBJECT, Student.class);
}
}
i have found solution of my problem.
Let say you have student object
Student s = new Student("imran",16,23);
and then implement these methods in your ignetionhelper calss:
public static boolean putData(Object object, Context context,String key) {
return GenericStore.saveObject(GenericStore.TYPE_MEMDISKCACHE,key, (Serializable) object, context.getApplicationContext());
}
public static Object getData(Context context,String key) {
return GenericStore.getObject(GenericStore.TYPE_MEMDISKCACHE,key, context.getApplicationContext());
}
https://github.com/wareninja/generic-store-for-android
import library given hare and then use above methods as:
IgnetionHelper.putData(s, context, IgnetionHelper.YOUR_KAY);
Student s=(Student)IgnetionHelper.getData(context,IgnetionHelper.YOUR_KAY);
You will need to use a cache that is stored to disk, when the app is killed the cache you are using appears to be cleared.
There is some information from Google about cache storage here http://developer.android.com/guide/topics/data/data-storage.html and check out this existing SO answer on some options for data caching within your app Best Way to Cache Data in Android

Categories

Resources