I have call the GetXMLTask from my service and it will repeatedly call every 1 seconds to get data from the IP address (MyIP).
MyService.java
public class MyService extends Service {
public int onStartCommand(Intent intent, int flags, int startId) {
if (GlobalFunctions.isInternetAvailable(MyService.this)
|| GlobalFunctions.isWifi(MyService.this)) {
MyTimerTask myTask = new MyTimerTask();
Timer myTimer = new Timer();
myTimer.schedule(myTask, 1000, 1000);
} else {
Toast.makeText(MyService.this, "No Internet Connection", 1000).show();
}
return Service.START_STICKY;
}
class MyTimerTask extends TimerTask {
public void run() {
GetXMLTask task = new GetXMLTask();
task.execute(new String[] { MyIP });
}
}
}
asynctask is use in the GetXMLTask.java.
public class GetXMLTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
try {
String output = null;
for (String url : urls) {
output = getOutputFromUrl(url);
}
return output;
} catch (Exception e) {
return null;
}
}
}
and now when the apps is running, i have change the ip address, but the "urls" still showing the previous ip address (see the data from eclipse debug mode) and it the "urls" will be updated after quite a long time.
May i know what should i do so that urls in the asynctask can directly take newest ip address without long delay.
thank you so much
Updated 24/4/2014:
I have make changes for the doinBackground code, but the data received from the IP address is still not the updated data.
protected String doInBackground(String... urls) {
try {
String output = null;
String[] newurl = {GlobalVariables.Global_URL + "/status.xml"};
for (String url : newurl) {
output = getOutputFromUrl(url);
}
return output;
} catch (Exception e) {
return null;
}
}
Any idea? Thank You
Updated 25/4/2014:
I have debug the code and notice that when IP address is changed, the asynctask seem like freeze for quite a long time. I have put the break point in the doinbackground, and it doesn't go in.
Any idea? thank you
The for loop in doInBackground is processing urls sequentially. You may need to check for change in ip inside for loop and if ip has changed do the needful (for example updating urls accordingly).
Related
From my Login Activity (First Activity Opened) I always do a check if the token is still active on my server which is done through Async Task that does API call to server.
here's the code from LoginActivity :
private void checkIfAuthenticated(){
SharedPreferences reader_auth = getSharedPreferences(getString(R.string.auth_preferences), MODE_PRIVATE);
String auth_key = reader_auth.getString(getString(R.string.auth_access_key),null);
String mobile_token = reader_auth.getString(getString(R.string.auth_mobile_token),null);
if (auth_key != null) {
//THIS PART RUNS THE TOKEN CHECK TO SERVER
authGlobal = new AuthenticationGlobal(this);
// I WANT THIS FUNCTION TO FINISH FIRST BEFORE IT GOES TO THE NEXT PART OF THE CODE
authGlobal.runAuthenticationCheck(auth_key,mobile_token);
String Auth_Key = reader_auth.getString(getString(R.string.auth_access_key),null);
Log.d("Auth Key Check 0",Auth_Key);
if (Auth_Key != null) {
Log.d("Auth Key Check 1",Auth_Key);
MoveToDashboardActivity();
}
}
}
The runAuthenticationCheck(String,String) Code is located on another class (Because it was meant to be a global function which can be called from any function on any activity)
runAuthenticationCheck is located in AuthenticationGlobal Class, here's the code :
public void runAuthenticationCheck (String mobile_token, String Access_token) {
checkAuthTask = new checkAuthenticationTask(mobile_token, Access_token);
checkAuthTask.execute((Void) null);
}
public class checkAuthenticationTask extends AsyncTask<Void, Void, Boolean> {
private GetDataService service;
private String mobile_token;
private String access_token;
checkAuthenticationTask( String Access_token,String Mobile_token) {
/*Create handle for the RetrofitInstance interface*/
mobile_token = Mobile_token;
access_token = Access_token;
service = RetrofitClientInstance.getRetrofitInstance().create(GetDataService.class);
}
#Override
protected Boolean doInBackground(Void... params) {
// TODO: attempt authentication against a network service.
try {
Call<CheckAuthenticationResponse> call = service.checkAuthentication(access_token,mobile_token);
Response<CheckAuthenticationResponse> CheckAuthenticationResponse = call.execute();
if (CheckAuthenticationResponse.code() == 200){
} else{
//clear shared preferences
clearAuthentication();
Log.e("AuthKey Global","Expired0");
}
} catch (IOException ea) {
clearAuthentication();
Log.e("AuthKey Global","Expired1");
Log.e("AuthenticationResponseError Global","Network Went Wrong");
ea.printStackTrace();
}
return true;
}
#Override
protected void onPostExecute(final Boolean success) {
//mAuthTask = null;
//showProgress(false);
if (success) {
Log.e("AuthKey Global","Done");
} else {
// mPasswordView.setError(getString(R.string.error_incorrect_password));
clearAuthentication();
Log.e("AuthKey Global","Expired2");
}
}
#Override
protected void onCancelled() {
//mAuthTask = null;
//showProgress(false);
}
There are 2 Class / Activity : "LoginActivity" and "AuthenticationGlobal".
There are 3 Function :
checkIfAuthenticated => located in LoginActivity, Which in turn actually call another function from another class (Function number 2 : "runAuthenticationCheck")
runAuthenticationCheck => located in AuthenticationGlobal. which in calls a AsyncTask via .execute(...) command.
checkAuthenticationTask => located in AuthenticationGlobal. Which actually does the API Call to server.
From "LoginActivity" I run a function "checkIfAuthenticated" => which calls function "runAuthenticationCheck" located at "AuthenticationGlobal" => which runs a Task "checkAuthenticationTask" which does API Call to server and does stuff.
The problem is, when I called the first Function, the code doesn't wait until the function "checkIfAuthenticated" / "checkAuthenticationTask" is done. Is there a way for me to make the app wait until the task / function finish first??
Thank you
UPDATE :
I ONLY NEED TO ADD .get() at the end of .execute() and wrap it inside try catch.
public void runAuthenticationCheck (String mobile_token, String Access_token) {
checkAuthTask = new checkAuthenticationTask(mobile_token, Access_token);
try {
checkAuthTask.execute((Void) null).get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Well. I just need to add a .get() on the execute() and wrap it inside a try catch.
A dumb mistake.
here's the updated code :
public void runAuthenticationCheck (String mobile_token, String Access_token) {
checkAuthTask = new checkAuthenticationTask(mobile_token, Access_token);
try {
checkAuthTask.execute((Void) null).get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
About my App
In my app there is a TCP Client at the start it ask the server for a number, and for now it's working properly but the problem is when i have to open the connection again and ask number times that the server sent before for other data. I mean i'm trying to make a for cycle that will ask X times the server for data and will put them in RecyclerView.Adapter but for now the For Cycle goes in a infinity loop without stoping after X times .
Example
So if i'm starting my app and it reveice number 5 from the server i will ask the server for 1st number details after i got it i will ask for 2nd number details and co.
Here is my AsyncTask from MainActivity code where i get the X number from the server at the start :
public static class ConnectTask extends AsyncTask<String, String, Client> {
#Override
protected Client doInBackground(String... message) {
client = new Client(new Client.OnMessageReceived() {
#Override
public void messageReceived(String message) {
publishProgress(message);
}
});
client.run();
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
if(MainActivity.active){
msgServer.setTextColor(Color.parseColor("#00FF00"));
msgServer.setText("ONLINE");
SelfNumber = values[0];
}
if(help.active){
for(int i=0; i< Integer.valueOf(SelfNumber); i++){
StringTokenizer stringTokenizer = new StringTokenizer(String.valueOf(values[0]),"#");
status = stringTokenizer.nextToken();
receipt = stringTokenizer.nextToken();
eur = stringTokenizer.nextToken();
help.adapter = new SelfAdapter(("CASSA SELF N°" + Integer.toString(i+1)),"EUR: " + eur,"SC: " + receipt,help.img);
help.selfList.add(help.adapter);
help.adapterView.notifyDataSetChanged();
startConnection.removeCallbacks(runnableConnection);
startConnection.postDelayed(runnableConnection,100);
startCashMessage.removeCallbacks(runnableCashMessage);
startCashMessage.postDelayed(runnableCashMessage,250);
}
}
}
}
Handlers :
static Handler startConnection = new Handler();
static Runnable runnableConnection = new Runnable() {
#Override
public void run() {
new ConnectTask().execute("");
}
};
static Handler startCashMessage = new Handler();
static Runnable runnableCashMessage = new Runnable() {
#Override
public void run() {
if (help.active) {
final Cursor cursor = myDB.fetchData();
if (cursor.moveToFirst()) {
do {
Client.SERVER_IP = cursor.getString(1);
} while (cursor.moveToNext());
}
if (client != null) {
client.sendMessage("RICEVO DATI CASSA 1");
}
}
}
};
I think you will benefit from learning to use RxJava / RxAndroid.
I believe that this presentation (and a video link) will help you with a solution, he was presenting a solution to a similar problem.
If you never used RxJava before perhaps you should start with his first presentation and video.
Good Luck!
I have a MainActivity in which I instantiate a class. This class contains basic data and two important methods: GetRequestAccessUrl(params) and getToken(string) which returns an AuthResponse.
The first method runs fine, the string is generated and processed in the application. However, the getToken-method involves networking and is therefore prohibited to run on the main thread and AsyncTask is recommended. The implementation of the latter method is as following:
public AuthResponse getToken(String code) {
if (secrete == null) {
throw new IllegalStateException("Application secrete is not set");
}
try {
URI uri = new URI(TOKEN_URL);
URL url = uri.toURL();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
try {
StringBuilder sb = new StringBuilder();
sb.append("client_id=" + clientId);
sb.append("&client_secret=" + secrete);
sb.append("&code=" + code);
conn.setRequestMethod("POST");
conn.setRequestProperty("Accept", "application/json");
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
os.write(sb.toString().getBytes("UTF-8"));
if (conn.getResponseCode() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ conn.getResponseCode());
}
Reader br = new InputStreamReader((conn.getInputStream()));
Gson gson = new Gson();
return gson.fromJson(br, AuthResponse.class);
} finally {
conn.disconnect();
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
In the MainActivity the entire class is created, the first method is called, some actions are executed and the the getToken-method should run. However I seem to be completely stuck on how to do this, or how to create a (working) AsyncTask regarding this method. Any help is appreciated.
new YourAsyncTask ().execute(code);
private class YourAsyncTask extends AsyncTask<String, Integer, Integer> {
protected Long doInBackground(String... codes) {
AuthResponse res = getToken(codes[0]);
doSthWithRes(res);
}
protected void onProgressUpdate(Integer... progress) {}
protected void onPostExecute(Integer result) {}
}
This will probably work. Depending on what you wanna do with the AuthResponse.
As you can see the ASyncTask is more of a batch processing in the background. I prefer just using a Standard Thread. Additionally you may want to process the AuthResponse in the UIThread.
Here the Quick and dirty version:
/* It would be better to create a subclass of Runnable and pass the Code in the constructor*/
final String code = "testcode";
//Create the new Thread
Thread t = new Thread(new Runnable() {
#Override
public void run() {
final AuthResponse res = getToken(code);
//RunOnUiThread is a method of the Activity
runOnUiThread(new Runnable() {
#Override
public void run() {
doSomethingWithResponse(res);
}
});
}
});
t.start()
Try something like this
new AsyncTask<String, void, AuthResponse>() {
#Override
protected String doInBackground(String... params) {
String id = params[0];
String secret = params[1];
String code = params[2];
//do your stuff
return myAuthResponse;
}
#Override
protected void onPostExecute(AuthReponse result) {
//do stuff with AuthResponse
}
}.execute(clientId, clientSecret, code);
In onPostExecute you can handle the AuthResponse on the UIThread.
I think that I answered this in the following thread :
Java AsyncTask passing variable to main thread
A Http request is done in background in an Asyntask and the result is sent to the main activity thanks to a Callback. I gave a sample code on the answer.
I have two AsyncTasks running and the async task that is waiting for the result is just not getting the correct result.
I have a network class that runs like so:
public ArrayList<User> searchForFriends(String activeHash, TelephoneNumber telephone)
{
Object[] obj = {activeHash, telephone};
try
{
return new SearchForFriendsTelephone().execute(obj).get(Constants.TIMEOUT_TIME, Constants.TIMEOUT_UNIT);
}
catch (InterruptedException e)
{
return null;
}
catch (ExecutionException e)
{
return null;
}
catch (TimeoutException e)
{
return null;
}
}
private class SearchForFriendsTelephone extends AsyncTask<Object, Void, ArrayList<User>>
{
#Override
protected ArrayList<User> doInBackground(Object... searchTelephone)
{
if (config.getNetworkVersion() == config.NETWORK_PROTOCOL_VERSION_1)
{
TelephoneNumber tel = (TelephoneNumber) searchTelephone[1];
List<NameValuePair> params = new ArrayList<NameValuePair>(3);
params.add(new BasicNameValuePair(NetworkConfig.POST_ACTIVE_HASH, (String) searchTelephone[0]));
params.add(new BasicNameValuePair(NetworkConfig.POST_MOBILE_NUMBER_COUNTRY_CODE, tel.getCountryCode()));
params.add(new BasicNameValuePair(NetworkConfig.POST_MOBILE_NUMBER_RAW, tel.getNumberRaw()));
ServerCommunication csc = new ServerCommunication();
JSONObject jsonFoundFriends = csc.postToServer(config.getBaseUrl() + URL_FRIEND_SEARCH_MOBILE, params);
if (jsonFoundFriends == null || csc.networkError())
{
FriendNetworkCommunication.this.networkError = csc.getNetworkError();
return null;
}
return _processSearchFriends(jsonFoundFriends);
}
FriendNetworkCommunication.this.networkError = new NetworkError(NetworkLanguage.UNABLE_TO_PROCESS);
return null;
}
Anyway this works fine with no issues and pulls back the user/s. I know this as I tried the following code in the main ui thread and it populates a view just fine. When I call this code from another AsyncTask. I get a timeout error.
Code to all the searchForFriends code:
private class CompareNumbers extends AsyncTask<ArrayList<NameAndNumber>, Integer, Void>
{
#Override
protected Void doInBackground(ArrayList<NameAndNumber>... params)
{
for (NameAndNumber nameNumber : params[0])
{
try
{
FriendNetworkCommunication fnc = new FriendNetworkCommunication();
ArrayList<User> users = fnc.searchForFriends(CurrentUser.getInstance().getUserActiveHash(), new TelephoneNumber(String.valueOf(nameNumber.getNumber().getNationalNumber()), String.valueOf(nameNumber.getNumber().getCountryCode())));
if (users != null && users.size() == 1)
{
User u = users.get(0);
String[] s = nameNumber.getName().split(" ");
u.setFirstName(s[0]);
u.setLastName(s[1]);
((ArrayAdapter<User>) ((ListView) getView().findViewById(R.id.friend_add_fragment_search_cont_list)).getAdapter()).add(u);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
((ArrayAdapter<User>) ((ListView)getView().findViewById(R.id.friend_add_fragment_search_cont_list)).getAdapter()).notifyDataSetChanged();
return null;
}
}
Can I not run an asynctask that waits on another?
NOTE: This is all running in a fragment if this makes any difference?
NOTE2: The first Asynctask runs a network call and has to be run asynchronously and so I wanted it to be like this so if I wanted I could run it anywhere synchronously
try giving the .execute() of the second async task in the onpostexecute() of the first async task.
I have found the answer to my question and this is not possible.
A full answer can be found here:
Creating another AsyncTask inside of doInBackground
i am developing application in which i am checking availability of port before reading and writing on socket. i am using following code to check status
private boolean isAvailable(String host, int port) {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(host, port), 1000);
isPortAvailable = socket.isConnected();
} catch (IOException e) {
isPortAvailable = false;
}
return isPortAvailable;
}
After this i am checking this status on onClick()
if (isAvailable(ip, Integer.parseInt(portLVR))) {
startActivity(new Intent(getApplicationContext(),ActivityLivingRoom.class));
} else
Toast.makeText(getApplicationContext(),"Connection Error !", Toast.LENGTH_SHORT).show();
but my problem is if i check this status on main thread then android will give me networkonMainThradException so how do i manage this operation using background thread?
Try this
private class SocketCheckTask extends AsyncTask<String , Integer , Boolean> {
String classname="";
public SocketCheckTask (String classname) {
this.classname=classname;
}
#Override
protected Boolean doInBackground(String... params) {
return isAvailable(params[0], Integer.parseInt(params[1]);
}
#Override
protected void onPostExecute(Boolean isAvailable) {
if (isAvailable)) {
Class c=Class.forName("yourpackage"+classname);
startActivity(new Intent(getApplicationContext(),c));
} else
Toast.makeText(getApplicationContext(),"Connection Error !", Toast.LENGTH_SHORT).show();
}
}
And send it like this
SocketCheckTask task=new SocketCheckTask ("ActivityLivingRoom");
task.execute(ipadress,port);
I think best solution would be, start a new thread on click event and putting your start activity code inside the same thread.
If you are using toast you can do it from that thread but if you plan to update UI (like red/green status) you have to use handler and messages.
FYI, Asynctask just remove the implementation of Thread and shows people a nice abstraction.
Like this:
private class CheckAvailabilityTask extends AsyncTask<Void, Void, Boolean> {
String ip;
int port;
public CheckAvailabilityTask(String ip, int port) {
this.ip = ip;
this.port = port;
}
#Override
protected Boolean doInBackground(Void... params) {
return isAvailable(this.ip, this.port);
}
#Override
protected void onPostExecute(Boolean isAvailable) {
if (iisAvailable) {
startActivity(new Intent(getApplicationContext(),ActivityLivingRoom.class));
} else
Toast.makeText(getApplicationContext(),"Connection Error !", Toast.LENGTH_SHORT).show();
}
}
And in onClick() event:
new CheckAvailabilityTask(IP, PORT).execute();
You can't open a socket and never close it just to establish whether a host:port is available.
The only real way to test whether any service or resource is available is to try to use it.
Just do the connect, and the I/O, when you need to do them, and handle the resulting exceptions at that point. You have to catch them anyway.
Don't write code that tries to predict the future.