Second Activity in my project starts very slow, and I don't know how to fix it. How it works (everything's in onCreate()): firstly it does get-request to the page with json:
try {
DefaultHttpClient hc = new DefaultHttpClient();
ResponseHandler<String> res = new BasicResponseHandler();
HttpGet getMethod = new HttpGet(url);
String response = hc.execute(getMethod, res);
resStr = response.toString();
} catch (Exception e) {
System.out.println("Exp=" + e);
}
I know some methods from here are deprecated, but I don't know how to make it more optimized. As a result it returns a string with JSON array of about 32 Objects.
Then I fill 6 arrays to pass them to ArrayAdapter for filling ListView. Methods of getting different types of data looks like this:
public static String GetWantedType(String resStr, int num) {
String jsonvalues = "";
try {
JSONArray json_Array = new JSONArray(resStr);
JSONObject json_data = json_Array.getJSONObject(num);
jsonvalues = json_data.getString("wanted_type");
} catch (JSONException e) {
e.printStackTrace();
}
return jsonvalues;
}
Maybe I should have created json_Array one time outside filling arrays and just pass it to those methods as a JSONArray, not as a string - I don't know if it influence the speed.
In the ArrayAdapter everything seems to be all right, I'm using ViewHolder and my scrolling is excelent. Unlike starting Activity.
How to make it better and more optimized?
First, don't do all operations in onCreate() , prefer to do in onResume()
Second, all server call should be in background thread using Async and use result for displaying user.
If you don't want to call multiple times API for data during onResume() and onPause(), you can consume result of data in array or something and when onResume() call, you can check whether it has data, just load it, else fetch from server.
As Gaurav said the problem is that the network request is called on the main thread.
At the time you ask a network call your program say : OK STOP I WAIT THE RESPONSE.
So if you want to change this you can do various things.
For example you can use a Asynchronous Network call with a lib (loopj lib)
or you can simply open a Thread : do the network call.
With that your UI will not freeze
Are you doing the network call on the main thread? Please don't do it. Instead do the network operations on different thread.
For networking you can use a library retrofit.
It also makes it easy for you do the operations asynchronously, by using callbacks or using Observables from RxJava
Related
I have an Android application that makes some requests on the server and also for sending data via web service, using the Volley library.
The data sent by the application are received by an API, and when there is confirmation, the API returns a specific value.
My problem is that I'm not getting this specific return from the API. How do I get this return, not only the server response 200 return that is received by library default?
You need to override parseNetworkResponse(NetworkResponse response)
Exemple :
#Override
protected Response<Bitmap> parseNetworkResponse(NetworkResponse response) {
// Serialize all decode on a global lock to reduce concurrent heap usage.
try {
return doParse(response); //your parser function
} catch (OutOfMemoryError e) {
//..Catch
}
}
Take a look to the doc.
Hope it helps,
I am facing an issue calling .net .asmx web service with parameter using android volley library.
Without parameter its working fine.
This my web service
[WebMethod]
private string MN_InsEOMTestScoreDetailsIndividual(string data)
{
ArrayList arrReturnDetails = new ArrayList();
bool bReturn = false;
string errMsg = globalErrMsg;
try
{
Dictionary<string, object> dicData = JsonConvert.DeserializeObject<Dictionary<string, object>>(data);
bReturn = InsEOMTestScoreDetailsIndividual(dicData["eomTSIndvlDetId"].ToString().Trim(), dicData["eomTRDetId"].ToString().Trim(), dicData["eomTSSummDetId"].ToString().Trim(),
dicData["studCode"].ToString().Trim(), dicData["ctrCode"].ToString().Trim(), dicData["batCode"].ToString().Trim(), dicData["phCode"].ToString().Trim(), dicData["pcCode"].ToString().Trim(),
dicData["tmCode"].ToString().Trim(), dicData["testActualDur"].ToString().Trim(),
dicData["testAttemptDur"].ToString().Trim(), dicData["testTtlMks"].ToString().Trim(), dicData["mksObt"].ToString().Trim(), dicData["ttlQues"].ToString().Trim(),
dicData["rAnsCnt"].ToString().Trim(), dicData["wAnsCnt"].ToString().Trim(), dicData["attemptTestDate"].ToString().Trim(),
dicData["isSolViewed"].ToString().Trim(), dicData["quesXML"].ToString().Trim(), out errMsg);
}
catch (Exception ex)
{
ErrorHandler.LogError("WebService:APP_UserActivityDetails", "M_InsEOMTestScoreDetailsIndividual", ex);
}
arrReturnDetails.Add(new
{
b = bReturn,
err = errMsg
});
return JsonConvert.SerializeObject(arrReturnDetails);
}
Your web service is probably a GET web service which you are trying to invoke as POST. That won't work. There are two ways to correct this:
Make sure your web service is of POST type and then add your parameters as a HashMap in the Volley request.
If you want to keep the web service as a GET, then append the parameters manually to the URL string (i.e. don't pass them as key-value pairs in a HashMap).
i want to call 3 service methods (A B and C) back to back. The important point is B must be called after response received from A and same situation between B and C as well. I add all of requests to queue using RequestQueue.add(...). But now request B is called before receiving response from A. Is it possible to manage this using volley library.
I know i can do request B after receiving response from A but i want to know can volley does this work.
You can implement your own Response listener so you can call A to B and B to C in the response callback method.
There is a simple example here: https://stackoverflow.com/a/17278867/508126
Volley can't do it itself but it can do it if you implement Response.Listener and add your logic in it
You can't give request an order, but you can make them run one after another. For this you need to implement your own RequestQueue.
Here is sample which demonstrates how to make all your requests execute in the same order, in which you added them to queue, since it uses single thread execution.
// Copied from Volley.newRequestQueue(..); source code
File cacheDir = new File(context.getCacheDir(), "def_cahce_dir");
String userAgent = "volley/0";
try {
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (PackageManager.NameNotFoundException e) {
}
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
// Prior to Gingerbread, HttpUrlConnection was unreliable.
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
int threadPoolSize = 1; // means only one request at a time
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network, threadPoolSize);
queue.start();
I am creating an android app for my facebook page. The app is supposed to display random statuses(not just the recent ones) from the facebook page. Is there anyway I could do this?
I haven't done anything of that kind ever, but I think you can gran some logic from this and get it to work.
Step 1:
Make a call to the Facebook API, get all Status Updates and in a for loop, add them to an ArrayList<String>. For example, Facebook returns its data in JSON format. I am assuming, you already know how to fetch data. You need to parse the "message" tag from the JSON data returned by your Facebook API call.
For example:
ArrayList<String> arrStatusMessage;
for (int i = 0; i < JAFeeds.length(); i++) {
JSONObject JOFeeds = JAFeeds.getJSONObject(i);
if (JOFeeds.has("message")) {
String strStatusMessage = JOFeeds.getString("message");
arrStatusMessage.add(strStatusMessage );
}
}
Step 2:
Once you have your entire set of Facebook Status Messages, you will now need to use a java.util.Random instance.
For example: (Please note: I have not tested this code and it might result in errors. You may have to play around with it a bit to get it to work. :-( )
private static final Random randomGenerator = new Random();
int intRandom = randomGenerator.nextInt(arrStatusMessage.size());
String strRandomStatus = arrStatusMessage.get(intRandom);
Step 3:
Use the strRandomStatus to set it on a TextView.
For example:
TextView txtRanStatus = (TextView) findViewById(R.id.txtRanStatus);
txtRanStatus.setText(strRandomStatus);
You haven't posted any code, so it is difficult to provide something that fits in your scheme of things. But I think this should get you started. You will, possibly, need to adapt a few things and fit them in your own code.
Hope this helps.
EDIT: As per a comment by th OP, adding some bits of code to fetch Facebook Status Messages:
in your onCreate() method:
Start a new AsyncTask:
new getFacebookFeeds().execute();
I use this method in my app to make the Facebook Call to get all feeds from the Graph API.
private class getFacebookFeeds extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
String URL = "https://graph.facebook.com/me/home&access_token=ACCESS_TOKEN?limit=10";
try {
HttpClient hc = new DefaultHttpClient();
HttpGet get = new HttpGet(URL);
HttpResponse rp = hc.execute(get);
if (rp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String result = EntityUtils.toString(rp.getEntity());
// GET THE INTIAL RESULTS JSON ROOT
JSONObject JORoot = new JSONObject(result);
// GET THE "DATA" TAG FOR FEEDS ROOT
JSONArray JAFeeds = JORoot.getJSONArray("data");
for (int i = 0; i < JAFeeds.length(); i++) {
JSONObject JOFeeds = JAFeeds.getJSONObject(i);
if (JOFeeds.has("message")) {
String strStatusMessage = JOFeeds.getString("message");
arrStatusMessage.add(strStatusMessage );
}
}
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
You can do the remaining code, where you select a random Status Update, in the onPostExecute() of the AsyncTask shown above:
#Override
protected void onPostExecute(Void result) {
int intRandom = randomGenerator.nextInt(arrStatusMessage.size());
String strRandomStatus = arrStatusMessage.get(intRandom);
txtRanStatus.setText(strRandomStatus);
}
Declare the TextView as a Global Variable and cast it on your onCreate() before calling the AsyncTask. I think this should work just fine. Let me know how it goes. :-)
I'm trying to get the user's cover photo and show it at the top of a layout. I'm using AsyncTask to run the API call to Facebook. The code I'm using to get the Facebook data is
JSONObject json = null;
response = Utility.facebook.request("me?fields=cover");
json = Util.parseJson(response);
The exception that stops the thread comes from a json error on the next step because the returned json is empty, even though the request clears through. I can get a proper json using just "me" or "me/albums" or anything other than "me?fields=cover". When I comment out the last line, 'try' process finishes with no exceptions/errors.
Is there something wrong with the Facebook API or am I doing something wrong?
I personally prefer using FQL when dealing with User Profile. If you would like to give FQL a try, check the following piece of code. If you would like to stick to Graph API, see this answer: https://stackoverflow.com/a/12434640/450534
try {
String query = "SELECT pic_cover FROM user where uid = " + PUT_THE_USER_ID_HERE;
Bundle param = new Bundle();
param.putString("method", "fql.query");
param.putString("query", query);
String response = Utility.mFacebook.request(param);
JSONArray JAUser = new JSONArray(response);
for (int i = 0; i < JAUser.length(); i++) {
JSONObject JOUser = JAUser.getJSONObject(i);
// COVER PHOTO
if (JOUser.has("pic_cover")) {
String getCover = JOUser.getString("pic_cover");
if (getCover.equals("null")) {
String finalCover = null;
} else {
JSONObject JOCoverSource = JOUser.optJSONObject("pic_cover");
if (JOCoverSource.has("source")) {
String finalCover = JOCoverSource.getString("source");
} else {
String finalCover = null;
}
}
} else {
String finalCover = null;
}
}
} catch (Exception e) {
// TODO: handle exception
}
The above code already accounts for User's who do not have a Cover Photo set in their profiles and checks for its availability. With this code, you will have the URL to the Cover Photo and can then process it as you prefer.
NOTE: If you are fetching the logged in users cover photo, this piece of code SELECT pic_cover FROM user where uid = " + PUT_THE_USER_ID_HERE; can also be written as: SELECT pic_cover FROM user where uid = me()"; For the non-logged in user's cover photo, the above can be used as is.
Couple of things as a side note.
I use Fedor's Lazy Loading technique to load images in almost exclusively.
I recommend running the code block, mine or any other solution you choose, in an AsyncTask.
The reason for not getting any result can be found in the javadoc of request(String graphPath) method:
(...) this method blocks waiting for a network response, so do not
call it in a UI thread.
In your case, you should probably do the following synchronous call:
Bundle params = new Bundle();
params.putString("fields", "cover");
String result = Utility.facebook.request("me/", params);
Siddharth Lele is very correct in his answer, but I wanted to specify the actual reason for not getting any response in this case.
Note: Fetching Cover Photo using Facebook API and endpoint https://graph.facebook.com/me?fields=cover no longer works as on 20th Dec 2014.
It was supposed to give following response:
{
"cover": {
"cover_id": "10151008748223553",
"source": "http://sphotos-a.ak.fbcdn.net/hphotos-ak-ash4/s720x720/391237_10151008748223553_422785532_n.jpg",
"offset_y": 0
},
"id": "19292868552"
}
But now it just gives User's id:
{
"id": "19292868552"
}
Verified this using Graph Tool explorer v2.2 using me?fields=cover.