-1

This is not a duplicate of the question posted above. As HAndlerThread starts a newThread and i get a NetworkOnMainThread exception, i think it is a strange error. It is entirely new issue to solve that normal NetworkOnMainThread exception. Kindly unmark this.

Hi first of all I am practicing HandlerThread's. I have used Fragment to start a handlerthread and send a message to the thread. Inside the HandlerThread's Handle message i use network call to download images. Then I post the downloaded images to the UI thread using the MainThread's Handler. But when running this application i get a NetworkOnMainThread Exception.Below are the codes for Fragment and the Handler Thread.

Fragment:

public class LoaderFragment extends Fragment {
Button loaderButton;
LoaderThread loadThread;
Handler loaderThreadHandler;
Handler mainHandler;
String[] queArray;


@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mainHandler = new Handler(Looper.getMainLooper());
    loadThread = new LoaderThread("LoaderThread",mainHandler);
     queArray = new String[]{"http://www.paynekillers.com/downloads/screens/17_screen05.jpg",
            "http://www.hdwallpapers.in/walls/jacob_frye_assassins_creed_syndicate-wide.jpg",
    "http://www.percivalconstantine.com/wp-content/uploads/2015/03/Tomb-Raider-Lara-Croft-Summit-2013.jpg",
    "http://orig00.deviantart.net/f904/f/2014/155/e/a/batman_arkham_knight_hd_wallpaper_1_by_rajivcr7-d7l19pt.jpg",
    "http://static5.gamespot.com/uploads/original/536/5360430/2753139-15774024117_9026e0a43c_o.jpg"};
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View loaderView = inflater.inflate(R.layout.loader_layout, container, false);
    this.loaderButton = (Button) loaderView.findViewById(R.id.proc_button);
    return loaderView;
}

@Override
public void onResume() {
    super.onResume();



    loaderButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            loadThread.start();
            loaderThreadHandler = loadThread.requestHandler();
            Message msg = Message.obtain(loaderThreadHandler, 1, queArray);
            msg.sendToTarget();
        }
    });
}

@Override
public void onDestroy() {
    super.onDestroy();
    loadThread.quit();
} }

Handler Thread :

public class LoaderThread extends HandlerThread implements Handler.Callback{
Handler imageHandler;
Handler loaderHandler;
Map<Integer,String> queMap;
HandlerActivity activity;


public LoaderThread(String name, Handler handler) {
    super(name);
    imageHandler= handler;
    Log.d("inside : ", name);
}

Handler requestHandler(){
    loaderHandler = new Handler(this.getLooper(),this);
    return loaderHandler;
}


@Override
public boolean handleMessage(Message msg) {
    String[] que = (String[]) msg.obj;
    queMap = new HashMap<Integer,String>();
    if(que != null){Log.d("",que[3]);}
    for (int i=0;i<=4; i++){
        String url = que[i];

        queMap.put(i,url);
        Log.d("1",url);
    }
    Log.d("THR : ", String.valueOf(Thread.currentThread()));
    Random rand = new Random();
   String link = queMap.get(rand.nextInt(5));

    loadImages(link);
    return true;
}

void loadImages(final String url){
    Log.d("inside Load :","Inside Load");
    try {
        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        final Bitmap image = BitmapFactory.decodeStream(connection.getInputStream());
        imageHandler.post(new Runnable() {
            @Override
            public void run() {
                activity.loadImage(image, url);
            }
        });

    } catch (IOException e) {
        e.printStackTrace();
    }
} }

Activity's loadImage method:

public void loadImage(Bitmap image, String url) {
    Bitmap img = image;
    String link = url;
    ft = fmg.beginTransaction();
    ft.add(R.id.frag_container,imgFrag,"ImageFragment");
    ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
    ft.show(imgFrag);
    ft.commit();
    imgFrag.loadImg(img,link);

}

Also When I use log to check which thread i am in (inside handleMessage in HandlerThread) I get a log message as I am in Main. How is it possible? Am I doing something wrong?

