kevoroid
kevoroid

Reputation: 5302

Error: Can't create handler inside thread that has not called Looper.prepare()

Im getting that famous "Can't create handler inside thread that has not called Looper.prepare()" error in my below code. based on most of my Google search result, this happens when i try to update UI from my none-ui-thread, but im not updating the UI at this point when i call the method from my other helper class (only after address has been returned); so please consult on why this is happening would be appreciated.

package com.parspake.kookojapost;

import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.location.*;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class TextShare extends Activity {


    ConnectionHandler textPageConn;
    TextView dt2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.text_share);

        textPageConn = new ConnectionHandler(this);
        dt2 = (TextView) findViewById(R.id.show_location_text_page);

        Thread thread1 = new Thread(new Runnable() {

            @Override
            public void run() {

                textPageConn.getLocation();
                do {

                    if (textPageConn.mAddress != null) {
                        dt2.setText(textPageConn.mAddress);
                        break;
                    } else {
                        Log.d("debug","no location");
                    }

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                } while (textPageConn.mAddress == null);
            }

        });
        thread1.start();
    }
}

this is the exception that i get:

07-04 23:59:38.730: E/AndroidRuntime(7149): FATAL EXCEPTION: Thread-8482
07-04 23:59:38.730: E/AndroidRuntime(7149): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
07-04 23:59:38.730: E/AndroidRuntime(7149):     at android.os.Handler.<init>(Handler.java:121)
07-04 23:59:38.730: E/AndroidRuntime(7149):     at android.location.LocationManager$ListenerTransport$1.<init>(LocationManager.java:183)
07-04 23:59:38.730: E/AndroidRuntime(7149):     at android.location.LocationManager$ListenerTransport.<init>(LocationManager.java:183)
07-04 23:59:38.730: E/AndroidRuntime(7149):     at android.location.LocationManager._requestLocationUpdates(LocationManager.java:661)
07-04 23:59:38.730: E/AndroidRuntime(7149):     at android.location.LocationManager.requestLocationUpdates(LocationManager.java:486)
07-04 23:59:38.730: E/AndroidRuntime(7149):     at com.parspake.kookojapost.ConnectionHandler.getLocation(ConnectionHandler.java:136)
07-04 23:59:38.730: E/AndroidRuntime(7149):     at com.parspake.kookojapost.TextShare$2.run(TextShare.java:69)
07-04 23:59:38.730: E/AndroidRuntime(7149):     at java.lang.Thread.run(Thread.java:856)

so ConnectionHandler.java:136 is -> mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 50, mlocationListener);

and TextShare.java:69 is -> textPageConn.getLocation();

this is my ConnectionHandler Helper class:

package com.parspake.kookojapost;

import android.content.Context;
import android.location.*;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import java.io.IOException;
import java.util.List;
import java.util.Locale;

public class ConnectionHandler {

    private Context ctx;
    double mLat;
    double mLong;
    String currCity;
    String currCountry;
    String mAddress;
    LocationManager mLocationManager;
    LocationListener mlocationListener;

    public ConnectionHandler(Context context) {
        this.ctx = context;
    }


    public boolean locationSourceEnabled() {
        mLocationManager = (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE);
        boolean isInternetLocationAvailable = mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        boolean isGpsAvailable = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        if (isInternetLocationAvailable) {
            return true;
        } else if (isGpsAvailable) {
            return true;
        }
        return false;
    }


    public void getLocation() {

        mlocationListener = new LocationListener() {
            @Override
            public void onLocationChanged(Location location) {

                mLat = location.getLatitude();
                mLong = location.getLongitude();

                Geocoder gcd = new Geocoder(ctx, Locale.getDefault());
                List<Address> addresses;
                try {
                    addresses = gcd.getFromLocation(mLat, mLong, 1);
                    if (addresses.size() > 0) {
                        currCity = addresses.get(0).getLocality();
                        currCountry =  addresses.get(0).getCountryName();
                        mAddress = currCity + " - " + currCountry;
                    }
                } catch (IOException e) {
                    Log.d("omid debug", e.getMessage());
                }
            }

            @Override
            public void onStatusChanged(String s, int i, Bundle bundle) {
            }

            @Override
            public void onProviderEnabled(String s) {
            }

            @Override
            public void onProviderDisabled(String s) {
            }
        };
        mLocationManager = (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE);
        if (locationSourceEnabled()) {
            if (mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
                mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10000, 50, mlocationListener);
            }
            if (mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
                mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 50, mlocationListener);
            }
        }
    }
}

Upvotes: 0

Views: 6547

Answers (3)

Ryan S
Ryan S

Reputation: 4567

Ok the problem is that requestLocationUpdates is an asynchronous call, meaning that you don't need to run it on another thread and also means if you try to you are effectively making a handler on another thread which is not allowed. So instead you can remove the thread and just run this all on onCreate() (since you are only doing async calls)

reference: requestLocationUpdates gives error "Can't create Handler inside thread that has not called Looper.prepare()

Instead you could put your syncronous calls in another thread...

@Override
public void onLocationChanged(Location location) {
     new Thread(new Runnable() {

        @Override
        public void run() {
             mLat = location.getLatitude();
             mLong = location.getLongitude();

             Geocoder gcd = new Geocoder(ctx, Locale.getDefault());
             List<Address> addresses;
             try {
                 addresses = gcd.getFromLocation(mLat, mLong, 1);
                 if (addresses.size() > 0) {
                     currCity = addresses.get(0).getLocality();
                     currCountry =  addresses.get(0).getCountryName();
                     mAddress = currCity + " - " + currCountry;
                 }
             } catch (IOException e) {
                 Log.d("omid debug", e.getMessage());
             }
        }
    }).start();
}

Upvotes: 2

Sreejith B Naick
Sreejith B Naick

Reputation: 1188

Its not possible to change the ui content in other thread.. you can solve these problem in basically 2 ways

  • Using runOnUiThread() method, its simple , but it is not best practice
  • Another way is by using handler with callback handler(Callback c), its recommended one

I'll suggest to use handler with callback method. You can get great tutorial here. handler with callback in thread

Upvotes: 0

azizbekian
azizbekian

Reputation: 62209

You can't update TextView from non-UI thread.

Use runOnUiThread instead:

runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        dt2.setText(textPageConn.mAddress);
                    }
                });

Upvotes: 1

Related Questions