0

Trying to improve the source code of my app I've noticed that in many activities I have different AsyncTasks that are doing the same: download from internet a document or an image. So I decided to abstract all that classes in only one that allows me doing all of this.

/*
 * Class for downloading documents or images from internet
 */
public class taskDownloader extends AsyncTask<Void,Void,Void>{

  // Type of download
  static final int DOC = 1;
  static final int IMAGE = 2;

  public String urlFetch;         // Url from download content
  public int operation;           // 'DOC' or 'IMAGE'
  public taskInterface listener;  // Notify events
  public InputStream file;        // Result of downloading a DOC
  public Bitmap image;            // Result of downloading an IMAGE

  /*
   * Set listener to events
   */
  public void setListener(taskInterface listener){
    this.listener = listener;
  }

  /*
   * Download a document by url for example an XML file
   */
  public void downloadDoc(String url){
    this.urlFetch = url;
    this.operation = DOC;
    this.execute();
  }

  /*
   * Download an image by url
   */
  public void downloadImage(String url){
    this.urlFetch = url;
    this.operation = IMAGE;
    this.execute();
  }

  @Override
  protected Void doInBackground(Void... params) {

    // Ask about operation requested
    switch(operation){

        case DOC:
            try{
                URL url = new URL(urlFetch);
                URLConnection urlCon = url.openConnection();
                file= urlCon.getInputStream();  // Saving the file

            }catch(Exception e){}
            break;

        case IMAGE:

            // Not yet coded
            break;
    }

    return null;
 }

@Override
protected void onPostExecute(Void result) {
    super.onPostExecute(result);

    Log.d("APP", "Downloaded!");

    // Test reading the inputstream and where I get exeception
    try{
        BufferedReader br = null;
        StringBuilder sb = new StringBuilder();
        String line;
        br = new BufferedReader(new InputStreamReader(this.file));
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        Log.d("APP", sb.toString());
    }catch(Exception e){
        Log.d("APP", "Error" + e);
    }

    this.listener.onFinished();
}

public InputStream getInputStream(){
    return this.file;
}
}

Well, in addition I have created a simple interface for notifications from the AsynTask to who lunched the task. And is that I don't use this AsyncTask exclusive in Activities also for example in a class that download a XML from internet and store on internal storage where I dont have to make changes on the UI.

public interface taskInterface {

    public abstract void onFinished();

}

My problem is that I can't access to the result of download (property "file" by getInputStream() method) because I get Android.os.NetworkOnMainThreadException. For tests, on the onPostExecute() method, I have wrote a few lines to read that InputStream and here a get the problem. But putting the same code on doInBackground() works well. How it is possible? The source of exception come from execute internet code on the UI thread but this lines havent code related to this. It's only BufferedReader and no connection to any place. My connection I have correctly placed on doInBackground but onPostExecute I only reading the result of downloading I'm not connecting a website. :(

    // Test reading the inputstream
    try{
        BufferedReader br = null;
        StringBuilder sb = new StringBuilder();
        String line;
        br = new BufferedReader(new InputStreamReader(this.file));
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        Log.d("APP", sb.toString());
    }catch(Exception e){
        Log.d("APP", "Error" + e);
    }

What is that BufferedReader is connected to the URL? I don't understand if only reads the result previusly downloaded on doInBackground method...

