I'm trying to contact my database using .php
It works fine the first time the ASYNC runs, though the second time i run it (without exiting the application) the application crashes (cant catch the error message from LogCat)
And also for some reason it won't enter the while-loop at all. I've written code like this many times before and it worked out just fine, though not this time.
Code:
class LOAD_USERS extends AsyncTask<String, Void, Void>
{
//Internet Input
URL url;
InputStream iS;
InputStreamReader iSR;
BufferedReader r;
//Variables
List<String> Users = new ArrayList<String>();
public String s = "";
public String DOWNLOAD_SUCCESS = "fail";
String charset = "iso-8859-1";
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(MenuActivity.this);
pDialog.setMessage("Letar efter spelare");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
#Override
protected Void doInBackground(String... sUrl) {
try{
url = new URL(sUrl[0]);
iS = url.openStream();
iSR = new InputStreamReader(iS, charset);
r = new BufferedReader(iSR);
Users.clear();
while((s = r.readLine()) != null)
{
Users.add(s);
DOWNLOAD_SUCCESS = "success";
}
}catch(Exception e)
{
Log.e(e.toString(),e.toString());
}
return null;
}
#Override
protected void onPostExecute(Void result)
{
super.onPostExecute(result);
pDialog.dismiss();
if(DOWNLOAD_SUCCESS.equalsIgnoreCase("success"))
{
MenuActivity.this.CheckValidation();
}
else if(DOWNLOAD_SUCCESS.equalsIgnoreCase("fail"))
{
Toast.makeText(getBaseContext(), "Check Your Internet Connection", Toast.LENGTH_SHORT).show();
}
DownloadComplete = true;
}
}
If you could catch my error, that would be great. Thank you!
From the AsyncTask documentation (Threading rules section):
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
My guess is that Async tasks created to run once, meaning you need to create a new instance of your class.
Related
I've been getting very strange behavior from my code.
Basically, my code is using an Input/Output stream to download a .pdf file from the internet, saving it to internal storage (using an AsyncTask) and then outputting it using an outside "showPdf" library.
The strangest thing is that it only works on two conditions:
I run the code twice (run or debug without any break points). The first run logs File is empty when showPdf() is called, but the second run through runs perfectly fine when showPdf() is called on its own.
I debug the code and step through the program
As a preface, I'm new to java and android studio, so my guess may not be right at all, but I'm guessing since the InputStream is being done "asynchronously", showPdf() may be called before the byte[] array is written into memory. If this is the case, what could I do to delay Async long enough to work?
public class pdfView extends AppCompatActivity {
PDFView pdfView; //pdfView object
String URL;
String fileName;
File directory; //path of created File
// Container for all parameters of DownloadAsync
private static class AsyncParameters {
String URL;
File directory;
AsyncParameters(String URL, File directory) {
this.URL = URL;
this.directory = directory;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pdf_view);
//Grab the extras from the intent call
Intent intent = getIntent(); //whatever calls this activity, gather the intent
URL = intent.getStringExtra("File URL"); // in this case, get the file name of the "extra" passed through
fileName = intent.getStringExtra("File Name");
//Grab the internal storage directory and create a folder if it doesn't exist
File intDirectory = getFilesDir();
File folder = new File(intDirectory, "pdf");
boolean isDirectoryCreated = folder.exists();
//See if the file exists
if (!isDirectoryCreated) {
isDirectoryCreated= folder.mkdir();
}
if(isDirectoryCreated) {
directory = new File(folder, fileName);
try {
directory.createNewFile();
if (directory.canWrite())
Log.d("hngggggggggggggg", "onCreate: ");
} catch (IOException e1) {
e1.printStackTrace();
}
//See if file already exists
boolean empty = directory.length() == 0;
if (empty){
/**Call class to create parameter container**/
AsyncParameters param = new AsyncParameters(URL, directory);
DownloadAsync Downloader = new DownloadAsync();
Downloader.execute(param);
showPdf();
}
else
showPdf();
}
}
public void showPdf()
{
pdfView = (PDFView) findViewById(R.id.pdfView);
pdfView.fromFile(directory).load();
}
/**Class for asynchronous tasks**/
public class DownloadAsync extends AsyncTask<AsyncParameters, Void, Void> {
// Container for all parameters of DownloadAsync
ProgressDialog pDialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(pdfView.this);
pDialog.setMessage("Downloading Database...");
String message= "Downloading Files";
SpannableString ss2 = new SpannableString(message);
ss2.setSpan(new RelativeSizeSpan(2f), 0, ss2.length(), 0);
ss2.setSpan(new ForegroundColorSpan(Color.BLACK), 0, ss2.length(), 0);
pDialog.setMessage(ss2);
pDialog.setCancelable(false);
pDialog.show();
}
#Override
protected Void doInBackground(AsyncParameters... params) {
Log.d("WE ARE IN DOBACKGROUND", "doInBackground: ");
String fileURL = params[0].URL;
File directory = params[0].directory;
try {
FileOutputStream f = new FileOutputStream(directory);
java.net.URL u = new URL(fileURL);
HttpURLConnection c = (HttpURLConnection) u.openConnection();
c.connect();
InputStream in = c.getInputStream();
byte[] buffer = new byte[8192];
int len1 = 0;
while ((len1 = in.read(buffer)) > 0) {
f.write(buffer, 0, len1);
}
f.close();
} catch (Exception e) {
e.printStackTrace();
}
onPostExecute();
return null;
}
protected void onPostExecute() {
pDialog.dismiss();
}
}
}
You already have answered your own question. Since the download is asyncTask running on a different thread, there is no wait for the asyncTask to complete before showPdf() is called. You can call showPdf() from onPostExecute() which is called after the background task completes. Your code should look like:
#Override
protected void onCreate(Bundle savedInstanceState) {
........
........
AsyncParameters param = new AsyncParameters(URL, directory);
DownloadAsync Downloader = new DownloadAsync();
Downloader.execute(param);
.......
.......
}
public class DownloadAsync extends AsyncTask<AsyncParameters, Void, Void> {
.......
#Override
protected void onPostExecute() {
pDialog.dismiss();
showPdf();
}
}
So I have an activity that goes to my server a fetches a text file. This text file holds one line of text containing a package name. My goal is to fetch the package name then use the package name to get the versionCode of the package specified in the txt file on the server.
Here is the class that fetches the txt file from the server:
public class getter extends Activity {
Activity context;
TextView txtview;
ProgressDialog pd;
protected void onCreate(Bundle savedInstanceState) {
//TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_get);
context=this;
}
public void onStart(){
super.onStart();
BackTask bt=new BackTask();
bt.execute("http://1.2.3.4/test.txt");
}
//background process to download the file from internet
public static class BackTask extends AsyncTask<String,Integer,Void>{
String text="";
protected void onPreExecute(){
super.onPreExecute();
//display progress dialog
}
protected Void doInBackground(String...params){
URL url;
try {
//create url object to point to the file location on internet
url = new URL(params[0]);
//make a request to server
HttpURLConnection con=(HttpURLConnection)url.openConnection();
//get InputStream instance
InputStream is=con.getInputStream();
//create BufferedReader object
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String line;
//read content of the file line by line
while((line=br.readLine())!=null){
text+=line;
}
br.close();
}catch (Exception e) {
e.printStackTrace();
//close dialog if error occurs
}
return null;
}
protected void onPostExecute(Void result){
String packageName = text;
}
}
public String getPackageName(Context mContext) {
if (mContext != null) {
BackTask bt=new BackTask();
bt.execute("http://1.2.3.4/test.txt");
}
return "";
}
}
And this is supposed to get the versionCode from the package specified on the server:
public static int getinstVersionCode(Context mContext) {
if (mContext != null) {
try {
getter.BackTask bt=new getter.BackTask();
bt.execute("http://1.2.3.4/test.txt");
return mContext.getPackageManager().getPackageInfo(String.valueOf(new getter.BackTask().execute("http://1.2.3.4/test.txt")), 0).versionCode;
} catch (PackageManager.NameNotFoundException ignored) {
}
}
return 0;
}
Why doesn't this return the versionCode of the package name on the server?
I think the error lies in the function below but I am not sure.
return mContext.getPackageManager().getPackageInfo(String.valueOf(new getter.BackTask().execute("http://1.2.3.4/test.txt")), 0).versionCode;
One issue is that your variable packageName in onPostExecute is local to that method. So even if that method gets called correctly, no other method would see that value.
You could try to declare packageName near the top of BackTask, near where you declare the variable text.
Then change this method to:
protected void onPostExecute(Void result){
packageName = text;
}
Disclaimer: I have not attempted to load and run your code or this fix!
if the network didn't have any issue then think the issue is caused because you communicate between the doInBackground and onPostExecute using a variable inside the the AsyncTask => text
you should using the return value on the doInBackground to pass it to the onPostExecute
change the Asynctask to
//background process to download the file from internet
public static class BackTask extends AsyncTask<String,Integer,String>{
protected void onPreExecute(){
super.onPreExecute();
//display progress dialog
}
protected String doInBackground(String...params){
URL url;
String text;
try {
//create url object to point to the file location on internet
url = new URL(params[0]);
//make a request to server
HttpURLConnection con=(HttpURLConnection)url.openConnection();
//get InputStream instance
InputStream is=con.getInputStream();
//create BufferedReader object
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String line;
//read content of the file line by line
while((line=br.readLine())!=null){
text+=line;
}
br.close();
}catch (Exception e) {
e.printStackTrace();
//close dialog if error occurs
}
return text;
}
protected void onPostExecute(String resultText){
String packageName = resultText;
}
}
You have twice
new getter.BackTask().execute("http://1.2.3.4/test.txt")).
Why? Looks no good.
Further you cannot get results from an AsyncTask with
String.valueOf(new getter.BackTask().execute("http://1.2.3.4/test.txt"))
You should handle the result of doInBackground in onPostExecute. Only there!
I want to retrieve photos in background using AsyncTask. I get photo as string in base64 encoded form. However, I have "The application may be doing too much work on its main thread" error message.
My activity:
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, ItemClickHandler{
private RecyclerView recyclerView;
private RecyclerViewAdapter adapter;
private LayoutManager layoutManager;
private ArrayList<Device> devices;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_action_bar);
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
adapter = new RecyclerViewAdapter(devices, this);
recyclerView.setAdapter(adapter);
initImages();
}
private void initImages() {
Thread thread = new Thread() {
#Override
public void run() {
for(int i = 0; i < devices.size(); i++){
final int pos = i;
GetImageJSON getImage = new GetImageJSON(MainActivity.this){
#Override
protected void onPostExecute(final String result) {
Log.d(TAG, result);
if(pos <= recyclerView.getLayoutManager().getChildCount()){
adapter.updateItem(ImageManager.convertToBitmap(result), pos);
}
}
};
getImage.execute(ConnectionConfig.getUserItemImage(devices.get(i).getId()));
}
}
};
thread.start();
}
}
GetImageJSON class:
public class GetDataJSON extends AsyncTask<String, Void, String> {
private static String charset = "UTF-8";
#Override
protected String doInBackground(String... args) {
String result = parseJSONString(args[0]);
if(!result.isEmpty()){
try{
JSONObject json = new JSONObject(result);
JSONObject jsonObject = json.getJSONObject(ConnectionConfig.TAG_RESULT);
String base64String = jsonObject.getString("image");
Log.d(TAG, base64String);
Bitmap bitmap = ImageManager.convertToBitmap(base64String);
bitmap = ImageManager.scaleDownBitmap(bitmap, context);
Log.d(TAG, "got result: " + result);
return ImageManager.convertBitMapToString(bitmap);
}catch (JSONException e){
e.printStackTrace();
}
}
return result;
}
public static String parseJSONString(String... args){
String result = "";
InputStream inputStream = null;
Log.d(TAG, args[0]);
try {
URL url = new URL(args[0]);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setDoOutput(false);
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept-Charset", charset);
conn.setConnectTimeout(15000);
conn.connect();
try {
InputStream in = new BufferedInputStream(conn.getInputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null) {
result += line;
}
} catch (IOException e) {
e.printStackTrace();
}
conn.disconnect();
} catch (Exception e) {
Log.d(TAG, "Exception", e);
} finally {
try{
if(inputStream != null)
inputStream.close();
}catch(Exception e){
Log.d(TAG, e.getMessage());
}
}
return result;
}
}
I could not find any solution. Please, suggest any one. How I can optimize the process of retrieving data.
I can't tell for sure without a runnable version of your code, but I would guess that having the line ImageManager.convertToBitmap(result)
in onPostExecute() is causing the "too much work on main thread" problem. Anything that happens in onPostExecute() happens on the main thread, so you want to keep that method as light as possible. As SRB suggested, you could avoid this by having doInBackground return the bitmap, instead of a String that needs to be converted back into a bitmap. Note that to change the return type, you'll need to change String to Bitmap in two places:
public class GetDataJSON extends AsyncTask<String, Void, Bitmap> {
#Override
protected Bitmap doInBackground(String... args) {
// TODO return the bitmap
}
//...the rest of your code
}
On a separate note, it looks like there's some room for improvement in your code. These are things that aren't directly related to your question but that it'd be good to understand.
When you call getImage.execute(), doInBackground method of the GetDataJSON class will be executed. The doInBackground method always runs on background thread (see "The 4 steps" section here), so there's no reason to create a new thread in the initImages() method.
One of benefits of using a recyclerview is that you don't need to load everything when recyclerview appears on the screen. If there are views that are off screen, those views can be created when the user scrolls towards them. By retrieving all the images when the activity is created, you're losing that benefit.
There are image loading libraries like Picasso and Glide that will do background image fetches for you. I don't know what your web API looks like, but if you're able to, using a preexisting library can make it simple to quickly deal with issues like placeholders, caching, resizing, etc.
I am trying to download web content using a multi thread approach. I am following an online android development tutorial service so I know believe my code is correct (The complete android web developer course Chapter 5). However, after displaying part of the web page in the log as requested, I get the message:
"I/Choreographer: Skipped 743 frames! The application may be doing too much work on its main thread."
I am using the AsynTask but still no luck.
public class MainActivity extends AppCompatActivity {
public class DownloadTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) { /
String result = "";
URL url;
HttpURLConnection urlConnection = null;
try{
url = new URL(urls[0]);
urlConnection = (HttpURLConnection) url.openConnection();
InputStream in = urlConnection.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
int data = reader.read();
while (data != -1) {
char current = (char) data;
result += current;
data = reader.read();
}
return result;
}
catch(Exception e) {
e.printStackTrace();
return "Failed";
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DownloadTask task = new DownloadTask();
String result = null;
try {
result = task.execute("http://www.w3schools.com/html/tryit.asp?filename=tryhtml_basic_document").get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
Log.i("Contents of URL", result);
}
}
Well, if you do call the AsyncTask.get() method directly in your onCreate() method, then you're kinda cheating, because the code is actually executed in the UI Thread !
You really must not call get(), because this will wait for the result, and thus block the UI Thread (which is precisely what you want to avoid)
I guess you did this because you wanted to have the result in your onCreate() method, but you can't.
Generally, you need to show the result in an UI field (like a TextView). In that case, you should use an Handler instance to be able to use its value from the UI Thread again.
Corrected code :
public class MainActivity extends AppCompatActivity {
public class DownloadTask extends AsyncTask<String, Void, String> {
#Override
protected void onPostExecute(Result result) {
Log.i("Contents of URL", result);
}
#Override
protected String doInBackground(String... urls) {
String result = "";
URL url;
HttpURLConnection urlConnection = null;
try{
url = new URL(urls[0]);
urlConnection = (HttpURLConnection) url.openConnection();
InputStream in = urlConnection.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
int data = reader.read();
while (data != -1) {
char current = (char) data;
result += current;
data = reader.read();
}
return result;
}
catch(Exception e) {
e.printStackTrace();
return "Failed";
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DownloadTask task = new DownloadTask();
task.execute("http://www.w3schools.com/html/tryit.asp?filename=tryhtml_basic_document");
}
}
I have a main activity with launch mode set as "singleTask". When I bring it to the foreground and the onNewIntent method is called, it runs an AsyncTask containing a while loop which reads lines from a text file.
Part way into this loop, the value of one of my integer variables changes to 0. This doesn't always happen in the same stage in the loop cycle and the loop has nothing to do with this variable at all so I don't understand why this is happening.
Here's an image that might better explain the problem:
http://i.stack.imgur.com/ogLQh.jpg
EDIT: Code as requested:
private class ReadFile extends AsyncTask<String, String, String> implements DialogInterface.OnCancelListener {
protected void onPreExecute() {
//Launch dialog
}
protected String doInBackground(String... path) {
try {
File f = new File(path[0]);
FileInputStream in = new FileInputStream(f);
InputStreamReader ir;
ir = new InputStreamReader(in);
BufferedReader br = new BufferedReader(ir);
StringBuffer sb = new StringBuffer();
String str = new String();
while ((str = br.readLine()) != null) {
Log.i("My Variable",Integer.toString(myVariable));
sb.append(str);
sb.append("\n\n");
}
br.close();
myTextFile = sb.toString();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
protected void onProgressUpdate(String... progress) {
//Nothing here
}
protected void onPostExecute(final String unusedString) {
//Dismiss dialog
}
protected void onCancelled() {
finish();
}
public void onCancel(DialogInterface dialog) {
cancel(true);
}
}
myVariable seems to be changed from UI thread (activity thread). Try to add logging in each place where you modify myVariable.