Raaja SN
  • 382
  • 3
  • 14
  • see [here](http://stackoverflow.com/a/25096981/2252830) on how to use a `HandlerThread` – pskink Jan 19 '16 at 13:15
  • `But I am trying to create an entirely new HandlerThread` and what am i doing??? why do you extend `HandlerThread` at all? what is the reason of that? – pskink Jan 19 '16 at 13:37
  • It's getting really hard to follow the discussion in the comments. Please post an answer if you have one, or ask for clarifying information here. If you need to have an extended discussion, use one of our chatrooms to facilitate that. – George Stocker Jan 19 '16 at 14:04
  • Comments are not for extended discussion; this conversation has been [moved to chat](http://chat.stackoverflow.com/rooms/101087/discussion-on-question-by-raaj-foru-handler-thread-networkonmainthread-excepti). – George Stocker Jan 19 '16 at 14:05
  • Can you please post the logs with the exception as well ? I tried your code but was not able to simulate the issue. Thanks – thedarkpassenger Jan 24 '16 at 18:17

3 Answers3

0

Change in LoaderFragment from

mainHandler = new Handler(Looper.getMainLooper());
loadThread = new LoaderThread("LoaderThread",mainHandler);

to

loadThread = new LoaderThread("LoaderThread");

and then in LoaderThread

public LoaderThread(String name, Handler handler) {
     super(name);         
     Log.d("inside : ", name);
}
 @Override
 protected void onLooperPrepared() {
     imageHandler = new Handler(getLooper(), this);
  }

You are getting the error since you are passing the UI Thread Looper to the LoaderThread, which you pass again in requestHandler() for the network access. Consequently your network operation is dequeued by the UI Thread Looper.

Radu Ionescu
  • 3,462
  • 5
  • 24
  • 43
  • Thanks for your reply. I think this solves the issue. But what i am trying to do is passing message between 2 threads. Now think of this I have a Thread1 and Thread 2. I have created a handler and prepared it in each of the thread. I can pass thread1 handler reference to thread2 and the same for thread2. Now what will happen if i send message to thread2 from thread1? Will the message be handled from first thread? – Raaja SN Jan 19 '16 at 17:49
  • If you are saying that i am passing UI looper to second thread and getting it again in request looper. the same happens if i send thread1 handler to thread2. And if i request Thread2 looper will i get the looper of the 1st thread? – Raaja SN Jan 19 '16 at 17:50
  • I see only one thread in your example `LoaderThread loadThread`, but to answer your question you have a target and a source of your `Message` for which your need to provide the respective handlers (think of them as _id_s) and when dequeu a message you can then post a message on the other thread looper by changing source and target. To set them up you can pass a reference on thread1 handler when you create thread2 and pass a message from thread2. when thread 1 reads the message it can store the source handler – Radu Ionescu Jan 19 '16 at 21:15
  • For your task you can even use the same thread and use the `Message` _what_ parameter to encode the desired action. You post a message to download (`what=100`) an image and right before you are finished with this message you post a new message on the same thread to display the image (`what==101`). – Radu Ionescu Jan 19 '16 at 21:19
  • "To set them up you can pass a reference on thread1 handler when you create thread2 and pass a message from thread2. when thread 1 reads the message it can store the source handler" . That's what i was actually doing in my previous coding. I just passed the Main Thread's handler into the HandlerThread inside the constructor of the HandlerThread. But you say that by doing so it binds to the looper of the Main Thread. – Raaja SN Jan 20 '16 at 05:45
  • Sorry, I read too fast through your code. You are right. Can you post in your question the content of this `activity.loadImage(image, url);` – Radu Ionescu Jan 20 '16 at 08:03
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/101168/discussion-between-raaj-foru-and-radu-ionescu). – Raaja SN Jan 20 '16 at 09:32
0

I had the same problem. And then I set my HandlerThread's handler in overriden method called onLooperPrepared(), and didn't receive that exception any more, so you should try to do something like this in your LoaderThread class:

@Override
protected void onLooperPrepared() {
    super.onLooperPrepared();
    loaderHandler = new Handler(this.getLooper(),this);
}

onLooperPrepared is, according to documentation, I quote: Call back method that can be explicitly overridden if needed to execute some setup before Looper loops. Please, tell here if this worked for you, or not.

Draško
  • 2,119
  • 4
  • 41
  • 73
-2

For any networking operations in Android it is advisable to write that code inside AsyncTask.

Ajaj Patel
  • 24
  • 8