1

我在下面的代码中遇到了著名的“无法在未调用 Looper.prepare() 的线程内创建处理程序”错误。根据我的大部分 Google 搜索结果,当我尝试从我的非 UI 线程更新 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 是 -> mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 50, mlocationListener);

和 TextShare.java:69 是 -> 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);
            }
        }
    }
}
4

3 回答 3

2

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

参考:requestLocationUpdates 给出错误“无法在未调用 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();
}
于 2013-07-04T19:20:30.410 回答
1

您无法TextView从非 UI 线程进行更新。

改用runOnUiThread

runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        dt2.setText(textPageConn.mAddress);
                    }
                });
于 2013-07-04T19:13:54.157 回答
0

无法更改其他线程中的ui内容..您可以通过两种方式解决这些问题

  • 使用runOnUiThread()方法,它很简单,但不是最佳实践
  • 另一种方法是使用带有回调handler(Callback c)的处理程序,这是推荐的

我会建议使用带有回调方法的处理程序。你可以在这里得到很棒的教程。线程中带有回调的处理程序

于 2013-07-04T19:22:47.473 回答