I'm trying to load a lot of data from the web to my android application and I've been getting this error:
07-18 10:16:00.575: E/AndroidRuntime(30117): java.lang.OutOfMemoryError: [memory exhausted]
and already read a lot about JSON. I've found some solutions but nothing really helped me.
This is my code :
public class HistoricoAdapter extends BaseAdapter {
private Context ctx;
JSONArray jsonArray;
public HistoricoAdapter(Context ctx) {
this.ctx = ctx;
String readHttp = readHttp();
try {
// transforma a string retornada pela função readHttp() em array
jsonArray = new JSONArray(readHttp);
} catch (Exception e) {
e.printStackTrace();
}
}
public String readHttp() {
// Acessa a URL que retorna uma string com os dados do banco
StringBuilder builder = new StringBuilder();
HttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet("some url");
try {
HttpResponse response = client.execute(httpGet);
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode == 200) {
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
BufferedReader reader = new BufferedReader(
new InputStreamReader(content));
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
} else {
Log.e(this.toString(), "Erro ao ler JSON!");
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return builder.toString();
}
public int getCount() {
return jsonArray.length();
}
public boolean isEmpty(){
if(jsonArray.toString().isEmpty()){
return true;
}
else {
return false;
}
}
public Object getItem(int position) {
JSONObject ob = null;
try {
ob = jsonArray.getJSONObject(position);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return ob;
}
public long getItemId(int arg0) {
return 0;
}
public View getView(int position, View view, ViewGroup arg2) {
LayoutInflater layout = (LayoutInflater) ctx
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = layout.inflate(R.layout.listar_compromisso, null);
try {
JSONObject obj = (JSONObject) getItem(position);
} catch (Exception ex) {
}
return v;
}
}
Can anyone predict why am I getting this error?
If you get this error then your JSON must be too large to be buffered into memory.
The problem is org.json is too basic to handle that.
You need an advanced library to stream responses instead such as GSON or Jackson.
GSON - Streaming
Jackson - Processing model: Streaming API
There are a few issues with this code. First thing I noticed is your not calling your web request inside of an asynctask. You want to use async task for all long running operations and you have to use it for web calls.
AsyncTask must be subclassed to be used. The subclass will override at least one method (doInBackground(Params...), and most often will override a second one
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
You should also use JSON to build your object object. It has been tested and you can find information about how much objects can handle under there documentation. Here is a little bit of information from there site:
Gson Performance and Scalability
Here are some metrics that we obtained on a desktop (dual opteron, 8GB RAM, 64-bit Ubuntu) running lots of other things along-with the tests. You can rerun these tests by using the class PerformanceTest.
Strings: Deserialized strings of over 25MB without any problems (see disabled_testStringDeserializationPerformance method in PerformanceTest)
Large collections:
Serialized a collection of 1.4 million objects (see disabled_testLargeCollectionSerialization method in PerformanceTest)
Deserialized a collection of 87,000 objects (see disabled_testLargeCollectionDeserialization in PerformanceTest)
Gson 1.4 raised the deserialization limit for byte arrays and collection to over 11MB from 80KB.
Also, build your class objects using Json to Java object convert like there one. There are many more if this link doesnt end of working later on. Do a simple Google search.
Convert from json to Java Objects but you can also convert to your own custom objects.
Gson gson = new Gson();
int[] ints = {1, 2, 3, 4, 5};
String[] strings = {"abc", "def", "ghi"};
(Serialization)
gson.toJson(ints); ==> prints [1,2,3,4,5]
gson.toJson(strings); ==> prints ["abc", "def", "ghi"]
Related
I'm trying to build a very basic weather app in android studio. I am using AsyncClass to return multiple strings.
As you can see in the code, I used a class named "Wrapper" that is used to store my strings so I can just return a class object and use it in the onPostExecute method of the AsyncTask. The problem I am facing is that when I test the app, all of the returned Strings somehow are undefined (the default for the Wrapper class). This means the strings are not being updated in the doInBackground method and I can't seem to figure out why!
My Activity
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.i(MainActivity.class.getSimpleName(), "Can't connect to Google Play Services!");
}
private class Wrapper
{
String Temperature = "UNDEFINED";
String city = "UNDEFINED";
String country = "UNDEFINED";
}
private class GetWeatherTask extends AsyncTask<String, Void, Wrapper> {
private TextView textView;
public GetWeatherTask(TextView textView) {
this.textView = textView;
}
#Override
protected Wrapper doInBackground(String... strings) {
Wrapper w = new Wrapper();
String Temperature = "x";
String city = "y";
String country = "z";
try {
URL url = new URL(strings[0]);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
InputStream stream = new BufferedInputStream(urlConnection.getInputStream());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream));
StringBuilder builder = new StringBuilder();
String inputString;
while ((inputString = bufferedReader.readLine()) != null) {
builder.append(inputString);
}
JSONObject topLevel = new JSONObject(builder.toString());
JSONObject main = topLevel.getJSONObject("main");
JSONObject cityobj = topLevel.getJSONObject("city");
Temperature = String.valueOf(main.getDouble("temp"));
city = cityobj.getString("name");
country = cityobj.getString("country");
w.Temperature= Temperature;
w.city= city;
w.country=country;
urlConnection.disconnect();
} catch (IOException | JSONException e) {
e.printStackTrace();
}
return w;
}
#Override
protected void onPostExecute(Wrapper w) {
textView.setText("Current Temperature: " + w.Temperature + " C" + (char) 0x00B0
+"\n" + "Current Location: "+ w.country +"\n" + "City: "+ w.city );
}
}
}
UPDATE:
turned out that that I was using the wrong url in my code,I was using :
http://api.openweathermap.org/data/2.5/weather?lat=%f&lon=%f&units=%s&appid=%s
Instead I should've been using:
http://api.openweathermap.org/data/2.5/forecast?lat=%f&lon=%f&units=%s&appid=%s
-aka instead of weather I should've been using forcast
Your error starts here
JSONObject main = topLevel.getJSONObject("main");
Probably because the topLevel object has no "main" key.
{
"city":{ },
"cod":"200",
"message":0.1859,
"cnt":40,
"list":[ ]
}
Throw your JSON into here. https://jsonformatter.curiousconcept.com/
You'll notice that there are many, many "main" keys that are within the "list" element, but you have to parse those starting from getJSONArray("list").
Basically, something like this
String city = "undefined";
String country = "undefined";
List<Double> temperatures = new ArrayList<Double>();
try {
JSONObject object = new JSONObject(builder.toString());
JSONObject jCity = object.getJSONObject("city");
city = jCity.getString("name");
country = jCity.getString("country");
JSONArray weatherList = object.getJSONArray("list");
for (int i = 0; i < weatherList.length(); i++) {
JSONObject listObject = weatherList.getJSONObject(i);
double temp = listObject.getJSONObject("main").getDouble("temp");
temperatures.add(temp);
}
} catch (JSONException e) {
e.printStackTrace();
}
return new Wrapper(city, country, temperatures);
After studying your code, either your try block is failing, which is returning your object, but empty, or there is something wrong with your JSON parsing. If you could show us the JSON you are trying to parse that would be a great help.
That being said, the fact that it is still showing as "UNDEFINED" is because that is how you initialised it, and becuase (the JSON parse is likely failing), the object is being returned in an un-edited state.
EDIT:
You are parsing the JSON wrong. You are trying to find an object called "main" in the top directory, however the main object only exists inside of an array called list!
Please look here for a more easy to see and visual representation: http://prntscr.com/dlhlrk
You can use this site to help visualise your JSON and create an appropriate soluton based upon it. https://jsonformatter.curiousconcept.com/
Looking at the API you posted earlier (api.openweathermap.org) you are trying to access variables that don't exist. I suggest you have a look at what the API returns and try getting the variables one by one if you are getting a JSONException
EDIT:
What API you are using? In your initial post you said it was http://api.openweathermap.org/data/2.5/weather but in a comment above you said it was http://api.openweathermap.org/data/2.5/forecast.
If you're using the weather API (as initially stated) you can use the below:
#Override
protected Wrapper doInBackground(String... strings) {
Wrapper w = new Wrapper();
try {
URL url = new URL(strings[0]);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
InputStream stream = new BufferedInputStream(urlConnection.getInputStream());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream));
StringBuilder builder = new StringBuilder();
String inputString;
while ((inputString = bufferedReader.readLine()) != null) {
builder.append(inputString);
}
Log.d("JSON", builder.toString());
JSONObject topLevel = new JSONObject(builder.toString());
JSONObject main = topLevel.getJSONObject("main");
JSONObject sys = topLevel.getJSONObject("sys");
w.Temperature = String.valueOf(main.getDouble("temp"));
w.city = topLevel.getString("name");
w.country = sys.getString("country");
urlConnection.disconnect();
} catch (IOException | JSONException e) {
e.printStackTrace();
}
return w;
}
I developing android app and now I have problem. Below is a part of my code, and it keeps skipping the "for" part. When I put a breakpoint inside for statement, it stops at the point, and executes the lines very well and makes an output that I want. When I just 'run' app, it skips that part so "String locations" value doesn't change. I googled and some say it's thread-related problem. So I put synchroinzed on the method, still not working. Any other suggestions?
UPDATE
I was trying to show code only related to the problem, but I think now showing the whole would be more useful for those who try to help so here's my entire code on showMapActivity. You can see I've tried some ways around and nothing worked. Saving path's information into String url is where I'm having problem. I tested, and other parts seem to work fine. I know my code is really massy, that was why I only posted parts of the code. TMap related classes are imported from .jar file.
public class showMapActivity extends Activity {
TMapData tmapdata=new TMapData();
TMapView tmapView;
TMapPoint origin, dest;
volatile ArrayList<TMapPoint> points=new ArrayList<>();
private TextView x;
private TextView y;
private HashMap<String,LatLng> coordinates;
private HashMap<LatLng,Double> finalpoint;
static private ConcurrentHashMap<Double,Double> path;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_map);
coordinates=new HashMap<>();
Intent intent=getIntent();
tmapView=new TMapView(this);
path=new ConcurrentHashMap<>();
coordinates=(HashMap<String,LatLng>)intent.getSerializableExtra("coordinate");
path=getPathPoints(coordinates);
int i=0;
String url=getUrl();
//String url = "https://maps.googleapis.com/maps/api/elevation/json?locations=";
//String locations="";
/*
Iterator<Double> keys= path.keySet().iterator();
while(keys.hasNext()){
Double key=keys.next();
//String lat=String.valueOf(key);
//String lng=String.valueOf(path.get(key));
locations=locations+String.valueOf(key)+","+String.valueOf(path.get(key));
if(keys.hasNext())
locations=locations+"|";
}path.entrySet()
*/
/*
for(ConcurrentHashMap.Entry<Double,Double> elem : path.entrySet())
{
String lat=String.valueOf(elem.getKey());
String lng=String.valueOf(elem.getValue());
locations=locations+lat+","+lng;
i++;
if(i!=path.size())
{
locations=locations+"|";
}
}
*/
//url=url+locations+"&key=AIzaSyDD88VFMPIfC5sr0XsFL0PDCE-QRN8gQto";
//String url=getUrl(path);
FetchUrl fetchUrl=new FetchUrl();
fetchUrl.execute(url);
}
private ConcurrentHashMap<Double,Double> getPathPoints(HashMap<String,LatLng> coordinates)
{
final ConcurrentHashMap<Double,Double> Path=new ConcurrentHashMap<>();
tmapView.setSKPMapApiKey("6bb5b7f3-1274-3c5e-ba93-790aee876673");
origin=new TMapPoint(coordinates.get("origin").latitude,coordinates.get("origin").longitude);
dest=new TMapPoint(coordinates.get("dest").latitude,coordinates.get("dest").longitude);
tmapdata.findPathData(origin, dest, new TMapData.FindPathDataListenerCallback() {
#Override
public void onFindPathData(TMapPolyLine polyLine) {
points=polyLine.getLinePoint();
for(TMapPoint point : points )
Path.put(point.getLatitude(),point.getLongitude());
}
});
return Path;
}
//ConcurrentHashMap<Double,Double> path
private synchronized String getUrl() {
int i=0;
String url = "https://maps.googleapis.com/maps/api/elevation/json?locations=";
String locations="";
for(HashMap.Entry<Double,Double> elem : path.entrySet())
{
String lat=String.valueOf(elem.getKey());
String lng=String.valueOf(elem.getValue());
locations=locations+lat+","+lng;
i++;
if(i!=path.size())
{
locations=locations+"|";
}
}
url=url+locations+"&key=AIzaSyDD88VFMPIfC5sr0XsFL0PDCE-QRN8gQto";
//https://maps.googleapis.com/maps/api/elevation/json?locations=
// 39.7391536,-104.9847034|36.455556,-116.866667&key=AIzaSyDD88VFMPIfC5sr0XsFL0PDCE-QRN8gQto
// Output format
return url;
}
private class FetchUrl extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... url) {
// For storing data from web service
String data = "";
try {
// Fetching the data from web service
//downloadURL
data = downloadUrl(url[0]);
Log.d("Background Task data", data.toString());
} catch (Exception e) {
Log.d("Background Task", e.toString());
}
return data;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
//ParserTask
ParserTask parserTask = new ParserTask();
// Invokes the thread for parsing the JSON data
parserTask.execute(result);
}
}
private String downloadUrl(String strUrl) throws IOException {
String data = "";
InputStream iStream = null;
HttpURLConnection urlConnection = null;
try {
URL url = new URL(strUrl);
// Creating an http connection to communicate with url
urlConnection = (HttpURLConnection) url.openConnection();
// Connecting to url
urlConnection.connect();
//읽은 데이터를 버퍼에 저장
// Reading data from url
iStream = urlConnection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(iStream));
StringBuffer sb = new StringBuffer();
String line = "";
while ((line = br.readLine()) != null) {
sb.append(line);
}
data = sb.toString();
Log.d("downloadUrl", data.toString());
br.close();
} catch (Exception e) {
Log.d("Exception", e.toString());
} finally {
iStream.close();
urlConnection.disconnect();
}
return data;
}
private class ParserTask extends AsyncTask<String, Integer, ArrayList<Double>> {
// Parsing the data in non-ui thread
#Override
protected ArrayList<Double> doInBackground(String... jsonData) {
JSONObject jObject;
ArrayList<Double> altitude = null;
try {
jObject = new JSONObject(jsonData[0]);
Log.d("ParserTask",jsonData[0].toString());
//DataParser class 호출
DataParser parser = new DataParser();
Log.d("ParserTask", parser.toString());
// Starts parsing data
altitude = parser.parse(jObject);
Log.d("ParserTask","Getting Altitudes");
Log.d("ParserTask",altitude.toString());
} catch (Exception e) {
Log.d("ParserTask",e.toString());
e.printStackTrace();
}
return altitude;
}
// Executes in UI thread, after the parsing process
#Override
protected void onPostExecute(ArrayList<Double> result) {
finalpoint=new HashMap<>();
LatLng latLng;
int i=0;
for(HashMap.Entry<Double,Double> elem : path.entrySet() )
{
latLng=new LatLng(elem.getKey(),elem.getValue());
finalpoint.put(latLng,result.get(i++));
}
x = (TextView) findViewById(R.id.textView5);
y = (TextView) findViewById(R.id.textView6);
x.setText(String.valueOf(finalpoint.get(coordinates.get("origin"))));
y.setText(String.valueOf(finalpoint.get(coordinates.get("dest"))));
}
}
}
(Apologies for posting this as an answer - I don't yet have the required reputation to comment)
Simply adding synchronized to a method doesn't necessarily guarantee thread safety.
How and when is path being populated?
Update after additional information provided
The problem seems to be that the path points are being generated asynchronously, and you are trying to use them before the generation process has finished (or perhaps even started). This happens because the findPathData simply starts the generation process and returns immediately (i.e. before the generation process has finished). In your code, you then go on and build the URL which is supposed to contain the point data immediately. At this point the background point generation process may not have finished, and may not have even started. As a result the point map may be empty or incomplete, and your URL will not be generated as you expect.
You need to find a way to wait until all of the path point data has been returned by the asynchronous processing before creating the URL. This looks like it could be very difficult, if not impossible, with the version of the findPathData method you are using, because it returns points via the callback one at a time and you may not know how many will be generated.
I had a quick look at the API for TMapData and it has a findPathDataAll method which seems to generate all the points and return them in a single callback call rather than one by one. If this is indeed what it does (sorry, I can't read Korean), you could use this method and then generate the URL from the callback, because when it's called you know that the generation process has been completed. If you do this, be careful to make sure that you're on the main thread before interacting with the UI or Activity.
Hope that helps.
Unfortunately I'm facing some issues when I try to upload some images from an android device to a database.
The images are in a folder. This folder contains images as well as other stuff. I don't know the names of the images and I need to upload only the images(jpg). Before I upload the images I need to encode them with base64.
First I get the jpg files from the folder. Then I get the ID out of the image name. After that I encode it via base64:
Button upload = (Button) findViewById(R.id.upload);
upload.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
String path = Environment.getExternalStorageDirectory().getPath();
File dir = new File(path);
File[] files = dir.listFiles();
for (int i = 0; i < files.length; ++i) {
if (files[i].getName().endsWith(".jpg")) {
pics = new File(String.valueOf(files[i]));
id = String.valueOf(files[i]);
String sub = id.substring(id.lastIndexOf("/") + 1);
int index = sub.indexOf("_");
String book;
if (index >= 0) {
book = sub.substring(0, index);
ID = book;
Log.e("ID", ID);
}
Bitmap imagex = BitmapFactory.decodeFile(pics.getAbsolutePath());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
imagex.compress(Bitmap.CompressFormat.JPEG, 70, baos);
byte[] b = baos.toByteArray();
Image = Base64.encodeToString(b, Base64.DEFAULT);
try {
new HttpAsyncTask(ID,Image,Nummer).execute("https://....");
} catch (Exception e) {
Log.e("InputStream", e.getMessage());
}
Log.e("PICS", id);
}
}
}
});
public String POST(String url) {
InputStream inputStream;
try {
HttpClient httpclient = classxy.getNewHttpClient();
HttpPost httpPost = new HttpPost(url);
String json = "";
JSONObject jsonObject = new JSONObject();
jsonObject.put("bookId", ID);
jsonObject.put("imageString", Image);
jsonObject.put("imageNumber", Nummer);
json = jsonObject.toString();
StringEntity se = new StringEntity(json);
httpPost.setEntity(se);
httpPost.setHeader("Apikey", data);
httpPost.setHeader("Modul", "upload_image");
HttpResponse httpResponse = httpclient.execute(httpPost);
inputStream = httpResponse.getEntity().getContent();
if (inputStream != null)
result = classxy.convertInputStreamToString(inputStream);
else
result = "Fehler!";
} catch (Exception e) {
Log.e("InputStream", e.getLocalizedMessage());
}
int num = Integer.parseInt(Nummer);
num++;
Nummer = Integer.toString(num);
return result;
}
public class HttpAsyncTask extends AsyncTask<String, Void, String> {
private final Object ID, Image, Nummer;
public HttpAsyncTask(Object ID, Object Image, Object Nummer) {
this.ID = ID;
this.Image = Image;
this.Nummer = Nummer;
}
protected String doInBackground(String... urls) {
return POST(urls[0]);
}
protected void onPostExecute(String result) {
if (result.matches("(.*)false(.*)")) {
Toast.makeText(getApplicationContext(), "....", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "...", Toast.LENGTH_SHORT).show();
}
Log.e("RESPONSE", result);
}
}
It does encode the images via base64 and it does upload some of the images. Unfortunately it uploads only the first image or one image multiple times. It never uploads the correct amount of images in the correct order. I've been sitting on this problem for a while now and can't figure out what I'm doing wrong.
Can you tell me what I'm doing wrong?
Your program doesn't seem to be thread-safe at all.
Your fields ID, Image and Nummer are updated with every iteration of the for loop. Most likely the loop has already finished before POST runs for the first time. Your observation would support this assumption:
Unfortunately it uploads only the first image or one image multiple times.
You can observe this by logging every access to these fields. You'll find, that it's not alternating like you expect it to be.
Therefore you should implement everything without using these fields at all. Instead use local variables and pass these around. Using the Nummer field could be usefull if you want to use it for more than one upload. But it might be better to use an int directly:
upload.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
String ID = "", Image;
int Nummer = 0;
[...]
for (int i = 0; i < files.length; ++i) {
if (files[i].getName().endsWith(".jpg")) {
[...]
try {
new HttpAsyncTask(ID,Image,Integer.toString(Nummer++)).execute("https://....");
} catch (Exception e) {
Log.e("InputStream", e.getMessage());
}
Log.e("PICS", id);
}
}
}
});
public String POST(String url, String ID, String Image, String Nummer) {
InputStream inputStream;
try {
[...]
} catch (Exception e) {
Log.e("InputStream", e.getLocalizedMessage());
}
//int num = Integer.parseInt(Nummer);
//num++;
//Nummer = Integer.toString(num);
return result;
}
public class HttpAsyncTask extends AsyncTask<String, Void, String> {
private final String ID, Image, Nummer;
public HttpAsyncTask(String ID, String Image, String Nummer) {
this.ID = ID;
this.Image = Image;
this.Nummer = Nummer;
}
protected String doInBackground(String... urls) {
return POST(urls[0], ID, Image, Nummer);
}
protected void onPostExecute(String result) {
[...]
}
}
In My suggestion Dont call Asynctask directly from for loop because there are no any monitor on we can set for which image selected.
So Go through below steps:
1) In for loop get all images ID,Name and number and store it to ArrayList
2) Check ArrayList first is empty or not
if not then get first position ID, Image and number
call new HttpAsyncTask(ID,Image,Integer.toString(Nummer++)).execute("https://....");
3) In HttpAsyncTask onPostExecute(String result) method
first remove first position data
then create
for loop (i=0;i<ArrayList.Size();i++) {
ID=ArrayList first position data ID
Image=ArrayList first position data IMAGE
number=ArrayList first position data number
Call new HttpAsyncTask(ID,Image,Integer.toString(Nummer++)).execute("https://....");
}
So here first Image send by then after second then after third up to your list not empty and every time different image selected.
Thats it...
I have used httpclient to call a restapi written in django. It returned the json output. My httpresponse variable stored it and later convert the reponse to string and then to json object, i think its lengthy though it is working . I am really new to java , can anybody advise me , what is the best alternative logic to the code below
public void onClick(View v) {
// TODO Auto-generated method stub
HttpClient httpclient = new DefaultHttpClient();
HttpGet httppost = new HttpGet("http://10.0.2.2:8000/api/ca/entry/?
format=json&username=pragya");
try {
// Add your data
//List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
//nameValuePairs.add(new BasicNameValuePair("username", un.getText().toString()));
//nameValuePairs.add(new BasicNameValuePair("username", pw.getText().toString()));
//httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append((line + "\n"));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
JSONObject jsonObject = new JSONObject(sb.toString());
JSONObject meta = jsonObject.getJSONObject("meta");
String limit = meta.getString("limit");
Toast.makeText(HelloWorldActivity.this, limit, Toast.LENGTH_SHORT).show();
JSONArray array = jsonObject.getJSONArray("objects");
String key = array.getJSONObject(0).getString("api_key");
String uname = array.getJSONObject(0).getString("username");
Toast.makeText(HelloWorldActivity.this, uname + " " + key,
Toast.LENGTH_SHORT).show();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Toast.makeText(HelloWorldActivity.this, sb.toString(), Toast.LENGTH_SHORT).show();
} catch (ClientProtocolException e) {
Toast.makeText(HelloWorldActivity.this, e.toString(), Toast.LENGTH_SHORT).show();
// TODO Auto-generated catch block
} catch (IOException e) {
// TODO Auto-generated catch block
Toast.makeText(HelloWorldActivity.this, e.toString(), Toast.LENGTH_SHORT).show();
}
}
});
the json is as follows
{"meta": {"limit": 20, "next": null, "offset": 0, "previous": null, "total_count": 1}, "objects": [{"api_key": "c87391754b522d0c83b2c8b5e4c8cfd614559632deee70fdf1b48d470307e40e", "homeAddress": "kathmandu", "resource_uri": "/api/ca/entry/1/", "username": "sumit"}]}
Use Gson library from google, it is perfect for these kind of tasks.
All you need to do is define a new class that contains fields with the names of the keys in the json object and then use Gson to parse the Json string directly into the object or vice versa.
So for example:
Json looks like this: "limit": 20, "next": null, "offset": 0, "previous": null, "total_count": 1.
Java Class will be:
public class MyClass {
private int limit;
private int next;
private int offset;
private int previous;
private int total_count;
public int getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
public int getNext() {
return next;
}
public void setNext(int next) {
this.next = next;
}
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
public int getPrevious() {
return previous;
}
public void setPrevious(int previous) {
this.previous = previous;
}
public int getTotal_count() {
return total_count;
}
public void setTotal_count(int total_count) {
this.total_count = total_count;
}
}
And use Gson code like that:
Gson gson = new Gson(); // Or use new GsonBuilder().create();
MyClass myClass = gson.fromJson(json, MyClass.class); // deserializes json into MyClass
Please note that the name of the class fields have to match exactly the name of the keys in the json string.
Always perform lengthy non-UI task using AsyncTask. All the operations you described, fetching of json and parsing them, can be performed in AsyncTask. Write the entire code which you have currently written in onClick event and write it doInBackground() of an AsyncTask.
Check the following for more details:
http://developer.android.com/reference/android/os/AsyncTask.html
How do I get the data from my AsyncTask? My MainActivity is calling the DataCall.getJSON function that triggers the AsyncTask but I am not sure how to get the data back to the original Activity.
MainActivity with call to DataCall that should return a string and save it in state_data
String state_data = DataCall.getJSON(spinnerURL,spinnerContentType);
DataCall:
public class DataCall extends Activity {
private static final String TAG = "MyApp";
private class DownloadWebPageTask extends AsyncTask<String, Void, String> {
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(
new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return response;
}
protected void onPostExecute(String result) {
//THIS IS WHERE I NEED TO RETURN MY DATA TO THE MAIN ACTIVITY. (I am guessing)
}
}
public void getJSON(String myUrlString, String contentType) {
DownloadWebPageTask task = new DownloadWebPageTask();
task.execute(new String[] { "http://www.mywebsite.com/" + myUrlString });
}
}
modify your AsyncTask as below:
public class GetData extends AsyncTask<String, Void, String>
{
DataDownloadListener dataDownloadListener;
public GetData()
{
//Constructor may be parametric
}
public void setDataDownloadListener(DataDownloadListener dataDownloadListener) {
this.dataDownloadListener = dataDownloadListener;
}
#Override
protected Object doInBackground(Object... param)
{
// do your task...
return null;
}
#Override
protected void onPostExecute(Object results)
{
if(results != null)
{
dataDownloadListener.dataDownloadedSuccessfully(results);
}
else
dataDownloadListener.dataDownloadFailed();
}
public static interface DataDownloadListener {
void dataDownloadedSuccessfully(Object data);
void dataDownloadFailed();
}
}
and use it in your Activity
GetData getdata = new GetData();
getdata.setDataDownloadListener(new DataDownloadListener()
{
#SuppressWarnings("unchecked")
#Override
public void dataDownloadedSuccessfully(Object data) {
// handler result
}
#Override
public void dataDownloadFailed() {
// handler failure (e.g network not available etc.)
}
});
getdata.execute("");
NOTE: For the people who are reading this.
Please consider this post for the best and perhaps right implementation.
The key for me was to create a class called URLWithParams or something because AsyncTask will allow only 1 type to be sent IN, and I needed both the URL and the params for the HTTP request.
public class URLWithParams {
public String url;
public List<NameValuePair> nameValuePairs;
public URLWithParams()
{
nameValuePairs = new ArrayList<NameValuePair>();
}
}
and then I send it to a JSONClient:
public class JSONClient extends AsyncTask<URLWithParams, Void, String> {
private final static String TAG = "JSONClient";
ProgressDialog progressDialog ;
GetJSONListener getJSONListener;
public JSONClient(GetJSONListener listener){
this.getJSONListener = listener;
}
#Override
protected String doInBackground(URLWithParams... urls) {
return connect(urls[0].url, urls[0].nameValuePairs);
}
public static String connect(String url, List<NameValuePair> pairs)
{
HttpClient httpclient = new DefaultHttpClient();
if(url == null)
{
Log.d(TAG, "want to connect, but url is null");
}
else
{
Log.d(TAG, "starting connect with url " + url);
}
if(pairs == null)
{
Log.d(TAG, "want to connect, though pairs is null");
}
else
{
Log.d(TAG, "starting connect with this many pairs: " + pairs.size());
for(NameValuePair dog : pairs)
{
Log.d(TAG, "example: " + dog.toString());
}
}
// Execute the request
HttpResponse response;
try {
// Prepare a request object
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(new UrlEncodedFormEntity(pairs));
response = httpclient.execute(httpPost);
// Examine the response status
Log.i(TAG,response.getStatusLine().toString());
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
String json = reader.readLine();
return json;
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String json ) {
getJSONListener.onRemoteCallComplete(json);
}
public interface GetJSONListener {
public void onRemoteCallComplete(String jsonFromNet);
}
}
Then call it from my main class like this
public class BookCatalog implements GetJSONListener {
private final String TAG = this.getClass().getSimpleName();
private String catalog_url = "URL";
private void getCatalogFromServer() {
URLWithParams mURLWithParams = new URLWithParams();
mURLWithParams.url = catalog_url;
try {
JSONClient asyncPoster = new JSONClient(this);
asyncPoster.execute(mURLWithParams);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void onRemoteCallComplete(String jsonBookCatalogList) {
Log.d(TAG, "received json catalog:");
Log.d(TAG, jsonBookCatalogList);
JSONObject bookCatalogResult;
try {
bookCatalogResult = (JSONObject) new JSONTokener(jsonBookCatalogList).nextValue();
JSONArray books = bookCatalogResult.getJSONArray("books");
if(books != null) {
ArrayList<String> newBookOrdering = new ArrayList<String>();
int num_books = books.length();
BookCatalogEntry temp;
DebugLog.d(TAG, "apparently we found " + Integer.toString(num_books) + " books.");
for(int book_id = 0; book_id < num_books; book_id++) {
JSONObject book = books.getJSONObject(book_id);
String title = book.getString("title");
int version = book.getInt("price");
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
Although i disagree creating a new activity for that simple task there is
startActivityForResult()
to get data from another activity.
Check this. You can store your data to the Intent's extras. But still if you have a large amount of data you better off write it to a file get the result from the other activity that is done downloading and then read the file.
Serialize it and then read it. The only way I'm aware of.
Some options:
a) Make your bean implement Serializable interface, you can then pass your bean through Intent.
b) Implement Application interface (you need to make an entry in manifest), Have setter\getter method in your Application class. You can set your bean in Application from AsyncTask and later retrieve from Activity.
Sorry for answering so late, i think by this time you might have solved this problem. when i was searching for something else, i came across your question. I'm pasting a link here which might of some help for others.