My app crashes when the link is empty. I am trying to download Instagram videos. The apps work fine with public links. But I put a private link the app crashes. This means with a private link the apps get no HTML from the website. And the download links remain empty. Which causes the app to crash. I want when enter a private link app wouldn't crash
I tried to use if-else statements in the onPostExecute method but it didn't work or maybe I am doing it the wrong way.
This AsyncTask class
private class InstaVideo extends AsyncTask<Void, Void, Void> {
String dlink, imglink;
#Override
protected void onPreExecute() {
ProgressBar progressBar = (ProgressBar) findViewById(R.id.loading_indicator);
progressBar.setVisibility(View.VISIBLE);
DoubleBounce doubleBounce = new DoubleBounce();
progressBar.setIndeterminateDrawable(doubleBounce);
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... voids) {
try {
Document doc = Jsoup.connect("https://www.10insta.net/#grid-gallery")
.data("url", temp)
.post();
Log.v("Hello", doc.title());
Element srctag = doc.select("img.card-img-top").first();
Element ptag = doc.select("p.card-text").first();
Element atag = ptag.select("a").first();
imglink = srctag.attr("src");
dlink = "https://www.10insta.net/";
dlink += atag.attr("href");
Log.i("DownloadActivity",dlink);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
if (dlink=="https://www.10insta.net/download.php?url=") {
Toast.makeText(DownloadActivity.this,"Link is private",Toast.LENGTH_SHORT).show();
} else {
View loadingIndicator = findViewById(R.id.loading_indicator);
loadingIndicator.setVisibility(View.GONE);
TextView t = (TextView) findViewById(R.id.imgtxt);
if (Content.id == 2) {
t.setText("Video Preview");
} else {
t.setText("Image Preview");
}
t.setVisibility(View.VISIBLE);
Button b = (Button) findViewById(R.id.instadownload);
b.setVisibility(View.VISIBLE);
final ImageView img = (ImageView) findViewById(R.id.instaimg);
Picasso.get().load(imglink).placeholder(R.drawable.loading).into(img);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
DownloadManager dm = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
Uri uri = Uri.parse(dlink);
DownloadManager.Request req = new DownloadManager.Request(uri);
req.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
if (Content.id == 2) {
req.setDestinationInExternalPublicDir("/VideoDownloader", "insta.mp4");
} else {
req.setDestinationInExternalPublicDir("/VideoDownloader", "insta.jpg");
}
StyleableToast.makeText(getBaseContext(), "Download Started", Toast.LENGTH_SHORT, R.style.mytoast).show();
Long ref = dm.enqueue(req);
}
});
}
}
}
doInBackground fetch HTML from the website and filters the required video download link. This works fine with public links but crashes with private links.
Now I want when I enter a private link app wouldn't crash. help is much appreciated
Error Image
Since you have mentioned if-else not working to check image path then try to consume the exception using try - catch block.
try {
Picasso.get().load(imglink).placeholder(R.drawable.loading).into(img);
} catch(Exception ex) {
ex.printStackTrace();
t.setVisibility(View.GONE);
b.setVisibility(View.GONE);
}
Besides this, you use == operator to compare String which give you false always. Try using equals()/equalsIgnoreCase()
if (dlink.equalsIgnoreCase("https://www.10insta.net/download.php?url="))
Related
I'm currently making a small app and I'm getting stuck on changing fragments using an onClick listener. I've searched the site and could find similar situations, but none of the proposed solutions worked.
So, when a user logs in, it sets a few values in SharedPreferences such as username, email and account level using a method from a class used to set and get SharedPreferences values. Afterwards, it should automatically redirect the user to a different Fragment. What's not happening, is redirecting the user to the other fragment.
I'm using AsyncTask for accessing the database. This is my code for the Login AsyncTask:
public class LoginSync extends AsyncTask <String, Void, String> {
AlertDialog dialog;
Context context;
String result;
JSONObject jObject;
String username, password;
String jEmail, jLevel;
public LoginSync(Context context){
this.context = context;
}
#Override
protected void onPreExecute() {
dialog = new AlertDialog.Builder(context).create();
dialog.setTitle("Login Status");
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if(result.equals("login")) {
dialog.setMessage("Logged in successfully!");
}else{
dialog.setMessage("Failed to login! Please check username/password.");
}
dialog.show();
}
#Override
protected String doInBackground(String... voids) {
username = voids[0];
password = voids[1];
String connstr = "URL HERE";
try{
URL url = new URL(connstr);
HttpURLConnection http = (HttpURLConnection) url.openConnection();
http.setRequestMethod("POST");
http.setDoInput(true);
http.setDoOutput(true);
OutputStream ops = http.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(ops, StandardCharsets.UTF_8));
String data = URLEncoder.encode("username","UTF-8")+"="+URLEncoder.encode(username,"UTF-8")
+"&&"+URLEncoder.encode("password","UTF-8")+"="+URLEncoder.encode(password,"UTF-8");
writer.write(data);
writer.flush();
writer.close();
ops.close();
InputStream ips = http.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(ips, StandardCharsets.ISO_8859_1));
String line;
while((line = reader.readLine()) != null){
jObject = new JSONObject(line);
result = "false";
if (jObject != null){
jEmail = jObject.getString("email");
jLevel = jObject.getString("account_level");
result = "login";
}
}
if(result.equals("login")) {
AppPreferences.setUserInfo(context.getApplicationContext(), username,jEmail,jLevel);
AppPreferences.setLoggedStatus(context.getApplicationContext(), true);
}
reader.close();
ips.close();
http.disconnect();
return result;
}catch (MalformedURLException e){
result = e.getMessage();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return result;
}
}
Using the debugger, I see that the values are being set as intended in the SharedPreferences. However, in the onClick check on the Login Fragment, it's set to false until the onClick method ends.
This is my Login Fragment code:
public class LoginFragment extends Fragment {
private FragmentLoginBinding binding;
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
binding = FragmentLoginBinding.inflate(inflater, container, false);
View root = binding.getRoot();
binding.btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final String user = binding.username.getText().toString().trim();
final String pass = binding.password.getText().toString().trim();
LoginSync login = new LoginSync(getActivity());
login.execute(user,pass);
if(AppPreferences.getLoggedStatusBool(getActivity()).equals(true)){
NavHostFragment.findNavController(getParentFragment()).navigate(R.id.action_nav_login_to_nav_home);
}
}
});
binding.lnkRegister.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
NavHostFragment.findNavController(getParentFragment()).navigate(R.id.action_nav_login_to_nav_register);
}
});
return root;
}
#Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}
On the first click, the values are set correctly, but checking the onClick with the debugger tells me that it's still false, after running the AsyncTask, and it doesn't trigger the fragment change in the if clause. On the second click, it changes the fragment.
What am I doing wrong? How can I make it change the fragment on the same click as it sets the information?
Thank you.
You are getting correct value from sharedPreference, only your timing to get that value is not correct. You are using async task, which works on a different thread. in your onCLick you have these lines:
LoginSync login = new LoginSync(getActivity());
login.execute(user,pass);
if(AppPreferences.getLoggedStatusBool(getActivity()).equals(true)){
NavHostFragment.findNavController(getParentFragment()).navigate(R.id.action_nav_login_to_nav_home);
}
you must have assumed that your if statement will execute after your login async task is completed, but this will not happen, it will execute straight after starting the login process and will check the sharedPref before the value is even set. You are doing network call and IO operation which will take some time and shared pref should be checked after the async task has been completed. So yo should write your if statement in async class's onPostExecute method like this:
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if(result.equals("login")) {
dialog.setMessage("Logged in successfully!");
if(AppPreferences.getLoggedStatusBool(getActivity()).equals(true)){
NavHostFragment.findNavController(getParentFragment()).navigate(R.id.action_nav_login_to_nav_home);
}
}else{
dialog.setMessage("Failed to login! Please check username/password.");
}
dialog.show();
}
I am trying to develop an application that reads jokes from a URL. I am using an AsyncTask to read from URL and then put the string to a textView. But I can't figure out why it isn't working.
Here is my code:
public class MainActivity extends AppCompatActivity {
private Button oneJokeBtn, threeJokesBtn;
private final static String ERROR_TAG = "Download Error";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Capturing our buttons from the view
oneJokeBtn = findViewById(R.id.joke_1);
threeJokesBtn = findViewById(R.id.joke_3);
// Register the onClick listener
oneJokeBtn.setOnClickListener(buttonHandler);
threeJokesBtn.setOnClickListener(buttonHandler);
// Declaring the Spinner
Spinner spinner = findViewById(R.id.spinner);
// Create an ArrayAdapter using the string array and a default spinner layout
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
R.array.length_array, android.R.layout.simple_spinner_item);
// Specify the layout to use when the list of choices appears
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// Apply the adapter to the spinner
spinner.setAdapter(adapter);
// Spinner onItemSelector implemented in the OnCreate Method
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
switch (position){
case 0:
Toast.makeText(parent.getContext(), R.string.short_toast, Toast.LENGTH_SHORT).show();
break;
case 1:
Toast.makeText(parent.getContext(), R.string.medium_toast, Toast.LENGTH_SHORT).show();
break;
case 2:
Toast.makeText(parent.getContext(), R.string.long_toast, Toast.LENGTH_SHORT).show();
break;
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
/** AsyncTask that reads one joke directly from the URL and adds it to the textView */
private class Download1JokeAsyncTask extends AsyncTask <Void, Void, String> {
private ProgressDialog progressDialog;
private String mResponse = "";
#Override
protected void onPreExecute() {
progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setMessage(getString(R.string.progress_msg));
progressDialog.setIndeterminate(true);
progressDialog.show();
}
#Override
protected String doInBackground(Void... voids) {
String joke = null;
try {
// Open a connection to the web service
URL url = new URL( "http://www-staff.it.uts.edu.au/~rheise/sarcastic.cgi" );
URLConnection conn = url.openConnection();
// Obtain the input stream
BufferedReader in = new BufferedReader( new InputStreamReader(conn.getInputStream()));
// The joke is a one liner, so just read one line.
joke = in.readLine();
// Close the connection
in.close();
} catch (MalformedURLException e) {
e.printStackTrace();
Log.e(ERROR_TAG, "Exception: ", e);
mResponse = getString(R.string.fail_msg);
} catch (IOException e) {
e.printStackTrace();
Log.e(ERROR_TAG, "Exception: ", e);
mResponse = getString(R.string.fail_msg);
}
return joke;
}
#Override
protected void onPostExecute(String joke) {
TextView tv = findViewById(R.id.tv_joke);
if (joke == null) {
tv.setText(R.string.fail_msg);
}
else {
tv.setText(joke);
}
if (progressDialog.isShowing()) {
progressDialog.dismiss();
}
}
}
/** AsyncTask that reads three jokes directly from the URL and adds it to the textView */
private class Download3JokeAsyncTask extends AsyncTask<Void, Integer, String[]> {
private ProgressDialog mProgressDialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog = new ProgressDialog(MainActivity.this);
mProgressDialog.setProgress(0);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setIndeterminate(false);
mProgressDialog.setMax(100);
mProgressDialog.setCancelable(true);
mProgressDialog.setMessage(getString(R.string.three_jokes_btn));
mProgressDialog.show();
}
#Override
protected String[] doInBackground(Void... voids) {
int count = 2;
for (int i = 0; i < 2; i++){
try {
URL url = new URL("http://www.oracle.com/");
URLConnection conn = url.openConnection();
// Obtain the input stream
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
// The joke is a one liner, so just read one line.
String joke;
while ((joke = in.readLine()) != null) {
System.out.println(joke);
}
// Close the connection
in.close();
} catch (MalformedURLException e) {
e.printStackTrace();
Log.e(ERROR_TAG, "Exception: ", e);
} catch (IOException e) {
e.printStackTrace();
Log.e(ERROR_TAG, "Exception: ", e);
}
publishProgress((int) ((i / (float) count) * 100));
}
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
setProgress(0);
}
#Override
protected void onPostExecute(String[] strings) {
super.onPostExecute(strings);
}
}
/** onClickListener that gets the id of the button pressed and download jokes accordingly */
OnClickListener buttonHandler = new OnClickListener() {
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.joke_1:
new Download1JokeAsyncTask().execute();
break;
case R.id.joke_3:
new Download3JokeAsyncTask().execute();
break;
}
}
};
The AsyncTask is called Download1JokeAsyncTask, it is supposed to read from URL and then put it into a text view. and I've put an error message to appear in the text view if the joke (the string where the joke is stored) is null.
And always the text view says that it failed to download a message.
Please help.
I went to your joke page and inspecting the source (in Firefox) and I found this:
<html>
<head>
<link rel="alternate stylesheet" type="text/css" href="resource://content-accessible/plaintext.css" title="Wrap Long Lines">
</head>
<body>
<pre>I'm really good at stuff until people watch me do that stuff.</pre>
</body>
</html>
So you could save the whole output as a String and then use this:
string.substring(string.indexOf("<pre>"), string.indexOf("</pre>");
string.substring(4);
Basically you are downloading only the first line of the page which would be the content declaration.
Instead you need to download the sixth line and remove the pre tags.
Good Luck!
i want to fetch data from website to my android app ,so i used jsoup.
Document document = Jsoup.connect(url).get();
error in this line of my project.i use above line three time as my requirement but all the three time where this above line is use and all three line shows error message.
Help how to remove this error ..
if anyone knows any other easy method/way to get(fetch) data from dynamic website data to android app kindly also mention that way..
public class Jsoup extends Activity{
// URL Address
String url = "http://www.vogella.com/tutorials/Android/article.html";
ProgressDialog mProgressDialog;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Locate the Buttons in activity_main.xml
Button titlebutton = (Button) findViewById(R.id.titlebutton);
Button descbutton = (Button) findViewById(R.id.descbutton);
Button logobutton = (Button) findViewById(R.id.logobutton);
// Capture button click
titlebutton.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
// Execute Title AsyncTask
new Title().execute();
}
});
// Capture button click
descbutton.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
// Execute Description AsyncTask
new Description().execute();
}
});
// Capture button click
logobutton.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
// Execute Logo AsyncTask
new Logo().execute();
}
});
}
// Title AsyncTask
private class Title extends AsyncTask<Void, Void, Void> {
String title;
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog = new ProgressDialog(Jsoup.this);
mProgressDialog.setTitle("Android Basic JSoup Tutorial");
mProgressDialog.setMessage("Loading...");
mProgressDialog.setIndeterminate(false);
mProgressDialog.show();
}
#Override
protected Void doInBackground(Void... params) {
try {
// Connect to the web site
Document document = Jsoup.connect(url).get();
// Get the html document title
title = document.title();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
// Set title into TextView
TextView txttitle = (TextView) findViewById(R.id.titletxt);
txttitle.setText(title);
mProgressDialog.dismiss();
}
}
// Description AsyncTask
private class Description extends AsyncTask<Void, Void, Void> {
String desc;
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog = new ProgressDialog(Jsoup.this);
mProgressDialog.setTitle("Android Basic JSoup Tutorial");
mProgressDialog.setMessage("Loading...");
mProgressDialog.setIndeterminate(false);
mProgressDialog.show();
}
#Override
protected Void doInBackground(Void... params) {
try {
// Connect to the web site
Document document = Jsoup.connect(url).get();
// Using Elements to get the Meta data
Elements description = document
.select("meta[name=description]");
// Locate the content attribute
desc = description.attr("content");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
// Set description into TextView
TextView txtdesc = (TextView) findViewById(R.id.desctxt);
txtdesc.setText(desc);
mProgressDialog.dismiss();
}
}
// Logo AsyncTask
private class Logo extends AsyncTask<Void, Void, Void> {
Bitmap bitmap;
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog = new ProgressDialog(Jsoup.this);
mProgressDialog.setTitle("Android Basic JSoup Tutorial");
mProgressDialog.setMessage("Loading...");
mProgressDialog.setIndeterminate(false);
mProgressDialog.show();
}
#Override
protected Void doInBackground(Void... params) {
try {
// Connect to the web site
Document document = Jsoup.connect(url).get();
// Using Elements to get the class data
Elements img = document.select("a[class=brand brand-image] img[src]");
// Locate the src attribute
String imgSrc = img.attr("src");
// Download image from URL
InputStream input = new java.net.URL(imgSrc).openStream();
// Decode Bitmap
bitmap = BitmapFactory.decodeStream(input);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
// Set downloaded image into ImageView
ImageView logoimg = (ImageView) findViewById(R.id.logo);
logoimg.setImageBitmap(bitmap);
mProgressDialog.dismiss();
}
}
}
You shouldn't name your class same way as already existing classes because compiler will connect each call of simplified name to current class, not to the class from imports. For instance
class String {
public static void main(String[] args) {
System.out.println(String.valueOf("1"));
}
}
will not compile because String.valueOf will not try to invoke valueOf from java.lang.String but from your class, and since there is no such method there you are seeing error saying that such method is undefined.
So change name of your class
public class Jsoup extends Activity{
...{
Document document = Jsoup.connect(url).get();
}
}
to something more like
public class JsoupActivity extends Activity{
// ^^^^^^^^^^^^^
...{
Document document = Jsoup.connect(url).get();
}
}
So, I want to display a spinning loading indicator while my ListView is being populated. I successfully have implemented the progress bar, BUT for some reason it disappears BEFORE all of the listings are displayed. What I want is the progressbar to be present during the TOTAL load time of the listings. Basically, what it seems like, each listing is being displayed one at a time, not all at once when they are all loaded.
What I'm doing is
1. Creating a new custom adapter class
2. Populating the ListView in an AsyncTask using this adapter class
3. Setting the ListView to this adapter
This works properly, the progress bar just disappears before all of the listings are displayed. Does anyone have any ideas?
Activity class:
public class MainActivity extends ActionBarActivity {
ArrayList<Location> arrayOfLocations;
LocationAdapter adapter;
// public static Bitmap bitmap;
Button refresh;
ProgressBar progress;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progress=(ProgressBar)findViewById(R.id.progressbar_loading);
// Construct the data source
arrayOfLocations = new ArrayList<Location>();
// Create the adapter to convert the array to views
adapter = new LocationAdapter(this, arrayOfLocations);
FillLocations myFill = new FillLocations();
myFill.execute();
refresh = (Button) findViewById(R.id.refresh);
refresh.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
finish();
startActivity(getIntent());
}
});
}
private class FillLocations extends AsyncTask<Integer, Void, String> {
String msg = "Done";
protected void onPreExecute() {
progress.setVisibility(View.VISIBLE);
}
// Decode image in background.
#Override
protected String doInBackground(Integer... params) {
String result = "";
InputStream isr = null;
try {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://afs.spotcontent.com/"); // YOUR
// PHP
// SCRIPT
// ADDRESS
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
isr = entity.getContent();
// resultView.setText("connected");
} catch (Exception e) {
Log.e("log_tag", "Error in http connection " + e.toString());
}
// convert response to string
try {
BufferedReader reader = new BufferedReader(
new InputStreamReader(isr, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
isr.close();
result = sb.toString();
} catch (Exception e) {
Log.e("log_tag", "Error converting result " + e.toString());
}
// parse json data
try {
JSONArray jArray = new JSONArray(result);
for (int i = 0; i < jArray.length(); i++) {
final JSONObject json = jArray.getJSONObject(i);
try {
BitmapWorkerTask myTask = new BitmapWorkerTask(
json.getInt("ID"), json);
myTask.execute();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (Exception e) {
// TODO: handle exception
Log.e("log_tag", "Error Parsing Data " + e.toString());
}
return msg;
}
protected void onPostExecute(String msg) {
// Attach the adapter to a ListView
ListView listView = (ListView) findViewById(R.id.listView1);
// View header = (View) getLayoutInflater().inflate(
// R.layout.listview_header, null);
// listView.addHeaderView(header);
listView.setAdapter(adapter);
progress.setVisibility(View.GONE);
}
}
}
Adapter class:
public class LocationAdapter extends ArrayAdapter<Location> {
public LocationAdapter(Context context, ArrayList<Location> locations) {
super(context, R.layout.item_location, locations);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
Location location = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_location, parent, false);
}
// Lookup view for data population
TextView tvName = (TextView) convertView.findViewById(R.id.tvName);
TextView tvDetails = (TextView) convertView.findViewById(R.id.tvDetails);
TextView tvDistance = (TextView) convertView.findViewById(R.id.tvDistance);
TextView tvHours = (TextView) convertView.findViewById(R.id.tvHours);
ImageView ivIcon = (ImageView) convertView.findViewById(R.id.imgIcon);
// Populate the data into the template view using the data object
tvName.setText(location.name);
tvDetails.setText(location.details);
tvDistance.setText(location.distance);
tvHours.setText(location.hours);
ivIcon.setImageBitmap(location.icon);
// Return the completed view to render on screen
return convertView;
}
}
The reason for that behavior is that you are starting multiple threads.
FillLocations preExecute --> SHOW ProgressBar
BitmapWorkerTask_1 --> new thread
BitmapWorkerTask_2 --> new thread
...
BitmapWorkerTask_N --> new thread
FillLocations postExecute --> HIDE ProgressBar
BitmapWorkerTask_K --> continue execution
BitmapWorkerTask_K+1 --> continue execution
etc.
If you want the list to be displayed until it's all loaded, Simply make BitmapWorker's processing synchronous. If you still want to display the list right away but keep the spinner until it's all finished, then keep a counter in your activity and increase it in preexecute and decrease it in postExecute of BitmapWorker via a setter. Once the counter hits 0, remove hide the progressBar.
In activity:
private int asynchCounter = 0;
private void updateCounter(int delta){
asynchCounter+=delta;
if(asynchCounter<=0){
progress.setVisibility(View.GONE);
}else{
progress.setVisibility(View.VISIBLE);
}
}
And instead of BitmapWorkerTask use
class CountedBitmapWorkerTask extends BitmapWorkerTask {
protected void onPreExecute() {
super.onPreExecute();
updateCounter(1);
}
protected void onPostExecute(String msg) {
super.onPostExecute();
updateCounter(-1);
}
}
I had this exact problem, to solve it I had to write AsyncTask complete listener. Which sends a notification to UI thread, that data was loaded and it has to change something, in this case hide the ProgressBar.
This is the basic example of how this should look like. I am not sure this will work for you after you copy it to your project, but complete listener is what you need, so after studying this case you should be able to find a solution.
AsyncTaskCompleteListener.java - listener interface.
public interface AsyncTaskCompleteListener {
public void onTaskComplete();
}
LoadDataTask.java
class LoadDataTask extends AsyncTask<Object, Object, Object> {
/* Your object types according to your task. */
private AsyncTaskCompleteListener callback; // Callback field
public LoadDataTask(AsyncTaskCompleteListener cb){
this.callback = cb;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Object doInBackground(String... urls) {
/* Your task here */
return result;
}
#Override
protected void onPostExecute(Object o) {
callback.onTaskComplete(); // Set the Callback
}
}
MainActivity.java
public class MainActivity implements AsyncTaskCompleteListener{
/* ...Other methods and fields... */
/* onTaskComplete method which fires after your data is loaded. */
#Override
public void onTaskComplete(){
// Hide ProgressBar
}
}
Self Plug: https://github.com/horvste/EasyWebPageDownloadForAndroid
This would separate the threading from the implementation and solve your problem. This is very similar to what Tony suggested except it's already implemented for you.
Github Readme:
Good for connecting to REST API's, HTML parsing, and many other uses. Using this library is meant to be easy:
Create a class which implements OnProgressUpdate
public class SampleClass implements OnProgressUpdate {
#Override
public void onUpdate(Integer percentProgress) {
}
#Override
public void onUpdateFailure() {
}
#Override
public void onSuccess(StringBuilder result) {
}
#Override
public void onFailure() {
}
}
}
Instantiate DownloadWebPage object
DownloadWebPage webPage = new DownloadWebPage(new SampleClass(), myUrl);
Call .downloadHtml() from the DownloadWebPage
webPage.downloadHtml();
Also if the asynchtask is updating properly and the amount of items is to large look here:
listing a listview is taking too much time and memory in android
Another option would be to only list a certain amount of items then have a next page button or gesture to deal with the ListView loading too slow.
I have an HTTP GET that is receiving information from a URI. The URI is for Google Shopping.
https://www.googleapis.com/shopping/search/v1/public/products?key=key&country=US&q=digital+camera&alt=atom
(Left my key out).
Is there a way that I can change it from
q=digital+camera
to anything a user puts in an EditText?
So basically, I want the EditText to change what is searched on Google Shopping.
First screen, ProductSearchEntry with EditText for search query:
Code for ProductSearchEntry
public class ProductSearchEntry extends Activity{
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.productsearchentry);
Button search = (Button) findViewById(R.id.searchButton);
search.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent searchIntent = new Intent(getApplicationContext(), ProductSearch.class);
startActivity(searchIntent);
}
});
}
}
Then, I have a second class, ProductSearch, with no picture, but just this code:
public class ProductSearch extends Activity{
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.productsearchresults);
EditText searchQuery = (EditText) findViewById(R.id.searchQuery);
ProductSearchMethod test = new ProductSearchMethod();
String entry;
TextView httpStuff = (TextView) findViewById(R.id.httpTextView);
try {
entry = test.getSearchData(searchQuery.getText().toString());
httpStuff.setText(entry);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Which references the ProductSearchMethod class which consists of a TextView that is changed to the code recieved in the HTTP GET:
Code:
public class ProductSearchMethod {
public String getSearchData(String query) throws Exception{
BufferedReader in = null;
String data = null;
try{
HttpClient client = new DefaultHttpClient();
URI site = new URI("https://www.googleapis.com/shopping/search/v1/public/products?key=key&country=US&q="+query.replace(" ","+")+"&alt=atom");
HttpGet request = new HttpGet();
request.setURI(site);
HttpResponse response = client.execute(request);
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String l = "";
String nl = System.getProperty("line.seperator");
while((l = in.readLine()) !=null){
sb.append(l + nl);
}
in.close();
data = sb.toString();
return data;
}finally{
if (in != null){
try{
in.close();
return data;
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
ProductSearchMethod comes up great, but it doesn't change the text from "Loading Items" to the website code. I had it working before but then I tried to edit what it searched (all this ^) and now it doesn't change.
Make changes in your code like
public class ProductSearchEntry extends Activity{
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.productsearchentry);
EditText etSearch = (EditText) findViewById(id of your edittext);
Button search = (Button) findViewById(R.id.searchButton);
search.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//while calling intent
Intent searchIntent = new Intent(getApplicationContext(), ProductSearch.class);
searchIntent.putExtra("searchText",etSearch.getText().toString());
startActivity(searchIntent);
}
});
}
}
and another activity like this,
public class ProductSearch extends Activity{
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.productsearchresults);
String searchQuery = getIntent().getStringExtra("searchText");
ProductSearchMethod test = new ProductSearchMethod();
String entry;
TextView httpStuff = (TextView) findViewById(R.id.httpTextView);
try {
entry = test.getSearchData(searchQuery);
httpStuff.setText(entry);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Yeah... Change your getSearchData() method to include a string as a parameter
public String getSearchData(String query) throws Exception{
Then, insert that string into the query URL, replacing spaces with "+". You may want to do further conditioning to the string, for instance URL encoding it.
URI site = new URI("https://www.googleapis.com/shopping/search/v1/public/products?key=key&country=US&q="+query.replace(" ","+")+"&alt=atom");
In your XML, create a button that contains the following line:
android:onClick="search"
In your ProductSearch activity, add the following method, and move the code in onCreate into it. You will also need to create an EditText in your XML for input.
public void search(View v)
{
EditText searchQuery = (EditText) findViewById(R.id.searchQuery);
ProductSearchMethod test = new ProductSearchMethod();
String returned;
try {
returned = test.getSearchData(searchQuery.getText().toString());
httpStuff.setText(returned);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Finally, you will probably want to read up on running asynchronous tasks so that the query won't freeze your app while performing.
May be I got you wrong, but why don't you just pass it as a parameter in
getSearchData() => getSearchData(string query)
Then you can change the line
URI site = new URI("https://www.googleapis.com/shopping/search/v1/public/products?key=key&country=US&q=digital+camera&alt=atom");
to
URI site = new URI("https://www.googleapis.com/shopping/search/v1/public/products?key=key&country=US&q=+ URLEncoder.encode(query, "UTF-8")+&alt=atom");
Check out http://androidforums.com/developer-101/528924-arduino-android-internet-garage-door-works-but-could-use-input.html I use Asynctask to trigger a get command on a local Arduino server. It appends the Arduino's pin number and, depending on if it's needed, a port number to the end of the URL. I'm sure you could use it to help you out.