I want to fetch the JSONArray from the internet and show it in the logcat so I use
Log.e("result ", result);
But it seems fail because I can't find any of the JSONArraay in the logcat
Here's my code and I hope you can have a look and tell me what's wrong ?
I know some of you are using BufferReader to read the text from internet
but I guess my way should also be OK
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnParse;
ListView listResult;
btnParse = (Button) findViewById(R.id.btn_parse);
listResult = (ListView) findViewById(R.id.list_result);
btnParse.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
JSONArray trial = getJSONData();
}
});
}
private JSONArray getJSONData() {
String url = "http://cloud.culture.tw/frontsite/trans/SearchShowAction.do?method=doFindAllTypeJ";
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(url);
try {
HttpResponse httpresponse = httpClient.execute(httpget);
String result = EntityUtils.toString(httpresponse.getEntity());
Log.e("result ", result);
JSONArray jsonarr = new JSONArray(result);
return jsonarr;
} catch (Exception err) {
return null;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
Android does not allow networking on the UI thread. Therefore, when you call HttpResponse httpresponse = httpClient.execute(httpget); It is throwing an android.os.NetworkOnMainThreadException exception. It would be more useful for you to call Log.e("error",err.printStackTrace())in the catch block rather than returning null as this error would be revealed in the logcat. You need to move the code int the try block to another thread. I recommend using an AsyncTask. See this link for more details on this. The basics about AsyncTask: it is a class that abstracts the use of a thread and a handler away from the developer. If you are familiar with threads and handlers you can implement your own solution (not an async task) to avoid having to conform to the asynctask frame work.
Ever since Android 3.0, StrictMode has been enabled by default. What it does it prohibit developers from doing lazy things such as running network code on the UI thread. It forces you to run such code asynchronously so that the application doesn't hang/pause and user interaction remains uninterrupted. You can turn that off so that you don't need to use an AsyncTask/Handler/Volley/whatever. It's a bad way to handle it, but here's one way to do it (don't do this):
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy); // Put these two lines before you execute your HTTTP request....
Do this instead:
Use Volley, here's a quick tutorial. Also, a Google Talk about it.
Related
I have a hosted website in php. The android app tries to open a web page happy.php. When I try to run this app, instead of displaying yayyyy in the textview, failed is shown. Please help me to find the error
public class MainActivity extends ActionBarActivity {
Button b;
TextView t;
String n;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b=(Button)findViewById(R.id.button);
t=(TextView)findViewById(R.id.textView);
b.setOnClickListener( new View.OnClickListener(){
public void onClick(View v)
{try {
DefaultHttpClient d = new DefaultHttpClient();
HttpPost p = new HttpPost("http://www.palakarora.net16.net/happy.php");
HttpResponse httpResponse = d.execute(p);
HttpEntity httpEntity = httpResponse.getEntity();
InputStream is = httpEntity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is, "iso-8859-1"), 8);
n = reader.readLine();
}
catch(Exception e)
{
n="failed";
}
t.setText(n);
}
});
}
#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_main, 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();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
happy.php is the web page called by android app. the page prints "yayyyy".
happy.php
<?
print("yayyyyy");
?>
All android async tasks (including connections) should be made in a separate threads, and in all modern versions, you are forced to make connection in a separate thread (using AsyncTask or something like that), the bad thing is that the connection problem is not shown specifically when this happens, so make sure you are doing this when sending your request. Hope this helps
It's indifferent that you work in local or with server, the 'httpPost' class need work inside of AsynClass, because the 'httpPost' is async method...
I explain a little bit here and has 3 examples!!
Tell me if I helped you and good programming!
Indeed, networking on main thread is not allowed.
Perhaps use Retrofit library to deal with the downloading.
Life is better without asynctasks
http://square.github.io/retrofit/
Ever get those moments where you stare at a piece of code for an hour and still can't come up with an answer? Yeah that's me now.
I'm working on a final project for class and I can't get this one piece of code to work. It is absolutely crucial that it works, or else it defeats the purpose of the program. I even asked my professor for help... and he doesn't know how to help me solve the issue. I posted a similar problem a day ago but I want to re-ask in a different way to see if it helps (Sorry if its a re-post, I have no other source for help :/).
My problem is that I need to access array elements on my MainActivity after its populated inside an AsyncTask class. The array is defined globally but as soon as I try to access it's element or size, it crashes. I need to be able to call this array outside of AsyncTask.
I've searched for hours and tried "returning" the array from AsyncTask but it crashes as well.
Here is my code (I've included comments as to where it crashes):
public class PostsActivity extends Activity {
public static GlobalRates[] gr;
TextView view;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_posts);
view = (TextView) findViewById(R.id.textView1);
BitRateFetcher br = new BitRateFetcher();
br.execute();
// !!! Line below crashes !!!
Log.i("BitRateFetcher", "Size from onCreate: " + gr.length);
}
private class BitRateFetcher extends AsyncTask<Void, Void, GlobalRates[]> {
private static final String TAG = "BitRateFetcher";
public String BIT_PAY_SERVER = "https://bitpay.com/api/rates";
private ProgressDialog dialog;
GlobalRates[] test;
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new ProgressDialog(PostsActivity.this);
dialog.setMessage("Please Wait... Downloading Information");
dialog.show();
}
#Override
protected GlobalRates[] doInBackground(Void... params) {
try {
// Create an HTTP client
HttpClient client = new DefaultHttpClient();
HttpGet getBitRates = new HttpGet(BIT_PAY_SERVER);
// Perform the request and check the status code
HttpResponse bitRatesResponse = client.execute(getBitRates);
StatusLine bitRatesStatus = bitRatesResponse.getStatusLine();
if (bitRatesStatus.getStatusCode() == 200) {
HttpEntity entity = bitRatesResponse.getEntity();
InputStream content = entity.getContent();
try {
// Read the server response and attempt to parse it as
// JSON
Reader reader = new InputStreamReader(content);
Gson gson = new Gson();
test = gson.fromJson(reader, GlobalRates[].class);
content.close();
entity.consumeContent();
} catch (Exception ex) {
Log.e(TAG, "Failed to parse JSON due to: " + ex);
failedLoadingPosts();
}
} else {
Log.e(TAG, "Server responded with status code: "
+ bitRatesStatus.getStatusCode());
failedLoadingPosts();
}
} catch (Exception ex) {
Log.e(TAG, "Failed to send HTTP POST request due to: " + ex);
failedLoadingPosts();
}
return test;
}
#Override
protected void onPostExecute(GlobalRates[] test) {
Log.i(TAG, "Test Size: " + test.length); // Returns 158
gr = test;
Log.i(TAG, "Gr Size: " + gr.length); // Returns 158
if (dialog.isShowing()) {
dialog.dismiss();
}
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.posts, menu);
return true;
}
private void failedLoadingPosts() {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(PostsActivity.this,
"Failed to load Posts. Have a look at LogCat.",
Toast.LENGTH_SHORT).show();
}
});
}
}
Here is the error Log:
04-21 20:30:01.954: E/AndroidRuntime(32595): FATAL EXCEPTION: main
04-21 20:30:01.954: E/AndroidRuntime(32595): Process: com.example.postsactivity, PID: 32595
04-21 20:30:01.954: E/AndroidRuntime(32595): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.postsactivity/com.example.postsactivity.PostsActivity}: java.lang.NullPointerException
My class partner and I are unsure as to how we can call the global array (gr) properly. I understand that onCreate is not going to wait for AsyncTask to finish. What can we do to get this to work? Thanks for the help and understanding. You guys can prove more useful than my professor...
the problem is that you are accessing array of globalrates before it was initialized in your postExecute(). There are a lot of way to do this one of which is creating an interface or creating callbacks that waits for globalrate to be initialized after ur background thread is done.
Create a Interface
public interface SampleInterface {
void globalResultBackground(GlobalRates[] gr);
}
implements the interface to ur activity
public class PostsActivity extends Activity implements SampleInterface
pass the interface to your asynctask
//in the activity
BitRateFetcher br = new BitRateFetcher(this);
br.execute();
//in the asynctask class
SampleInterface si;
public BitRateFetcher(SampleInterface si){
this.si = si;
}
pass the result of the background thread to ur interface method
#Override
protected void onPostExecute(GlobalRates[] test) {
si.globalResultBackground(test);
Log.i(TAG, "Test Size: " + test.length); // Returns 158
gr = test;
Log.i(TAG, "Gr Size: " + gr.length); // Returns 158
if (dialog.isShowing()) {
dialog.dismiss();
}
}
in the activity where the you implemented the interface and generated the globalResultBackground method
#Override
public void globalResultBackground(GlobalRates[] gr) {
//you can freely access the globalrates here because this is called when the
//background thread is done
Log.i("BitRateFetcher", "Size from onCreate: " + gr.length);
}
Pass in your activity to the AsyncTask and directly access its gr in your onPostExecute
Sample code:
private class BitRateFetcher extends AsyncTask {
PostsActivity activity;
...
public BitRateFetcher(PostsActivity activity){
this.activity= activity;
}
...
#Override
protected void onPostExecute(GlobalRates[] test) {
activity.gr = ...
}
}
In PostsActivity,
BitRateFetcher br = new BitRateFetcher(this);
Take care to attach and reAttach the activity to handle scenarios such as device rotations.
EDIT: Just noticed you've got a static, so you don't even need to pass in the activity. The same principle applies though.
GlobalRates[] gr is public and static, so you dont really new GlobalRates[] test
simply replace every instance of test with gr:
test = gson.fromJson(reader, GlobalRates[].class);
to
gr = gson.fromJson(reader, GlobalRates[].class);
if you need to access gr in Oncreate then move that logic to postExecute
Log.i("BitRateFetcher", "Size from onCreate: " + gr.length);
Scenario: A bit tricky but interesting.
I have sent a request that will give me a JSON response. This response will further contain, say 10, JSON request URLs.
I will then send request to these 10 Urls and each URL will then contain 2 image URLs. That means 20 images in total.
My intentions are to show these images in a ListView as fast as possible to the user.
This is what I've done till now:
Step 1: As soon as the activity starts, pop a ProgressDialog showing loading circle as in youtube.
Step 2: IN AN ASYNC TASK, Send the first request that give URLs of those 10 JSON requests. Send this request then parse & store these 10 URLs present is response.
Step 3: Starting from first(out of 10), send the request that will give the JSON response.
Step 4: Parse this response to fetch the 2 image URLs and store in LinkedList.
Step 5: As we have the actual link of the image now, dismiss the progress dialog and fetch the image.
Step 6: This image will be stored in drawable. I've made a custom BaseAdapter called ImageAdapter that has ArrayList<Drawable> mImages;
Step 7: Store the received drawable in this ArrayList, using: adapter.mImages.add(drawable);
Step 8: Then call adapter.notifyDataSetChanged(); This will update the listview as soon the image is ready to be displayed.
Step 9: Back to step 3 to process further URLs.
Below is the code (striped all the unnecessary code):
ActivityClass
public class ImageViewer extends Activity {
GridView gvImage;
private ProgressDialog progressDialog;
private final static Integer IMAGE_LIMIT = 10;
private ImageAdapter adapter;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
setContentView(R.layout.ImageViewer);
gvImage = (GridView) findViewById(R.id.gvImage);
adapter = new ImageAdapter(this);
gvImage.setAdapter(adapter);
progressDialog = ProgressDialog.show(ImageViewer.this, "In Progress",
"Loading...", true, true, new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
finish();
}
});
new SendRequest().execute(null);
} catch (Exception e) {
}
}
class SendRequest extends AsyncTask {
protected Object doInBackground(Object... params) {
try {
HttpClient client = new DefaultHttpClient(httpParameters);
HttpContext localContext = new BasicHttpContext();
HttpGet httpGet = new HttpGet(BaseRequest_URL);
JSONObject jsonResponse = null;
HttpResponse httpResponse = client.execute(httpGet, localContext);
if (httpResponse.getStatusLine().getStatusCode() == 200) {
HttpEntity entity = httpResponse.getEntity();
jsonResponse = getJSONObjectFromEntity(entity); //getJSONObjectFromEntity() will return JSONObject
processJSON(jsonResponse);
}
progressDialog.dismiss();
} catch (Exception e) {
}
return null;
}
private void processJSON(JSONObject jsonResponse) throws JSONException {
for (int i = 0; i < IMAGE_LIMIT; i++) {
// Some JSON parsing. Output will be 'imageURL' which will be image URL
displayImage(imageURL);
}
}
public void displayImage(String uri150) {
try {
InputStream is = (InputStream) new URL(uri150).getContent();
if(progressDialog.isShowing()){
progressDialog.dismiss();
}
Drawable d = Drawable.createFromStream(is, "image 150");
adapter.mImages.add(d);
handler.sendEmptyMessage(0); // Handler Below
} catch (Exception e) {
}
}
protected void onPostExecute(Object result) {
super.onPostExecute(result);
}
}
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
adapter.notifyDataSetChanged();
};
};
}
ImageAdapter Class:
public class ImageAdapter extends BaseAdapter {
Context context;
public ArrayList<Drawable> mImages = new ArrayList<Drawable>();
public ImageAdapter(Context c) {
this.context = c;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = new ImageView(context);
try {
imageView.setLayoutParams(new GridView.LayoutParams(150, 150));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setImageDrawable(mImages.get(position));
imageView.setTag("Image" + position);
} catch (Exception e) {
}
return imageView;
}
}
Questions:
The way I see it ImageAdapter is called several times. Is there any other way to reduce it.
How can I optimize the code of ImageAdapter.
Any other improvement?
(the first 2 questions) Adapter doesn't only control which row (view in the list) appears, it also recycles it. In your Adapter, getView creates a new view every time it is called, when it should only create a new one if the old one is not available. Check out Mark Murphy (commonsware)'s adapter here.
In your code, all the images are downloaded during progress dialog. Your user will probably not see them all to the last one and it will definitely burden your memory. I suggest you lazy load both JSON and images (request your JSON, parse it, load the image one-by-one asynchronously depending on how much of the grid your users see/scroll). There have been a lot of discussions regarding image lazy loading and you should definitely start from Fedor's answer.
What I can tell you for sure it is WRONG to store your images in memory, as you can get OutOfMemoryException.
To learn how to work with images and cache visit Displaying Bitmaps Efficiently
Try this library. It is really good for layz loading.
just search for Android LazyImageLoading
Good Luck
I've made an app that sends a request to a webserver in a specified interval and gets XML data. It then parses the XML data, gets information from the phone (text messages, contacts or something similar) and shoots it back to the server with a http post request.
The problem is that it usually takes a few seconds for the app to get the info, which often leaves the app crashing. A dialog comes up saying the app has become unresponsive and asks if i want to close the app or wait, if i press wait it eventually starts working again.
Is AsyncTask the right solution to this problem?
Another thing i don't really understand is how AsyncTask actually works. Let's say i have two methods that do a lot of work and crashes the app, can i put both of them in one AsyncTask and just call them from doInBackground()?
I have also implemented something similar you are trying. That is sending request to server, receive XML response, parse XML, show result. View This. I have used AsyncTask for this.
Here is how i have implemented it using AsynTask
private class AsyncClass extends AsyncTask<Void, Void, Bundle>{
#Override
protected Bundle doInBackground(Void... arg0) {
Bundle b=startProcess();
// startBundle() method do all the processing and return result in a bundle. You can as many methods from within startBundle() method
return b;
}
#Override
protected void onPostExecute(Bundle result) {
Log.d(TAG , "In onPostExecute");
dialog.dismiss();
if(result==null)
Toast.makeText(cont, "Can't process query.\nTry again later.", Toast.LENGTH_LONG).show();
else{
Intent in = new Intent(cont, QueryResultDisplay.class);
Log.d(TAG , "Displaying");
in.putExtras(result);
cont.startActivity(in);
}
}
I give you brief description about your problem.
There are many possibility that you don't get data from server
if your network speed is very slow and you try to get all the
information from server and XML data then in this case if network crash then it show you error
if you're making request to that page which is not in server
Now, if you are facing the problem in code, then I give you the complete code of AsyncTask class which I had implemented in my project and it work fine.
private class GetLoginResponse extends AsyncTask<Void, Void, Boolean> {
private ProgressDialog progressDialog;
private String email;
private String password;
public GetLoginResponse(String emailId, String paswd) {
this.email = emailId;
this.password = paswd;
}
#Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(LoginActivity.this, "",
"Loading....", true, false);
}
#Override
protected Boolean doInBackground(Void... params) {
try {
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
HttpResponse response = httpclient.execute(httpGet);
//here u can check the reponse is ok and 200
} catch (NetworkException e) {
isNetworkError = true;
}
return false;
}
#Override
protected void onPostExecute(Boolean data) {
progressDialog.dismiss();
System.out.println("lOGIN RESPONSE for email = " + email + data);
}
}// end AsyncTask
This would solve your problem.
Yes, you can use AsyncTask.
The code called in doInBackground() must not touch the UI.
You can touch the UI thread with publishProgress().
I have a web address www.abc.com/check ... I have created a web service on this address for receiving data. Through an android app i send some data to this address using following code:
public class TestappActivity extends Activity {
EditText ch;
Button btn;
InputStream is;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ch=(EditText)findViewById(R.id.ch);
btn=(Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
sendData();
}
});
}
private void sendData() {
Log.i(getClass().getSimpleName(), "send task - start");
HttpParams p=new BasicHttpParams();
p.setParameter("name", ch.getText());
HttpClient client = new DefaultHttpClient(p);
try {
HttpResponse response=client.execute(new HttpPost("http://www.abc.com/check"));
is=response.getEntity().getContent();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.i(getClass().getSimpleName(), "send task - end");
}
}
How can i find if my post was successful ? What do i get back when i post something. ?
[update]Simple solution, you can just check the status code
response.getStatusLine().getStatusCode();
It's a integer(200 means OK, 500 means error on server) , Reference Here
Or a completely check by using the response body
response.getEntity().getContent();
It is generated on the server by your service, so if you want to assure the invocation is really successful, you can return something to client. e.g. a XML string
"<status>OK</status>"
in the response body would be enough. You will get it on client and then do whatever you want to do.
I recommend the simpler solution. Thanks shraddha
I guess baoz is right, but there is one simple alternative to this.
response.getStatusLine.getstatuscode(); //200-successful
It will return numeric response code for success as well as error. Moreover, if the response is negative, it will return you relevant error code so that you can track and catch those errors.
Regards.