错误:无法在未调用Looper.prepare()的线程内创建处理程序

时间:2013-07-04 19:10:15

标签: android multithreading

我在下面的代码中得到那个着名的“无法在未调用Looper.prepare()的线程内创建处理程序”错误。基于我的大部分Google搜索结果,当我尝试从我的非线程更新UI时会发生这种情况,但是当我从其他帮助程序类调用该方法时,我不会更新UI(仅在地址已经过了回);所以请咨询为什么会发生这种情况。

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();
    }
}

这是我得到的例外:

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)

所以ConnectionHandler.java:136是 - &gt; mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,10000,50,mlocationListener);

和TextShare.java:69是 - &gt; textPageConn.getLocation();

这是我的ConnectionHandler Helper类:

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);
            }
        }
    }
}

3 个答案:

答案 0 :(得分:2)

好的问题是requestLocationUpdates是一个异步调用,这意味着你不需要在另一个线程上运行它,也意味着如果你试图在另一个不允许的线程上有效地创建一个处理程序。所以你可以删除线程,然后在onCreate()上运行全部(因为你只是在进行异步调用)

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

相反,您可以将同步调用放在另一个线程中......

@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();
}

答案 1 :(得分:1)

您无法从非UI线程更新TextView

改为使用runOnUiThread

runOnUiThread(new Runnable() {

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

答案 2 :(得分:0)

它不可能改变其他线程中的ui内容..你可以基本上以两种方式解决这些问题

  • 使用 runOnUiThread()方法,其简单,但不是最佳做法
  • 另一种方法是使用带有回调处理程序(回调c)的处理程序,推荐使用

我建议使用处理程序和回调方法。 你可以在这里获得很棒的教程。 handler with callback in thread