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

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

我正在尝试使用 android 拥有的 Geocoder 获取城市 它的应用程序是我们作为家庭作业创建的。 我试图在 AsyncTask 中执行此操作,但出现此异常:

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

AsyncTask代码:

public class GeocoderTask extends AsyncTask<Void, Void, String> {

LocationManager locationManager;
Location location;
Context context;
String city;

public GeocoderTask(Context context) {
    this.context = context;
    locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
}

@SuppressLint("MissingPermission")
@Override
protected String doInBackground(Void... voids) {
    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            GeocoderTask.this.location = location;
            Geocoder geocoder = new Geocoder(context, Locale.getDefault());
            List<Address> addresses;
            try {
               addresses  = geocoder.getFromLocation(GeocoderTask.this.location.getLatitude(), GeocoderTask.this.location.getLongitude(), 3);
               city = addresses.get(0).getLocality();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e){
                e.getMessage();
            }
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }

        @Override
        public void onProviderEnabled(String provider) {

        }

        @Override
        public void onProviderDisabled(String provider) {

        }
    });
    return city;
}

@Override
protected void onPostExecute(String s) {
    super.onPostExecute(s);
    FrgPersonInfo frgPersonInfo = new FrgPersonInfo();
    System.out.println(s);
    frgPersonInfo.saveUserToTable(s);
}

}

我正在从片段中调用 AsyncTask 来自片段的调用:

 view.findViewById(R.id.btnRegister).setOnClickListener(new View.OnClickListener() {
        @SuppressLint("MissingPermission")
        @Override
        public void onClick(View v) {
            checkPermissions();
            GeocoderTask geocoderTask = new GeocoderTask(context);
            geocoderTask.execute();
        }
    });

我在 AsyncTask 的 onPostExecute 中调用的方法:

public void saveUserToTable(String city) {
    String age = uAge.getText().toString();
    String name = fName.getText().toString();

    UserInfo userInfo = new UserInfo();
    userInfo.setIsConnected(true);
    userInfo.setUserImage(imageUrl);
    userInfo.setAge(Integer.valueOf(age));
    userInfo.setName(name);
    userInfo.setCity(city);

    Backendless.Data.of(UserInfo.class).save(userInfo, new AsyncCallback<UserInfo>() {
        @Override
        public void handleResponse(UserInfo response) {
            System.out.println("Bitch, im here again!");
            ((TextView)parentView.findViewById(R.id.loginFrgBtn)).setTextColor(Color.BLUE);
            ((TextView)parentView.findViewById(R.id.registerFrgBtn)).setTextColor(Color.BLACK);

            FragmentTransaction ft = fm.beginTransaction();
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
            FrgLogin frgLogin = new FrgLogin();
            ft.replace(R.id.container, frgLogin);
            ft.commit();
            TastyToast.makeText(context, "Welcome!", TastyToast.LENGTH_LONG, TastyToast.SUCCESS).show();
        }

        @Override
        public void handleFault(BackendlessFault fault) {
            TastyToast.makeText(context, fault.getMessage(), TastyToast.LENGTH_LONG, TastyToast.ERROR).show();
        }
    });
}

检查权限:

 private void checkPermissions() {
    List<String> neededPerms = new ArrayList<>();
    int fineGpsPerm = context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION);
    int coarseGpsPerm = context.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION);

    if (fineGpsPerm != PackageManager.PERMISSION_GRANTED || coarseGpsPerm != PackageManager.PERMISSION_GRANTED) {
        neededPerms.add(Manifest.permission.ACCESS_FINE_LOCATION);
        neededPerms.add(Manifest.permission.ACCESS_COARSE_LOCATION);
    }

    if (!neededPerms.isEmpty()) {
        ActivityCompat.requestPermissions( getActivity(), neededPerms.toArray(new String[neededPerms.size()]), GPS_PERM_CODE);
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode){
        case GPS_PERM_CODE:
            if (grantResults[0] != PackageManager.PERMISSION_GRANTED|| grantResults[1] != PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(context, "Need to Allow perms First", Toast.LENGTH_SHORT).show();
                checkPermissions();
            }
            break;
    }
}

片段class:

public class FrgPersonInfo extends Fragment{
public static final int GPS_PERM_CODE = 103;
Context context;
EditText fName, uAge, uCity;
String imageUrl = "";

FragmentManager fm;
View parentView;

LocationManager locationManager;
Location location;
boolean isLocEnabled = false;
String cityAddress = "";


@Override
public void onAttach(@NonNull Context context) {
    super.onAttach(context);
    this.context = context;
    System.out.println("in person onattach");
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@SuppressLint("MissingPermission")
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    //inflating the wanted fragmentView
    View myView = inflater.inflate(R.layout.frg_person_info, container, false);
    // init the fields
    fName = myView.findViewById(R.id.fName);
    uAge = myView.findViewById(R.id.userAge);
    uCity = myView.findViewById(R.id.userCity);
    fm = getActivity().getSupportFragmentManager();
    locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
    return myView;
}

@SuppressLint("MissingPermission")
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    parentView = view.getRootView();
    //creating a bundle so we can (in this case) get data
    Bundle bundle = getArguments();
    //use the get.. method to get data by key
//        imageUrl = bundle.getString(FrgRegister.IMAGE_KEY);
    checkPermissions();

