Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I have an SQL Server Database with quotes.
The table has four fields ID primary key, Title, Description, and InsertDate.
I have created an Android application to display the quotes. The quotes are downloaded locally to the SQLite database and then displayed using ListView.
Whenever the user clicks the sync button, if any new quotes are added to the SQL Server database it should be downloaded to the SQLite database.
I have created a web service for the syncing using RestApi.
I have never used Webservice and new to Android development. Worked on Asp.net/C#.
My question is:
The android application should only download the latest records how to request only the latest inserted record from android using webservice.
If I change a record on SQL server how to identify such records and change in the SQLite database.
My current code is logically wrong and I need to change as it is deleting all the records and inserting all the records again. (Wanted to give demo to the customer)
// Create AsycHttpClient object
AsyncHttpClient client = new AsyncHttpClient();
// Http Request Params Object
RequestParams params = new RequestParams();
// Show ProgressBar
prgDialog.show();
client.get(getApplicationContext().getString(R.string.IpAdd) + "/WebApi/api/mpAudioapi/GetAllAudio", params, new AsyncHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
// Hide ProgressBar
prgDialog.hide();
// Update SQLite DB with response sent by getusers.php
String str;
try {
str = new String(responseBody, "UTF-8");
} catch (UnsupportedEncodingException e) {
// this should never happen because "UTF-8" is hard-coded.
throw new IllegalStateException(e);
}
updateSQLite(str);
}
#Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
// TODO Auto-generated method stub
// Hide ProgressBar
prgDialog.hide();
if (statusCode == 404) {
Toast.makeText(getApplicationContext(), "Requested resource not found", Toast.LENGTH_LONG).show();
} else if (statusCode == 500) {
Toast.makeText(getApplicationContext(), "Something went wrong at server end", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(), "Unexpected Error occcured! [Most common Error: Device might not be connected to Internet]",
Toast.LENGTH_LONG).show();
}
}
});
The code to Sync
int writing_counts = dbHandler.getMpAudioRowCount();
ArrayList<HashMap<String, String>> usersynclist;
usersynclist = new ArrayList<HashMap<String, String>>();
// Create GSON object
Gson gson = new GsonBuilder().create();
try {
// Extract JSON array from the response
JSONArray arr = new JSONArray(response);
//JSONObject responseObject = new JSONObject(response);
//JSONArray arr = responseObject.getJSONArray("results");
//JSONArray arr = new JSONArray(response);
System.out.println(arr.length());
if (writing_counts == arr.length()) {
Toast.makeText(getApplicationContext(), "Sorry. No new writings to sync.", Toast.LENGTH_LONG).show();
return;
}
dbHandler.truncateTableAudio();
// If no of array elements is not zero
if (arr.length() != 0) {
// Loop through each array element, get JSON object which has Title and Des
for (int i = 0; i < arr.length(); i++) {
// Get JSON object
JSONObject obj = (JSONObject) arr.get(i);
System.out.println(obj.get("Id"));
System.out.println(obj.get("Title_Audio"));
System.out.println(obj.get("URL_Audio"));
// DB QueryValues Object to insert into SQLite
queryValues = new HashMap<String, String>();
// Add ID extracted from Object
queryValues.put("id", obj.get("Id").toString());
// Add Title extracted from Object
queryValues.put("title", obj.get("Title_Audio").toString());
// Add Des extracted from Object
queryValues.put("url", obj.get("URL_Audio").toString());
// Insert User into SQLite DB
dbHandler.insertWriteAudio(queryValues);
HashMap<String, String> map = new HashMap<String, String>();
// Add status for each User in Hashmap
map.put("id", obj.get("Id").toString());
map.put("title", obj.get("Title_Audio").toString());
map.put("url", obj.get("URL_Audio").toString());
usersynclist.add(map);
}
// Inform Remote MySQL DB about the completion of Sync activity by passing Sync status of Users
//updateMySQLSyncSts(gson.toJson(usersynclist));
// Reload the Main Activity
reloadActivity();
Toast.makeText(getApplicationContext(), "Sync activity completed successfully.", Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
My DBhandler Code:
public void truncateTable(){
SQLiteDatabase db = this.getWritableDatabase();
db.execSQL("delete from "+ MP_TABLE);
}
public void insertWriteAudio(HashMap<String, String> queryValues) {
SQLiteDatabase database = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("id", queryValues.get("Id"));
values.put("title", queryValues.get("title"));
values.put("url", queryValues.get("url"));
database.insert("audios", null, values);
database.close();
}
public int getMpAudioRowCount() {
SQLiteDatabase db = this.getReadableDatabase();
long cnt = DatabaseUtils.queryNumEntries(db, MP_TABLE_Audio);
db.close();
return (int) cnt;
}
You can download only the updated content from database server. This is how you can do that. It will need some changes in your schema -
On Server side
Add one more column in the database, 'Updated_On' which will contain
the timestamp when that record was updated on the server
When you are inserting or updating any new record in the databse,
change the 'Updated_On' field accordingly
Now make some changes on the client side
On Client Side
In your Android app, keep a note of what was the last change that
was downloaded, i.e. the last download was made for 'Updated_On' =
{some past time stamp} (You can do that in SharedPreferences on cancreate a SQLite table)
When you query to download, query for all records who have
'Updated_On' > {some past time stamp}
If the record exist in your local SQLite database, update it; else insert the record in your SQLite databse
To help you get started, where you are making the AsyncHttp call
....
RequestParams params = new RequestParams();
// Show ProgressBar
prgDialog.show();
params.put("latestChange",lastUpdateTimestamp);
//where lastUpdateTimestamp is the sharedPreference value you are keeping of last update
client.get(getApplicationContext().getString(R.string.IpAdd) + "/WebApi/api/mpAudioapi/GetAllAudio", params, new AsyncHttpResponseHandler() {
....
On your server side you get that post variable $lastUpdate = $_POST['latestChange']. Now use the variable $lastUpdate in your API to query the database Select * from table where Updated_On > $lastUpdate
Related
I have implemented Volley and Recycler view to parse and display a list of few items from a simple JSON file.
There are at times when a key doesnot exists in an object but may appear in other object. That key is already defined using object.getInt("someKey").
As soon as Volley starts parsing the object with the missing key, it breaks out of the for loop (objects are stored in array) and catches the JSONException e, which is exactly what the app is supposed to do in case of a missing key.
However, I would like to prevent this behavior and use a placeholder value for that missing key of that particular object, so that the array list gets successfully buildup and recyclerview gets filled thereby application starts working normally.
What logic can I use in order to achieve this behavior?
Thank you!
private void parseJSON() {
String url = "https://example.com/index.json";
JsonArrayRequest request = new JsonArrayRequest(Request.Method.GET, url, null,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
try {
for (int i = 0; i < response.length(); i++) {
JSONObject object = response.getJSONObject(i);
String title = object.getString("subject");
String description = object.getString("message");
String imageUrl = object.getString("thumb");
Integer threadId = object.getInt("threadId");
mList.add(new Item( title, description, threadId));
}
mItemAdapter.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
});
In the above code, threadId is the key, which may or maynot appear in many objects of the JSON.
You can check firstly if your key exists on object
try {
for (int i = 0; i < response.length(); i++) {
JSONObject object = response.getJSONObject(i);
String title = object.getString("subject");
String description = object.getString("message");
String imageUrl = object.getString("thumb");
Integer threadId;
if(object.toString().contain("threadId"){
threadId = object.getInt("threadId");
}else{
threadId = 0;
}
mList.add(new Item( title, description, threadId));
}
mItemAdapter.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
If i understood well your Question , here what you need to do , if you are not sure if this key exists use the following
jsonObject.optBoolean("yourKey");
jsonObject.optInt("yourKey");
jsonObject.optString("yourKey");
jsonObject.optLong("yourKey");
jsonObject.optDouble("yourKey");
jsonObject.optJSONArray("yourKey");
this will make sure jsonObject will ignore that key if it doesn't exist.
object.getInt("someKey") is to get value from "somekey".if somekey is not appeared it shows JSONException. Instead of this object.optInt("someKey"). It will get value from "somekey" if it appears, otherwise it skipped. This is simple solution. Thanks
I would like to ask if someone here knows how to convert a HashMap to JSON Array to be used on a Adapter. The logic is when you logged in, it will fetch data on a web server using Volley, store it on SQLite database and at the same time it will show the retrieve data on a custom listview. The thing is, if you will move to another fragment on the application and then go back, it will request again on the volley which it will take time. I wanted that if you will go back the data stored on the SQLite database will be retrieved and if the user wanted to update the data using SwipeRefresh, that's the time to update for new data.
Here is my code.
public void LoadMarkets()
{
Map<String,String>tmpRate = new HashMap<String,String>();
RateDb db = new RateDb(getActivity().getApplicationContext());
Cursor rs = db.getData();
if(rs!=null && rs.getCount()>0)
{
if(rs.moveToFirst())
{
while(rs.moveToNext())
{
tmpRate.put("rateID",rs.getString(rs.getColumnIndex(RateDb.rateID)));
tmpRate.put("Name",rs.getString(rs.getColumnIndex(RateDb.rateName)));
tmpRate.put("Rate",rs.getString(rs.getColumnIndex(RateDb.rateRate)));
tmpRate.put("Date",rs.getString(rs.getColumnIndex(RateDb.rateDate)));
tmpRate.put("Time",rs.getString(rs.getColumnIndex(RateDb.rateTime)));
tmpRate.put("Ask",rs.getString(rs.getColumnIndex(RateDb.rateAsk)));
tmpRate.put("Bid",rs.getString(rs.getColumnIndex(RateDb.rateBid)));
tmpRate.put("Balance",rs.getString(rs.getColumnIndex(RateDb.rateBalance)));
//Log.d("MyDebug",rs.getString(rs.getColumnIndex(RateDb.rateName)));
}
}
}
rs.close();
db.close();
JSONObject jsonObject = new JSONObject(tmpRate);
JSONArray jsonArray = new JSONArray();
jsonArray.put(jsonObject);
RowAAdapter rowAAdapter = new RowAAdapter(getActivity(),jsonArray);
lvMarkets.setAdapter(rowAAdapter);
swipeRefreshLayout.setRefreshing(false);
}
The problem is that when i load this function, it only shows the last data.
I hope you can help me with my problem.
Thank you very much.
You can put the values directly into the jsonObject instead of adding it to the hashmap like this :
public void LoadMarkets()
{
RateDb db = new RateDb(getActivity().getApplicationContext());
Cursor rs = db.getData();
if(rs!=null && rs.getCount()>0)
{
if(rs.moveToFirst())
{
while(rs.moveToNext())
{
JSONObject jsonObject = new JSONObject();
jsonObject.put("rateID",rs.getString(rs.getColumnIndex(RateDb.rateID)));
jsonObject.put("Name",rs.getString(rs.getColumnIndex(RateDb.rateName)));
jsonObject.put("Rate",rs.getString(rs.getColumnIndex(RateDb.rateRate)));
jsonObject.put("Date",rs.getString(rs.getColumnIndex(RateDb.rateDate)));
jsonObject.put("Time",rs.getString(rs.getColumnIndex(RateDb.rateTime)));
jsonObject.put("Ask",rs.getString(rs.getColumnIndex(RateDb.rateAsk)));
jsonObject.put("Bid",rs.getString(rs.getColumnIndex(RateDb.rateBid)));
jsonObject.put("Balance",rs.getString(rs.getColumnIndex(RateDb.rateBalance)));
jsonArray.put(jsonObject);
//Log.d("MyDebug",rs.getString(rs.getColumnIndex(RateDb.rateName)));
}
}
}
rs.close();
db.close();
RowAAdapter rowAAdapter = new RowAAdapter(getActivity(),jsonArray);
lvMarkets.setAdapter(rowAAdapter);
swipeRefreshLayout.setRefreshing(false);
}
The problem with your code is that :
You're putting the values with keys "rateID", "Name"... etc. in the while loop again and again, so the previous values are being replaced with the new values and finally you've just one set of data in your hashmap. That's why you're getting only the last set of data.
Try the above code. It should work as expected.
This will work as it creates a new JsonObject in the loop and adds it to the jsonArray when the data is successfully added to it.
I'm using parse backend to store and retrieve the datas for my android app, the storing gets done properly but i have problem in retrieving it. I just went through the parse documentation to retrieve the result but what i get is just 0 for all the retrieved values..im suret that the class exists in the parse cloud with valid values but still i get 0 for all the queries.. this is my code to save:
Toast.makeText(getApplicationContext(),"writing to parse",Toast.LENGTH_SHORT).show();
ParseObject dataObject = new ParseObject("Score");
dataObject.put("correct",correctAnswers);
dataObject.put("wrong",wrongAnswers);
dataObject.put("percent", percentage);
dataObject.saveInBackground();
this is how i get back the saved data
ParseQuery<Score> query = ParseQuery.getQuery("Score");
try {
List<Score> scoreList = query.find();
} catch (ParseException e) {
e.printStackTrace();
}
query = ParseQuery.getQuery("Score");
final Activity ctx = this;
query.findInBackground( new FindCallback<Score>() {
#Override public void done(List<Score> scoreList, ParseException e) {
if ( e == null ) {
ParseObject dataObject = ParseObject.create("Score");
int p = dataObject.getInt("correct");
int q = dataObject.getInt("wrong");
int r = dataObject.getInt("percent");
Toast.makeText(ExamRecordActivity.this,String.valueOf(p),Toast.LENGTH_SHORT).show();
Toast.makeText(ExamRecordActivity.this,String.valueOf(q),Toast.LENGTH_SHORT).show();
Toast.makeText(ExamRecordActivity.this,String.valueOf(r),Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(ctx,
"Error updating questions - please make sure you have internet connection",
Toast.LENGTH_LONG).show();
}
}
});
Inside the done method you are creating a new by calling ParseObject dataObject = ParseObject.create("Score"); and then trying to read values from it without putting any in.
I don't know what the structure of your class is but you need to be iterating through List<Score> scoreList in order to get the queried data.
I have a piece of code which basically synchronises data between an online database. However I am getting an error on one particular line of code (map.put("id", obj.get(mydb.WEB_ID).toString());) where an integer value is obtained from the android sqlite databasse and submitted to the online database. The full cose is as displayed below :
public void updateSQLite(String response){
ArrayList<HashMap<String, String>> syncL;
syncL = new ArrayList<HashMap<String, String>>();
// Create GSON object
Gson gson = new GsonBuilder().create();
try {
// Extract JSON array from the response
JSONArray arr = new JSONArray(response);
System.out.println(arr.length());
// If no of array elements is not zero
if(arr.length() != 0){
// Loop through each array element, get JSON object which has userid and username
for (int i = 0; i < arr.length(); i++) {
// Get JSON object
JSONObject obj = (JSONObject) arr.get(i);
System.out.println(obj.get("web_id"));
System.out.println(obj.get("phone_id"));
System.out.println(obj.get("msg_id"));
mydb.updateWebSync(obj.get(obj.get("phone_id").toString(), obj.get("msg_id").toString(), obj.get("web_id").toString());
HashMap<String, String> map = new HashMap<String, String>();
map.put("id", obj.get(mydb.WEB_ID).toString());
map.put("p_id", obj.get(mydb.COLUMN_ID).toString());
map.put("s", "1");
syncL.add(map);
}
updateMySQLSyncSts(gson.toJson(syncL), "syncsts");
Toast.makeText(getApplicationContext(), "Download Messages success!", Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
Toast.makeText(getApplicationContext(), "Download Messages error!", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
In my android sqlite database, the value of mydb.WEB_ID is stored as an integer. Any assistance is appreciated.
Hashmap<String,String>
it only contains String values. So you have to convert it to String.
with using
toString()
function it ll give you error.
Try with
String.ValueOf(obj.get("web_id"))
it ll convert the interger value to String and your problem gets resolved.
Happy coding. :P
I figured out my mistake...I was calling the database column name in the HashMap which is different from the json variable. Thanks all for your assistance.
I have this structure that is generated by my application and I read in a listView:
[{
"phone": "202020",
"name": "Jhon",
"id": 10,
"age": 20
},
{
"phone": "303030",
"name": "Rose",
"id": 11,
"age": 22
}]
When I select an item in the listview, I open a screen form passing the values of the clicked item.
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// getting values from selected ListItem
String name = ((TextView) view.findViewById(R.id.name)).getText().toString();
String age = ((TextView) view.findViewById(R.id.age)).getText().toString();
String phone = ((TextView) view.findViewById(R.id.phone)).getText().toString();
// Starting new intent
Intent in = new Intent(getApplicationContext(), SingleMenuItemActivity.class);
in.putExtra(TAG_NAME, name);
in.putExtra(TAG_AGGE, age);
in.putExtra(TAG_PHONE, phone);
startActivity(in);
}
});
This screen opens when you click on the item is a form where I put the values passed from the previous screen fields.
My question is: When you click save in this form, I have to get the new values and update the json file. How to do this?
Ex: I want to change the record ID 22, which is the user Rose.
ADD MORE INFORMATION:
I already use the Gson to generate items.
Code to generate:
btnSalvar.setOnClickListener( new View.OnClickListener() {
public void onClick(View v) {
gson = new GsonBuilder().setPrettyPrinting().create();
final File file = new File(Environment.getExternalStorageDirectory() + "/download/ibbca/auditar.json");
// to check if file exists before before it maybe will be created
if (file.exists())
fileExists = true;
try{
// create file or get access to file
raf = new RandomAccessFile(file, "rw");
if (fileExists) // start new file as an array
raf.seek(file.length() - 1);
else { // start writing inside the bracket
raf.writeBytes("[");
raf.seek(file.length());
}
UserTestJson obj1 = new UserTestJson();
obj1.setId(10);
obj1.setName("Jhon");
obj1.setAge(20);
obj1.setPhone("202020");
toJson(obj1);
// end file
raf.writeBytes("]");
raf.close();
}catch(FileNotFoundException f){
f.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
And the Class UserTestJson, i created with get and seters for each variable.
The Simplest way is, Just go to that json Object and set the desired value for the key.
JSONArray arr = new JSONArray(str);
for(int i = 0; i < arr.length(); i++){
JSONObject jsonObj = (JSONObject)arr.get(i); // get the josn object
if(jsonObj.getString("name").equals("Rose")){ // compare for the key-value
((JSONObject)arr.get(i)).put("id", 22); // put the new value for the key
}
textview.setText(arr.toString());// display and verify your Json with updated value
}
It's perhaps a good time to switch to an ArrayAdapter.
I recommend to transfer the JSON into a custom model bean first:
class Person {
long id;
String phone, name, age;
}
Then you can use an JSON parser library like gson to parse the array into a List<Person> and use this array to drive your list. (See Gson help with parse array - works without array but won't with array) for an example on the parsing.
Finally, when you are ready to write back the data, simply re-generate the JSON from the array. This question got an example for that: Trouble with Gson serializing an ArrayList of POJO's
Pros:
Once your JSON data model changes, only a small change in your model is needed to read the new format.
You can use standard Java tools like ArrayList and POJOs
Cons:
You will need to import GSON or equivalent into your project.
Also check this question: How to parse JSON in Android
I cant find a direct way to do so.
But you can use this function to solve the problem first. See if there is other solution
private JSONObject setJSONVal(JSONObject jsonObject, String index, String value) throws JSONException{
String jsonString = jsonObject.toString().trim();
jsonString = jsonString.replace("\"" + index + "\":\"" + jsonObject.getString(index) + "\"", "\"" + index + "\":\"" + value + "\"");
return new JSONObject(jsonString);
}