I am developing an Android application and when it launches :
1) I make an HTTP Request to my server to send a small JSON file.
2) Open a webView to show a URL.
When the server is running properly there is absolutely no problem and everything goes smoothly.
HOWEVER , if for any reason the server is down , the HTTP request literally hangs and i need to wait till there is an HTTP timeOut which is around 30seconds till i actually see the webView with the URL loading.
I read that i shouldn't make any networking inside the UI thread and i should use another thread for that.
In BlackBerry , that i have already developed the application for , this is as simple as that :
new Thread(){
public void run(){
HttpConnection hc =
(HttpConnection)Connector.open("http://www.stackoverflow.com");
}
}.start();
I just start a new thread and inside i make the requests and all the necessary networking. That way , even when my server is not reachable the webView is loaded immediately without making the user wait and sense that the app is actually hanging.
How could i do exactly the same in Android , easiest way possible ?
Why not to use the same method as you use it for BlackBerry?
new Thread() {
public void run() {
new URL("http://www.stackoverflow.com").getContent();
}
}.start();
Use AsyncTask, it's the simplest way to do that. For more details:
http://developer.android.com/reference/android/os/AsyncTask.html
In icecream sandwich and above you are not allowed to use any web cal in UI thread. However you may use threads, but best way proposed by android is to use Async task. A very simple example is as follow.
"AsyncTask < Parameters Type, Progress Value Type, Return Type >"
class MyAsyncTask extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
// Runs on UI thread- Any code you wants
// to execute before web service call. Put it here.
// Eg show progress dialog
}
#Override
protected String doInBackground(String... params) {
// Runs in background thread
String result = //your web service request;
return result;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String resp) {
// runs in UI thread - You may do what you want with response
// Eg Cancel progress dialog - Use result
}
}
Related
I get a username from a login screen. I want to make a call to a web service to validate user. The problem is that I am getting the error:
android.os.NetworkOnMainThreadException
I know why I'm getting it. I'm making a network call on the main thread.
The problem is that I don't want to use AsyncTask. I don't want the user to be able to sign in BEFORE I get a response from the web service.
How do I get around this?
You can start an AsyncTask when the user opens the first Activity, with a "Waiting" fragment. When the AsyncTask finished, you can switch to the "Login" fragment.
You can use AsyncTask as shown below to sign in only when you get a response from the web service.
class SignInAsyncTask extends AsyncTask<Void, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// Display a progress bar saying signing in or something
}
#Override
protected String doInBackground(Void... params) {
// Call your web service
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
// Sign in if the credentials are okay, otherwise show some error message to the user
}
}
If you really don't want to use AsyncTask you could start a new Thread and put your logic here.
new Thread(new Runnable() {
public void run() {
// Sign in validation
}
}).start();
I have created an AsyncTsak class in my project which downloads some information from web server. I am sure that it works well because when it is called by onCreate() , I can see the result . But unfortunately when I call it again via a button it doesn't work.
I am not sure but i think i have read somewhere about this problem . It said , we are permitted to use AsyncTask class only once.
AsyncTask class
class DownloadAdvertismentLevel2 extends AsyncTask<String,String,String>{
String [] ImageInformation=null;
protected void onPreExecute(){
// do nothing !
}
protected String doInBackground(String...Urls){
String Data="";
HttpURLConnection urlConnection = null;
try{
URL myUrl=new URL("http://10.0.2.2:80/Urgence/ads.aspx?Action=DownloadIds&TB="+TopBoundry+"&LB="+LowBoundry);
urlConnection = (HttpURLConnection)myUrl.openConnection();
BufferedReader in = new BufferedReader (new InputStreamReader(urlConnection.getInputStream()));
String temp="";
// Data is used to store Server's Response
while((temp=in.readLine())!=null)
{
Data=Data+temp;
}
}
catch(Exception ex){
Log.d("Er>doInBackground", ex.toString());
urlConnection.disconnect();
}
finally{
urlConnection.disconnect();
}
return Data;// it sends Result to onPostExcute
}
protected void onPostExecute(String Data){
createPhotoAlbum();
pb.closedProg();
}
}
onCreate
Here I don't have any problem . It works fine
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ads);
new DownloadAdvertismentLevel2().execute();
}
Via Button
ButtonSeeMore.setOnClickListener(new View.OnClickListener(){
public void onClick(View view) {
Counting();
}});
Counting
public void Counting(){
if(TotalRows-6>0){
TopBoundry=TotalRows;
LowBoundry=TotalRows-6;
TotalRows=LowBoundry;
}
new DownloadAdvertismentLevel2().execute();
}
Please consider that I need to use this class till it shows the information. What would you suggest ?
To expand on what JVN said about AsyncTask
Each instance of Async task can only be executed once.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
http://developer.android.com/reference/android/os/AsyncTask.html (Under 'Threading Rules')
This doesn't stop you making a new instance -
public void Counting(){
if(TotalRows-6>0){
TopBoundry=TotalRows;
LowBoundry=TotalRows-6;
TotalRows=LowBoundry;
}
new DownloadAdvertismentLevel2().execute();
new DownloadAdvertismentLevel2().execute();
}
^ The code above will run your task twice.
Your code looks fine.
I would guess that the problem is (in order of likelihood)
1) On click isn't working
2) Post Execute isn't working as expected
3) The server response isn't being read correctly
4) Your Server isn't handling the request properly
But this would be obvious if you run your debugger or add some extra log outputs
1) I think you might be able to use the Async task only once in the class. But definitely it can be called multiple times.
2) please check if your button onclicklistener() function is really getting called on button click. try some logs in that.
because the code seems to be fine.
To allow multiple asycnh tasks run at the same time you need to use the 'executeOnExceuter mechanism:
See this note from the Android doucmentation:
When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.
If you truly want parallel execution, you can invoke executeOnExecutor(java.util.concurrent.Executor, Object[]) with THREAD_POOL_EXECUTOR.
An example invocation would look like (this particular example is from a video manipulation app - the 'distributionTask' is an instance of a class that extends AsynchTask):
//Now execute synch task - to allow multiple AsynchTasks execute in parallel the
//'executeOnExecutor' call is required. It needs to be used with caution to avoid the usual synchronization issues and also
//to avoid too many threads being created
distributionTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Environment.getExternalStorageDirectory() + "/videoChunk_"+i+".mp4");
I have a download activity which downloads some zip files for my application.
I want my activity have this features :
capable of pause/resume download
shows download progress in my activity's UI by a progress bar ( not with
dialogProgress)
shows notification with download progress and when user clicks on the
notification it opens my activity even when the app is closed and my UI keeps updated during download
I have searched a lot and saw lots of methods that can be used to download files (like using AsyncTask/Downloadmanager/Groundy ... ) but I don't know which one of them has the features I want
what do you think is the best way to achieve this features all together ??
I don't want the full code from you, just some tips and methods or references to help me implement each of these features and find the best way.
Thanks for your time.
Fundamentally you can use AsyncTask through which you would be able to achieve the above, if the download is strictly tied to the activity. However AsyncTask needs to be properly cancelled once user cancel or back out from activity. Also it provide basic mechanism to do the progress thing.
For example, imagine a simple async task (not the best implementation) but something like below
class SearchAsyncTask extends AsyncTask<String, Void, Void> {
SearchHttpClient searchHttpClient = null;
public SearchAsyncTask(SearchHttpClient client) {
searchHttpClient = client;
}
#Override
protected void onProgressUpdate(Void... values) {
// You can update the progress on dialog here
super.onProgressUpdate(values);
}
#Override
protected void onCancelled() {
// Cancel the http downloading here
super.onCancelled();
}
protected Void doInBackground(String... params) {
try {
// Perform http operation here
// publish progress using method publishProgress(values)
return null;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute() {
// If not cancelled then do UI work
}
}
Now in your activity's onDestroy method
#Override
protected void onDestroy() {
Log.d(TAG, "ResultListActivity onDestory called");
if (mSearchTask != null && mSearchTask.getStatus() != AsyncTask.Status.FINISHED) {
// This would not cancel downloading from httpClient
// we have do handle that manually in onCancelled event inside AsyncTask
mSearchTask.cancel(true);
mSearchTask = null;
}
super.onDestroy();
}
However if you allow user to Download file even independent of activity (like it continues downloading even if user got away from Activity), I would suggest to use a Service which can do the stuff in background.
UPDATE: Just noticed there is a similar answer on Stackoverflow which explains my thoughts in further detail Download a file with Android, and showing the progress in a ProgressDialog
I have a Main activity with a few methods.
GetTopics: calls REST API and returns JSON results
BindTopics: displays the results from GetTopics on the screen
There are a few others with similar functionality, but I'm sure I can fit the solution to these across all methods.
Question: What is the proper way to run these in separate threads? Should both of them be in the same thread? Should I call BindTopics once GetTopics is complete?
Either way, doesn't the UI get built prior to the async threads are completed? If so, how do I update the UI?
Any help is appreciated.
The answer to all your questions is AsyncTask
I would load it in a progress dialog with an AsyncTask. You will need to declare the handler to update controls in the UI thread.
Example:
private Handler handler = new Handler();
final ProgressDialog pd = new ProgressDialog(this);
pd.setTitle("Getting topics..");
pd.setMessage("Please while topics are retrieved");
pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pd.setIndeterminate(true);
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
GetTopics();
return null;
}
#Override
protected void onPreExecute() {
pd.show();
super.onPreExecute();
}
#Override
protected void onPostExecute(Void result) {
BindTopics();
pd.dismiss();
handler.post(new Runnable() {
public void run() {
// update UI
// remove loading view
// load details of topics
}
});
super.onPostExecute(result);
}
}.execute();
You want to create your UI (with some sort of loading screen), then start an AsyncTask to download the data and display it.
There is a basic blog post about AsyncTasks here: http://android-developers.blogspot.co.uk/2009/05/painless-threading.html
In the AsyncTasks doInBackground method you would call GetTopics. Then in the onPostExecute method you would call BindTopics and display the data. In the onPostExecute method you can check to see if the data downloaded properly before attempting to display it.
The main use of threads for me were when my app had to download large amount of data from ftp server. But while downloading I wanted that the user still can use my app. If I had written the download code in main thread, the user could not use the app and all buttons would not work. The main idea of thread is to divide time of CPU usage for each thread.
If you wish more then one task to be preformed simultaneously you have to use Threads.
This works in a Java application run in Eclipse:
URL yahoo = new URL("http://www.nytimes.com/2011/08/17/business/global/merkel-arrives-in-paris-to-begin-economic-talks-with-sarkozy.html?_r=1&hp");
yc = (HttpURLConnection) yahoo.openConnection();
yc.setRequestProperty("User-Agent","sdfdfvjavasdvdsv");
in = new BufferedReader(new InputStreamReader(yc.getInputStream()));
The same code doesn't work in an Android application in the same Eclipse +emulator:
public void onCreate(Bundle savedInstanceState) {
URL yahoo = new URL("http://www.nytimes.com/2011/08/17/business/global/merkel-arrives-in-paris-to-begin-economic-talks-with-sarkozy.html?_r=1&hp");
yc = (HttpURLConnection) yahoo.openConnection();
yc.setRequestProperty("User-Agent","sdfdfvjavasdvdsv");
in = new BufferedReader(new InputStreamReader(yc.getInputStream()));
}
They are identical; one runs as a Java app, the other as an Android app. The Android app gets many redirects and eventually times out. Does the Android app send something special to tick off nytimes.com?
You should not (and, as of Honeycomb, cannot) do networking activity on the UI thread in Android, and onCreate executes on the UI thread. Check out the article on Painless Threading. Also check out the guide topic Designing for Responsiveness.
You are doing this in the main UI thread. The internet connectivity generally takes more time than the UI thread.
Try to do this in an Async Task class in the doInBackGround().
For more information refer to this. https://developer.android.com/reference/android/os/AsyncTask.html
In android you should use AsyncTask to achieve what you want.
An example of an AsyncTask would look sth like this:
private class FetchData extends AsyncTask<String, String, String>> {
ProgressDialog progress;
#Override
protected void onPreExecute() //Starts the progress dailog
{
progress = ProgressDialog.show(YourActivity.this, "Loading...",
"", true);
}
#Override
protected String doInBackground(String... strings)
{
String result="";
URL yahoo = new URL("http://www.nytimes.com/2011/08/17/business/global/merkel-arrives-in-paris-to-begin-economic-talks-
with-sarkozy.html?_r=1&hp");
yc = (HttpURLConnection) yahoo.openConnection();
yc.setRequestProperty("User-Agent","sdfdfvjavasdvdsv");
in = new BufferedReader(new InputStreamReader(yc.getInputStream()));
//do sth with your data here
return result;
}
#Override
protected void onPostExecute(ArrayList<Article> result)
{
progress.dismiss();
}
}
Keep in mind that
onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
as stated on Android developers.
You can find more info about AsyncTask and how to implement it on the provided link.