    if (isLocEnabled) {

    } else {
        Toast.makeText(context, "dont have perms", Toast.LENGTH_SHORT).show();
    }


    view.findViewById(R.id.btnRegister).setOnClickListener(new View.OnClickListener() {
        @SuppressLint("MissingPermission")
        @Override
        public void onClick(View v) {
            checkPermissions();
            GeocoderTask geocoderTask = new GeocoderTask(context);
            geocoderTask.getUpdate();
        }
    });
}


@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
}

@Override
public void onDetach() {
    super.onDetach();
    this.fName = null;
    this.uAge = null;
    this.uCity = null;
    this.fm = null;
    this.imageUrl = null;
}


public void saveUserToTable(String city) {
    String age = uAge.getText().toString();
    String name = fName.getText().toString();

    UserInfo userInfo = new UserInfo();
    userInfo.setIsConnected(true);
    userInfo.setUserImage(imageUrl);
    userInfo.setAge(Integer.valueOf(age));
    userInfo.setName(name);
    userInfo.setCity(city);

    Backendless.Data.of(UserInfo.class).save(userInfo, new AsyncCallback<UserInfo>() {
        @Override
        public void handleResponse(UserInfo response) {
            System.out.println("Bitch, im here again!");
            ((TextView)parentView.findViewById(R.id.loginFrgBtn)).setTextColor(Color.BLUE);
            ((TextView)parentView.findViewById(R.id.registerFrgBtn)).setTextColor(Color.BLACK);

            FragmentTransaction ft = fm.beginTransaction();
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
            FrgLogin frgLogin = new FrgLogin();
            ft.replace(R.id.container, frgLogin);
            ft.commit();
            TastyToast.makeText(context, "Welcome!", TastyToast.LENGTH_LONG, TastyToast.SUCCESS).show();
        }

        @Override
        public void handleFault(BackendlessFault fault) {
            TastyToast.makeText(context, fault.getMessage(), TastyToast.LENGTH_LONG, TastyToast.ERROR).show();
        }
    });
}


private void checkPermissions() {
    List<String> neededPerms = new ArrayList<>();
    int fineGpsPerm = context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION);
    int coarseGpsPerm = context.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION);

    if (fineGpsPerm != PackageManager.PERMISSION_GRANTED || coarseGpsPerm != PackageManager.PERMISSION_GRANTED) {
        neededPerms.add(Manifest.permission.ACCESS_FINE_LOCATION);
        neededPerms.add(Manifest.permission.ACCESS_COARSE_LOCATION);
    }

    if (!neededPerms.isEmpty()) {
        ActivityCompat.requestPermissions( getActivity(), neededPerms.toArray(new String[neededPerms.size()]), GPS_PERM_CODE);
    } else {
        isLocEnabled = true;
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode){
        case GPS_PERM_CODE:
            if (grantResults[0] != PackageManager.PERMISSION_GRANTED || grantResults[1] != PackageManager.PERMISSION_GRANTED) {
                checkPermissions();
            } else {
                isLocEnabled = true;
            }
            break;
    }
}
}

Asynctask是一个Thread,它只执行它应该执行的任务,不需要Looper,虽然这个Thread没有调用Looper。 Locationlistener 的工作方式与您尝试过的不同。 OnLocationchanged 只要您不停止侦听器,就会调用 get,但这是异步发生的,您不能只在 asynctask 中等待它完成。您必须从主线程启动 locationlistener,每当您的 Location 发生变化时,都会调用函数 onLocationChanged。例如,您可以将 onPostExecution 放在 locationlistener 中。

@Override
    public void onLocationChanged(Location location) {
        GeocoderTask.this.location = location;
        Geocoder geocoder = new Geocoder(context, Locale.getDefault());
        List<Address> addresses;
        try {
           addresses  = geocoder.getFromLocation(GeocoderTask.this.location.getLatitude(), GeocoderTask.this.location.getLongitude(), 3);
           city = addresses.get(0).getLocality();
           FrgPersonInfo frgPersonInfo = new FrgPersonInfo();
           System.out.println(city);
           frgPersonInfo.saveUserToTable(s);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e){
            e.getMessage();
        }
    }

创建 locationListener 以保留对它的引用。

创建一个 class 来触发 LocationUpdates

public class GeocoderTask {

LocationManager locationManager;
Location location;
Context context;
String city;

LocationListener locationListener = new LocationListener(){
@Override
    public void onLocationChanged(Location location) {
        GeocoderTask.this.location = location;
        Geocoder geocoder = new Geocoder(context, Locale.getDefault());
        List<Address> addresses;
        FrgPersonInfo frgPersonInfo = new FrgPersonInfo();
        System.out.println(city);
        frgPersonInfo.saveUserToTable(s);
        try {
           addresses  = geocoder.getFromLocation(GeocoderTask.this.location.getLatitude(), GeocoderTask.this.location.getLongitude(), 3);
           city = addresses.get(0).getLocality();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e){
            e.getMessage();
        }
    }
    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {}
    @Override
    public void onProviderEnabled(String provider) {}
    @Override
    public void onProviderDisabled(String provider) {}
}
public GeocoderTask(Context context) {
this.context = context;
locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
}

public void getUpdate(){
locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER,locationListener,null
}

您只需创建 class 并使用 locationListener 调用函数 getUpdate,这将调用更新一次。如果您需要更多更新,您还可以使用 requestUpdates 并创建一个函数来删除侦听器。