LogCatg

 07-16 12:08:05.945: W/ActivityThread(5042): Application com.example.lectorrss is waiting for the debugger on port 8100...
 07-16 12:08:05.955: I/System.out(5042): Sending WAIT chunk
 07-16 12:08:05.985: I/dalvikvm(5042): Debugger is active
 07-16 12:08:06.165: I/System.out(5042): Debugger has connected
 07-16 12:08:06.165: I/System.out(5042): waiting for debugger to settle...
 07-16 12:08:06.375: I/System.out(5042): waiting for debugger to settle...
 07-16 12:08:06.585: I/System.out(5042): waiting for debugger to settle...
 07-16 12:08:06.795: I/System.out(5042): waiting for debugger to settle...
 07-16 12:08:07.005: I/System.out(5042): waiting for debugger to settle...
 07-16 12:08:07.215: I/System.out(5042): waiting for debugger to settle...
 07-16 12:08:07.425: I/System.out(5042): waiting for debugger to settle...
 07-16 12:08:07.635: I/System.out(5042): debugger has settled (1400)
 07-16 12:08:07.745: D/SPLASH_SCREEN_ACTIVITY(5042): Descargando información portales
 07-16 12:08:07.745: D/SPLASH_SCREEN_ACTIVITY(5042): Descargado
 07-16 12:08:07.865: I/PGA(5042): New SOCKET connection: ample.lectorrss (pid 5042, tid 5058)
 07-16 12:08:07.875: I/PGA(5042): New SOCKET connection: ample.lectorrss (pid 5042, tid 5042)
 07-16 12:08:07.965: D/dalvikvm(5042): GC_FOR_ALLOC freed 76K, 24% free 7469K/9795K, paused 10ms
 07-16 12:08:08.005: I/dalvikvm-heap(5042): Grow heap (frag case) to 12.370MB for 3072012-byte allocation
 07-16 12:08:08.015: D/dalvikvm(5042): GC_FOR_ALLOC freed 1K, 19% free 10467K/12803K, paused 10ms
 07-16 12:08:08.045: D/dalvikvm(5042): GC_CONCURRENT freed 0K, 19% free 10468K/12803K, paused 0ms+0ms
 07-16 12:08:08.235: D/APP(5042): Descargado
 07-16 12:08:08.255: D/Error(5042): Errorandroid.os.NetworkOnMainThreadException

EDIT: My really question is why BufferedReader throws the exception if it no connects any place. Only reads a variable where previuly have been filled on doInBackground()

korima
  • 306
  • 5
  • 12
  • 1
    How do you invoke asynctask? – Raghunandan Jul 16 '14 at 09:49
  • 1
    **ALWAYS** include the logcat in your question if you get exceptions. – Xaver Kapeller Jul 16 '14 at 09:51
  • For example on my first activity I make a cache of a XML file of Internet. So I call from here to a custom class where I manage all this process of downloading from internet an XML and store on Storage Internal. And this class communicate with AsyncTask. Activity -> cacheMaker class -> AsynkTask. And about the code: 1) I create the asynk task. 2) Set my custom listener. 3) Call to downloadDoc(). (The call to execute() is inside on downloadDoc() I put above) – korima Jul 16 '14 at 09:58
  • I don't think this is a duplicate. I think the issue you are seeing is that although you get a reference to the stream by calling `urlCon.getInputStream()`, you have not actually read from the stream yet. You then pass this reference to the UI thread, then read from it, which causes a network operation to get the data, and you receive the exception you described. – dave.c Jul 16 '14 at 16:11
  • @dave.c Exactly! That was the problem! Now I'm understanding what happened. :) I thought that getInputStream() would make the read the content but it's just what you say, it's a reference but not a complete reading of the content. Now I've fixed and instead of saving the result in the InputStream I save directly as String in doInBackGround. Thank you very much! – korima Jul 16 '14 at 18:29
  • @marcin-orlowski I think too that my problem wasnt duplicate. It is a diffirent problem than the other. It is not the typicall question about AsyncTask. It was understanding why works one thing and the other no. I don't know if u can reopen it if someone in the future has problems. – korima Jul 16 '14 at 18:35
  • I reopened this question as is indeed not exactly the commonly seen case – Marcin Orlowski Jul 16 '14 at 22:30
  • I've added my comment as an answer – dave.c Jul 17 '14 at 09:02

1 Answers1

1

The issue you are seeing is that although you get a reference to the stream by calling urlCon.getInputStream(), you have not actually read from the stream yet. You then pass this reference to the UI thread, then read from it, which causes a network operation to get the data, and you receive the exception you described.

If you move the call to read from the stream into the background thread it will slove your problem.

dave.c
  • 10,910
  • 5
  • 39
  • 62