There is a problem when it tries to page in a normal java class everything works fine, but if this is done already in the android app, the answer comes "you don't have permission to access" while the user-agent is specified in the android manifest has the permission to use the Internet and all this in a separate thread, can someone faced with this problem
public void onClick(View view)
{
new Thread(new Runnable() {
#Override
public void run()
{
go();
}
}).start();
}
private void go()
{
try {
document = Jsoup.connect("http://issa.beltelecom.by/main.html").userAgent("Chrome 53.0.2785.143").ignoreHttpErrors(true).get();
} catch (IOException e) {
e.printStackTrace();
}
}
It seems to be important to set the Accept header field (note: tested on Android 5.1.1 device).
In general: if the connection is refused using jsoup, inspect the requests (for example using the networks tab in the chrome dev tools/F12) and add missing header fields.
Example Code
String userAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36";
String url = "https://issa.beltelecom.by/main.html";
String acceptValue = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
String host = "issa.beltelecom.by";
document = Jsoup.connect(url).header("Accept",acceptValue).header("Host", host).userAgent(userAgent).get();
You can try this, set your OnClickListener to call the background task.
new MyAsyncTask().execute();
Then perform your task
private class MyAsyncTask extends AsyncTask<Void, Void, Boolean> {
protected void onPreExecute() {
super.onPreExecute();
//do anything here
}
protected Boolean doInBackground(Void...param) {
Document document = null;
try {
document = Jsoup.connect(getString(R.string.your_url_string)).get();
} catch (IOException e) {
e.printStackTrace();
}
if (document != null) {
Elements yourElements = document.select("#element_id");
//Do anything here
return true;
}
//Document is null
return false;
}
protected void onPostExecute(Boolean result) {
if(result==true) {
// do this
}
}
}
Related
Been looking on the internet how to check the current app version of the application and the version available on Play Store. But it was using Asynctask that was deprecated already and Ive been looking alternative way aside from Asynctask been searching on the internet but I couldnt figure out how to do it correctly. Please check the code below:
private class GetLatestVersion extends AsyncTask<String, String, String> {
private String latestVersion;
private ProgressDialog progressDialog;
private boolean manualCheck;
GetLatestVersion(boolean manualCheck) {
this.manualCheck = manualCheck;
}
String currentVersion = getCurrentVersion();
//If the versions are not the same
if(!currentVersion.equals(latestVersion)&&latestVersion!=null){
final Dialog dialog = new Dialog(activity);
dialog.setContentView(R.layout.custom_warning_dialog);
dialog.setCancelable(false);
Button tryAgain = dialog.findViewById(R.id.bt_positive);
Button settings = dialog.findViewById(R.id.bt_negative);
tryAgain.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id="+activity.getPackageName())));
dialog.dismiss();
}
});
settings.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
activity.finish();
}
});
dialog.show();
}else {
if (manualCheck) {
Toast.makeText(activity, "No Update Available", Toast.LENGTH_SHORT).show();
}
}
}
#Override
protected String doInBackground(String... params) {
try {
//It retrieves the latest version by scraping the content of current version from play store at runtime
latestVersion = Jsoup.connect("https://play.google.com/store/apps/details?id=" + activity.getPackageName() + "&hl=en")
.timeout(30000)
.userAgent("Mozilla/5.0 (Windows; U; WindowsNT 5.1; en-US; rv1.8.1.6) Gecko/20070725 Firefox/2.0.0.6")
.referrer("http://www.google.com")
.get()
.select(".hAyfc .htlgb")
.get(7)
.ownText();
return latestVersion;
} catch (Exception e) {
return latestVersion;
}
}
}
Here's how you can basically convert asyncTask to coroutine on kotlin
private suspend fun GetLatestVersion(String,String,String) {
withContext(Dispatcher.Default)
{
// you just have to refactor all your code inside doInBaakground inside this withContext
}
//then if you want to update the UI
withContext(Dispatchers.Main)
{
//return code for your task
}
}
See this link . For further information.
Thanks Ginxx, but I used executer instead of coroutine since I am only a beginner but it might help others who the same as me.
Check my update codes below:
public void CheckLatestAppVersionFromPlayStore() {
final String[] latestAppVersionFromPlayStore = new String[1];
ExecutorService executor = Executors.newSingleThreadExecutor();
final Handler handler = new Handler(Looper.getMainLooper());
executor.execute(new Runnable() {
#Override
public void run() {
try {
//It retrieves the latest version by scraping the content of current version from play store at runtime
latestAppVersionFromPlayStore[0] = Jsoup.connect("https://play.google.com/store/apps/details?id=" + activityWeakReference.get().getPackageName() + "&hl=it")
.timeout(30000)
.userAgent("Mozilla/5.0 (Windows; U; WindowsNT 5.1; en-US; rv1.8.1.6) Gecko/20070725 Firefox/2.0.0.6")
.referrer("http://www.google.com")
.get()
.select(".hAyfc .htlgb")
.get(7)
.ownText();
} catch (Exception e) {
e.printStackTrace();
}
handler.post(new Runnable() {
#Override
public void run() {
final String installedAppVersion = currentVersionName;
//If the versions are not the same
if (!installedAppVersion.equals(latestAppVersionFromPlayStore[0]))
if (latestAppVersionFromPlayStore[0] != null) {
final Dialog dialog = new Dialog(activityWeakReference.get());
dialog.setContentView(R.layout.custom_warning_dialog);
dialog.setCancelable(false);
Button tryAgain = dialog.findViewById(R.id.bt_positive);
Button settings = dialog.findViewById(R.id.bt_negative);
tryAgain.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
activityWeakReference.get().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + activityWeakReference.get().getPackageName())));
}
});
settings.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
activityWeakReference.get().finish();
}
});
// to avoid the bad token exception
if ((activityWeakReference.get() != null) && (!activityWeakReference.get().isFinishing()) && (!activityWeakReference.get().isDestroyed()))
dialog.show();
}
}
});
}
});
}
For further information please click this link.
The following code ran on a java file on my computer gives the correct result of "/pws/client/pdf/offers-in-store-10-11-16.pdf"
String pdfLink= null;
try {
Document doc = Jsoup.connect("http://www.dunnesstores.com/offer20/food-wine/fcp-category/home").get();
Element links = doc.select("a[title=\"Download offers in store\"]").first();
System.out.println(links.attr("href"));
} catch (IOException e) {
//e.printStackTrace();
}
However when I run the code on my android device in an app where it is activated by the button press,I get a null pointer exception on "pdfLink=links.attr("href");" so it isnt finding the link "/pws/client/pdf/offers-in-store-10-11-16.pdf" for whatever reason.In my android app the code is on a onclick listener of a button and I have stepped through the code,it does activate the on click and runs the right lines of code but for whatever reason JSOUP is not finding the link.Below is the android code
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnFetchData = (Button) findViewById(R.id.buttonTest);
btnFetchData.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new FetchWebsiteData().execute();
}
});
}
private class FetchWebsiteData extends AsyncTask<Void, Void, Void> {
private String pdfLink = "didnt work";
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
try {
Document doc = Jsoup.connect("http://www.dunnesstores.com/offer20/food-wine/fcp-category/home").get();
//Elements links = doc.select("a[title=\"Download offers in store\"]");
Element links = doc.select("a[title=\"Download offers in store\"]").first();
pdfLink=links.attr("href");
} catch (IOException e) {
//e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
TextView txttitle = (TextView) findViewById(R.id.resultTextView);
txttitle.setText(pdfLink);
}
}
}
the mobile browser user-agent differs from the desktop browser; therefore, the HTML responses differ. In order to get the same result you have to set a desktop user-agent. Change this line :
Document doc = Jsoup.connect("http://www.dunnesstores.com/offer20/food-wine/fcp-category/home").get();
to:
Document doc = Jsoup.connect("http://www.dunnesstores.com/offer20/food-wine/fcp-category/home").userAgent("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0").get();
I am making an android app which requires it to fetch some information from a remote server and therefore i have to make a http request in a async task.Now the problem is that that the response sometimes take more than 2 secs and when it does it give http timeout exception but most of the time it works just fine .So i want to implement the functionality that when i recieve a http timeout exception i want to retry the request again(try the doinBackground again,because network call can only be made in thread other than the main thread) because chances are that it will be successful and all the things that need to be fetched from the remote server will occur in CallRemoteServer() method
Now in my program i have implemented something like this
new AsyncTask<Void, Void, Void>() {
private boolean httpResponseOK = true;
#Override
protected Void doInBackground(Void... params) {
try {
CallRemoteServer();
}
} catch (Exception e) {
httpResponseOK = false;
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
if (httpResponseOK == false) {
//Show an alert dialog stating that unable to coonect
}
else
{
//update UI with the information fetched
}
});
Can someone advice me how can i implement something which i have mentioned above ,i mean that if i get some other exception other than timeout than show an alert dialog otherwise retry atleast five time more CallRemoteServer method before showing the dialog that unable to connect.
I am not able to think of any good way to implement this logic.
Thanks in advance
You're probably getting a ConnectTimeoutException (or check in the logs what is the IOException you're getting). I would first try to extend the timeout. Some similar answers for this can be found here or here.
However, an auto-reconnect mechanism is a must to have. I would implement it using recursive code:
final int maxAttempts = 5;
protected MyServerData callRemoteServer(int attempt) throws IOException {
try {
// do the IO stuff and in case of success return some data
} catch (ConnectTimeoutException ex) {
if(attempt == maxAttempts) {
return callRemoteServer(attempt + 1);
} else {
throw ex;
}
}
}
Your doInBackground method should look like:
#Override
protected Void doInBackground(Void... params) {
try {
callRemoteServer(0);
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
In this way if the connection timeouts it will attempt to retry for 5 max times (you can set the max attempts to anything you like). Just make sure to return some data from this IO operation as that is the most valuable asset from that method anyway ...
For this reason I would change it to following:
private class MyAsynckTask extends AsyncTask<Void, Void, MyServerData> {
#Override
protected MyServerData doInBackground(Void... params) {
try {
return callRemoteServer(0);
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(MyServerData result) {
if(result != null) {
// display data on UI
}
}
}
I'm trying to add import contacts from gmail account function in my android app. So the first problem is to get access token from gmail. I've found that there is GoogleAuthUtil class which can help me with it.
Here is my code:
private void importContactsFromGmail() {
showProgressDialog();
GetTokenTask getTokenTask = new GetTokenTask();
getTokenTask.execute();
String token = "";
try {
token = getTokenTask.get();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(token);
hideProgressDialog();
}
private class GetTokenTask extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
String token = "";
try {
token = GoogleAuthUtil.getToken(activity, <My_gmail_account>, "https://www.google.com/m8/feeds/");
} catch (Exception e) {
e.printStackTrace();
}
return token;
}
}
Now after calling GoogleAuthUtil.getToken my app completely freezes(no errors in Logcat). I completely stuck and I need your help.
What is wrong with my code? Maybe I should import contacts in some other way?
Not sure if this is related but calling the .get() method on the main thread is not correct because is blocking method.
What if you use the AsyncTask in this way?
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new GetTokenTask().execute();
}
static class GetTokenTask extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... unused) {
String token = "";
try {
token = GoogleAuthUtil.getToken(activity, <My_gmail_account>, "https://www.google.com/m8/feeds/");
} catch (Exception e) {
e.printStackTrace();
}
return token;
}
#Override
protected void onPostExecute(String token) {
Toast.makeText(MainActivity.this, token, Toast.LENGTH_SHORT).show();
}
}
}
(I wrote without compiling it, maybe it needs to be adjusted)
On Android devices, Gmail contacts are synced locally onto the device and are available via a public Contacts Provider, therefore there's no reason you'd need to use the Google API to pull what is already available. There is a whole training series dedicated specifically to retrieving a list of contacts.
Note that the Contacts training series does assume you have knowledge of Content Providers already, so it may be helpful to read up on the basics of Content Providers as well.
In my app I performing loading data from web and then displaying it to user. Before loading data app shows progress dialog. I have problem if user locks phone in the middle of loading operation, or server is overloaded and can't respond in time my application freezes, because it doesn't dismiss progress dialog, or in some cases it crashes because lack on needed data.
If some error happened while loading data I want show some dialog to user to let him know about error and ask him should application repeat last request. I tried to use AlertDialog for it, but I haven't succeed.
Here is code of one activity (There is no progress dialog here, but it demonstrates how I loading data):
#EActivity(R.layout.layout_splash)
#RoboGuice
public class SplashScreenActivity extends Activity {
#Inject
private AvtopoiskParserImpl parser;
#Bean
BrandsAndRegionsHolder brandsAndRegionsHolder;
#ViewById(R.id.splash_progress)
ProgressBar progressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loadData();
}
#Background
protected void loadData() {
publishProgress(10);
LinkedHashMap<String, Integer> brands = null;
try {
brands = parser.getBrands();
} catch (IOException e) {
Log.e(e.getMessage());
}
publishProgress(50);
LinkedHashMap<String, Integer> regions = null;
try {
regions = parser.getRegions();
} catch (IOException e) {
Log.e(e.getMessage());
}
publishProgress(70);
populateData(brands, regions);
}
#UiThread
protected void populateData(LinkedHashMap<String, Integer> brands, LinkedHashMap<String, Integer> regions) {
Intent intent = new Intent(SplashScreenActivity.this, SearchActivity_.class);
brandsAndRegionsHolder.brandsMap = brands;
brandsAndRegionsHolder.regionsMap = regions;
publishProgress(100);
startActivity(intent);
finish();
}
#UiThread
void publishProgress(int progress) {
progressBar.setProgress(progress);
}
}
parser.getBrands() and parser.getRegions() are loading data from the web.
I want to do something like this:
boolean repeatRequest = true;
while (repeatRequest) {
try {
brands = parser.getBrands();
repeatRequest = false;
} catch (IOException e) {
Log.e(e.getMessage());
repeatRequest = showErrorDialog();
}
}
But I didn't manage to do so because this code executes in background thread, but dialog should be shown in UI thread.
I believe that it should be standard approach of doing so, but didn't manage to find it.
Any ides how can I implement this?
The best way is to use AsyncTask.
private class LoadDataTask extends AsyncTask<Void, Integer, Object> {
private ProgressDialog mProgress;
protected Object doInBackground(Void... params) {
// This method runs in background
Object result = null;
try {
result = parser.parse();
} catch (Exception e) {
result = e.getMessage();
}
return result;
}
protected void onProgressUpdate(Integer... progress) {
// This method runs in UI thread
mProgress.setProgress(progress[0]);
}
protected void onPreExecute() {
// This method runs in UI thread
mProgress = new ProgressDialog(context);
mProgress.show();
}
protected void onPostExecute(Object result) {
// This method runs in UI thread
mProgress.dismiss();
if (result instance of String) {
// Here you can launch AlertDialog with error message and proposal to retry
showErrorDialog((String) result);
} else {
populateData(result);
}
}
}