I'm a novice in Android programming and I was wondering whether it's possible to connect to multiple URLs using a single AsyncTask(70 different URLs). At the moment, I'm only able to connect to one URL through the use of HttpURLConnection.
class MyAsyncTaskClass extends AsyncTask<String, String, String>
{
private String rez;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... f_url) {
try {
////////....
URL url = new URL(("url"));
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
urlConnection.connect();
/////////////////
} catch (Exception e) {
rez = "false";
}
return rez;
}
#Override
protected void onPostExecute(String rez)
{
}
}
I don't think you would like to access all there 70 links at the same time (too much connections at the same time will make your connection not responding well), but I think you prefer to execute it one by one.
Why not creare a function like:
public String connection(String url) {
URL cURL = new URL(url);
HttpURLConnection urlConnection = (HttpURLConnection) cURL.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
urlConnection.connect();
rez = ..........
return rez;
}
and then use:
public List<String> doInBackground() {
final ArrayList<String> cResult = new ArrayList<>();
cResult.add(connection(url1));
cResult.add(connection(url2));
cResult.add(connection(url3));
...
return cResult;
}
In this way you are accessing all links one_by_one.
However it seems you miss the part that GETs the results....
Related
I am testing an AsyncTask. I want to stub an HttpURLConnection to return my mocked object. This is how I do it (PackageDownloader represents an AsyncTask):
...
PackageDownloader packageDownloader = new PackageDownloader();
packageDownloader.setParameters(URL, downloadFolder, downloadProgressCallback);
PackageDownloader mPackageDownloader = spy(packageDownloader);
HttpURLConnection connectionMock = Mockito.mock(HttpURLConnection.class);
doReturn(0).when(connectionMock).getContentLength();
doReturn(connectionMock).when(mPackageDownloader).createConnection(Mockito.any(URL.class));
mPackageDownloader.execute();
mPackageDownloader.get();
This is PackageDownloader:
public HttpURLConnection createConnection(URL url) throws IOException {
HttpURLConnection connection;
connection = (HttpURLConnection) url.openConnection();
return connection;
}
#Override
protected DownloadResult doInBackground(Void... params) {
HttpURLConnection connection;
URL downloadUrl = new URL(downloadUrlString);
connection = createConnection(downloadUrl);
long totalBytes = connection.getContentLength();
...
Here, createConnection returns real, not mocked object, and I can't figure out why.
Well I have found a solution, though haven't found an explanation why it works so.
The reason nothing worked was that doInBackground method is async, I assume, so I had to call it directly via reflection, like so:
Method method = mPackageDownloader.getClass().getMethod("doInBackground", Void[].class);
method.invoke(mPackageDownloader, new Void[] {null});
You can use robolectric to test the asynctask rather than reflection. Following the ShadowApplication.runBackgroundTasks() should invoke the doInBackground() method.
#RunWith(RobolectricTestRunner.class)
public class AcknowledgeAppRemovedTaskTest {
#Test
public void execute_shouldOpenInputStreamOfConnection() throws IOException {
DownloadTask spy = spy(new DownloadTask());
HttpURLConnection connectionMock = mock(HttpURLConnection.class);
doReturn(connectionMock).when(spy).createConnection(any(URL.class));
spy.execute();
ShadowApplication.runBackgroundTasks();
verify(connectionMock).getInputStream();
}
}
class DownloadTask extends AsyncTask<Void, Void, Void> {}
public HttpURLConnection createConnection(URL url) throws IOException {
return (HttpURLConnection) url.openConnection();
}
#Override
protected Void doInBackground(Void... voids) {
try {
HttpURLConnection urlConnection = createConnection(new URL("https://www.google.com/"));
urlConnection.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
https://github.com/robolectric/robolectric/blob/master/robolectric/src/test/java/org/robolectric/shadows/ShadowAsyncTaskTest.java
https://groups.google.com/forum/#!topic/mockito/mqF21aqTi5g
In my Android Application I have two activities: Main and Articles. My application starts with Main. In Articles I am showing Images which are downloaded from server.
Here is the code to download the images from server:
public class SyncImage extends AsyncTask<Void, Void, Bitmap> {
private String url;
private URLConnection connection;
public SyncImage(String url) {
this.url = url;
}
#Override
protected Bitmap doInBackground(Void... voids) {
Bitmap img;
try {
URL source = new URL(url);
connection = source.openConnection();
Handler.addUrlConnection(connection);
connection.setConnectTimeout(10000);
connection.setReadTimeout(10000);
connection.connect();
img = BitmapFactory.decodeStream(connection.getInputStream());
return img;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
}
Articles activity
private void downloadImages(ArrayList<String> images) {
for (String image : images) {
SyncImage sync = new SyncImage(image);
sync.execute();
// Rest of the code
}
}
What I want that if user press back button to go back to Main Screen, all UrlConnection objects should cancel/stop their executions.
I can cancel the SyncImage object using sync.cancel(true), but it will only stop AsyncTask object, not the URLConnection object in process.
So, how to cancel the ongoing execution UrlConnection objects on Back Press?
Make Connection and SyncImage class variable and then try to disconnect connection as follows :
#Override
public void onBackPressed() {
connection.close();
connection.disconnect();
SyncImages.cancel(true);
finish();
}
try this
#Override
public void onBackPressed() {
connection = null;
url = "";
finish();
}
The Problem
I have an AsyncTask task called from an Activity's OnCreate method. This task makes an http request. The HTTP request hangs. Once the "CODE HANGS HERE" code in the code below is executed, I observe in the debugger that the Async threads are perpetually 'running' and never return anything.
The Code
Here's the OnCreate method of the activity:
protected void onCreate(Bundle savedInstanceState) {
asyncRequest.delegate = this;
super.onCreate(savedInstanceState);
setContentView(R.layout.activty_attach);
Button retakeButton = (Button) (findViewById(R.id.retake_button));
retakeButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(AttachActivity.this, MainActivity.class);
startActivity(intent);
}
});
try {
URL url;
url = new URL("http://btl-cromwell:9000/api/engine/v1/version");
asyncRequest.execute(url);
} catch (Exception e) {
Log.e(logtag, e.toString());
}
}
Note the URL that is passed to he async task should just return JSON containing the version number of the service receiving the request.
The async task (asyncRequest) code is below:
public class AsyncRequest extends AsyncTask<URL, Void, List<String>> {
private String logtag = "AsyncRequestTask";
public AsyncResponse delegate;
List<String> projects = new ArrayList<String>();
#Override
protected void onPreExecute(){
super.onPreExecute();
}
#Override
protected List<String> doInBackground(URL... urls) {
try {
// Creating & connection Connection with url and required Header.
HttpURLConnection urlConnection = (HttpURLConnection) urls[0].openConnection();
urlConnection.setRequestProperty("Content-Type", "application/json");
urlConnection.setRequestMethod("GET"); //POST or GET
urlConnection.setRequestProperty("User-Agent", "Test");
// CODE HANGS HERE
int responseCode = urlConnection.getResponseCode();
String responseMessage = urlConnection.getResponseMessage();
projects.add(responseMessage);
} catch (Exception e) {
Log.e(logtag, e.toString());
}
return projects;
}
#Override
protected void onPostExecute(List<String> result){
delegate.processFinish(result);
}
}
Once I have the request working I will populate the projects variable with what I actually want to return but for now I just have it set to responseMessage. I'm sure this is just something to do with my unfamiliarity in making requests in Java, but I have spent days on this and can't figure it out. Any help is greatly appreciated.
asyncRequest.execute(url);
asyncRequest.getStatus();
String[] projects = asyncRequest.get();
It is not possible to do both an .execute and a .get().
As you should never use .get(), you better remove that statement.
Remove all code after asyncRequest.execute(url); and put that code in the onPostExecute of your AsyncTask.
I have pc running node in the same wifi with development phone(i dont use virtual device).
I test nodejs server with firefox extension rested and works fine(same pc with server)
I try to post from my android app a simple json. No error thrown but no seems to work(I have a console.log() on server's .post which not shown). I have also open 8080 port. here is my android code
public void sendJson(View view) {
new LongOperation().execute();
}
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
try {
URL url = new URL("http://192.168.1.5:8080/api");
URLConnection urlConn;
DataInputStream input;
urlConn = url.openConnection();
urlConn.setDoInput (true);
urlConn.setDoOutput (true);
urlConn.setUseCaches (false);
urlConn.setRequestProperty("Content-Type","application/json");
urlConn.setRequestProperty("Host", "android.schoolportal.gr");
urlConn.connect();
//Create JSONObject here
JSONObject jsonParam = new JSONObject();
jsonParam.put("name", "kalosto");
// Send POST output.
OutputStreamWriter printout = new OutputStreamWriter(urlConn.getOutputStream ());
printout.write(jsonParam.toString());
printout.flush ();
printout.close ();
} catch (Exception e) {
e.printStackTrace();
}
return "Executed";
}
#Override
protected void onPostExecute(String result) {
TextView txt = (TextView) findViewById(R.id.output);
txt.setText(result);
}
#Override
protected void onPreExecute() {}
#Override
protected void onProgressUpdate(Void... values) {}
}
I change the request from post to get, from my phone browser i can access the server and the console.log be triggered but app still do nothing
I am currently wondering how to use AsyncTask in multiple Activitys without copying it.
I used this Guide to do it in one Activity and that worked just fine. But to load and use this information in more than one Activity seems to me like to much work. I tried to put my LoadUrl function into another Class and just pass my Textfield I want to be edited. But my App crashes when i start it. (I am not sure if this is the right approach )
public class LoadFromUrl {
public void loadAccountInfo(String key) {
if( key != null ) {
new DownloadWebpageTask().execute();
}
}
private class DownloadWebpageTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
// params comes from the execute() call: params[0] is the url.
try {
return downloadUrl(urls[0]);
} catch (IOException e) {
return "Unable to retrieve web page. URL may be invalid.";
}
}
// onPostExecute displays the results of the AsyncTask.
#Override
protected void onPostExecute(String result) {
//textView.setText(result);
}
// Given a URL, establishes an HttpUrlConnection and retrieves
// the web page content as a InputStream, which it returns as
// a string.
private String downloadUrl(String myurl) throws IOException {
InputStream is = null;
// Only display the first 500 characters of the retrieved
// web page content.
int len = 500;
try {
URL url = new URL(myurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Starts the query
conn.connect();
int response = conn.getResponseCode();
//Log.d(DEBUG_TAG, "The response is: " + response);
is = conn.getInputStream();
// Convert the InputStream into a string
String contentAsString = readIt(is, len);
return contentAsString;
// Makes sure that the InputStream is closed after the app is
// finished using it.
} finally {
if (is != null) {
is.close();
}
}
}
// Reads an InputStream and converts it to a String.
public String readIt(InputStream stream, int len) throws IOException, UnsupportedEncodingException {
Reader reader = null;
reader = new InputStreamReader(stream, "UTF-8");
char[] buffer = new char[len];
reader.read(buffer);
return new String(buffer);
}
}
}
and calling it in:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
selectedAccount.setKey("google.com");
loadUrl.loadAccountInfo(selectedAccount.getKey());
}
All I want to do is, load the information of an URL and use this to fill my activitys (like multiple TextViews). Every activity uses different urls and structures.
Create DownloadWebPageTask in a separate file, as a public class. Then override its constructor to pass anything you need (a textfield, key, etc).
Put DownloadWebPageTask in a separate class. Then in onPostExecute, run a callback to the activity or fragment that will update its UI. This is done by having an activity implement a callback which is an inner interface inside the the DownloadWebpageTask (doesn't have to be an inner interface!). As you can see, the inner interface I put with your code is WebpageCallbacks.
This is your asynctask in another class (the spacing isn't perfect sorry...):
public class DownloadWebpageTask extends AsyncTask<String, Void, String> {
/**
* Any activity or fragment that implements WebPageCallbacks
*/
private WebPageCallbacks callbacks;
//start by referencing your activity to call onURLLoaded() for onPostExecute()
public DownloadWebpageTask(WebPageCallbacks callbacks) {
this.callbacks = callbacks; //note: I think weak references are preferred though
}
//no changes here
#Override
protected String doInBackground(String... urls) {
// params comes from the execute() call: params[0] is the url.
try {
return downloadUrl(urls[0]);
} catch (IOException e) {
return "Unable to retrieve web page. URL may be invalid.";
}
}
// onPostExecute displays the results of the AsyncTask by callback's onURLLoaded()
#Override
protected void onPostExecute(String result) {
//each activity or fragment will has a method to change their UI
callbacks.onURLLoaded(result);
}
// Given a URL, establishes an HttpUrlConnection and retrieves
// the web page content as a InputStream, which it returns as
// a string. No changes here
private String downloadUrl(String myurl) throws IOException {
InputStream is = null;
// Only display the first 500 characters of the retrieved
// web page content.
int len = 500;
try {
URL url = new URL(myurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Starts the query
conn.connect();
int response = conn.getResponseCode();
//Log.d(DEBUG_TAG, "The response is: " + response);
is = conn.getInputStream();
// Convert the InputStream into a string
String contentAsString = readIt(is, len);
return contentAsString;
// Makes sure that the InputStream is closed after the app is
// finished using it.
} finally {
if (is != null) {
is.close();
}
}
/**
* Any Activity or fragment that implements this will have
* onURLLoaded() method to update its own UI.
*/
public interface WebpageCallbacks {
void onURLLoaded(String result);
}
}
I would then add implements DownloadWebpageTask.WebpageCallBacks to all your fragments and activities that will use this asynctask.
Here is your activity:
public class ExampleActivity extends AppCompatActivity implements DownloadWebpageTask.WebpageCallBacks {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
selectedAccount.setKey("google.com");
//changed your oncreate at line below to run your accountInfo
runAccountInfo(selectedAccount.getKey());
}
.......................
//runs the asynctask to load url info from account info like your old loadURLInfo()
public void runAccountInfo(String key) {
if( key != null ) {
//get url with getURL(key)
new DownloadWebpageTask(this).execute(getURL(key));
}
}
//this will be run from onPostExecute from the asynctask
#Override
public void onURLLoaded(String result) {
textView.setText(result);
}
}
If you have the time though, I suggest to not use AsyncTask at all and look into other libraries like rxJava/rxAndroid. I hope this code is ok........