Не удается создать обработчик внутри потока, который не вызвал Looper.prepare () в AsyncTask - PullRequest
0 голосов
/ 15 января 2020

Я пытаюсь получить город, используя Geocoder, приложение android которого мы создаем в качестве домашней работы. Я пытаюсь сделать это внутри 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();
        }
    });

метод, который я вызываю в onPostExecute в AsyncTask:

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

checkPermission:

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

фрагмент класса:

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

Ответы [ 2 ]

0 голосов
/ 15 января 2020

Создайте locationListener, чтобы сохранить ссылку на него.

Создайте класс для запуска 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
}

Вам просто нужно создать класс и использовать locationListener для вызова функции getUpdate, это вызовет обновление один раз. Вы также можете использовать requestUpdates и создать функцию для удаления слушателя, если вы хотите больше обновлений.

0 голосов
/ 15 января 2020

Asynctask - Поток, который выполняет только те задачи, для которых он должен, и не нуждается в Looper, и, хотя для этого Нити Looper не вызван. Locationlistener работает иначе, чем то, что вы пробовали. OnLocationchanged get вызывается до тех пор, пока вы не остановите слушателя, но это происходит асинхронно, и вы не можете просто ждать внутри asynctask, пока это не закончится sh. Вы должны запустить locationlistener из своей Mainthread, и всякий раз, когда меняется ваше местоположение, вызывается функция onLocationChanged. Например, вы можете поместить свой onPostExecution в список местоположений.

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