인프런 커뮤니티 질문&답변

이재윤님의 프로필 이미지
이재윤

작성한 질문수

모던 안드로이드 - 코틀린과 Jetpack 활용

실제 위치 기반으로 약국 정보 표시하기

실제 위도경도 가져올때 널포인터납니다

해결된 질문

작성

·

590

0

    public void fetchStoreInfo() {

        service.fetchStoreInfo(location.getLatitude(), location.getLongitude()).enqueue(new Callback() {

            @Override

            public void onResponse(Call call, Response response) {

                List items = response.body().getStores()

                        .stream()

                        .filter(item -> item.getRemainStat() != null)

                        .collect(Collectors.toList());

                itemLiveData.postValue(items);

            }

            @Override

            public void onFailure(Call call, Throwable t) {

                Log.e("tag", "fail ", t);

                itemLiveData.postValue(Collections.emptyList());

            }

        });

    }

여기서 위도경도가 널이 떠버리는데 왜 널인지 알수있을까요 

레트로핏 통신하는부분을 주석하고 메인 액티비티에서 location이 null아닌지 체크하는 곳에서 로그찍어보면 location이 제대로 들어가는 것은 확인됩니다 
근데 viewmodel에서 널포인터가 나버리는데..  이유가 뭘까요? 실기기 사용중입니다 안드로이드 10 이랑은 관련이 없는건가요?

아니면 레트로핏 get url이 문제일까요?

     String BASE_URL = "https://gist.githubusercontent.com/junsuk5/";

  @GET("bb7485d5f70974deee920b8f0cd1e2f0/raw/063f64d9b343120c2cb01a6555cf9b38761b1d94/sample.json/?m=5000")

    Call<StoreInfo> fetchStoreInfo(@Query("lat") double lat, @Query("lng") double lng);

답변 14

0

오준석님의 프로필 이미지
오준석
지식공유자

네. 샘플이라서 아쉽게도 항상 결과는 같습니다.

해결되셨다니 다행이네요. 역시 등잔밑이 어둡군요. 저도 생성자쪽은 못 봤네요.

0

이재윤님의 프로필 이미지
이재윤
질문자

뷰모델 생성자에서 performAction 메소드를 호출하고 있어서 그랬던건 확인되서 해결을 했는데

if (location != null) {
location.setLatitude(37.188078);
location.setLongitude(127.043002);
viewModel.location = location;
viewModel.fetchStoreInfo();
}

이렇게 setlocation해도 그 json에 있던거 그대로 파싱이되네요 현재위치론 안되고.. 샘플 json이라그런건가요?

0

이재윤님의 프로필 이미지
이재윤
질문자

넵 감사합니다 

0

오준석님의 프로필 이미지
오준석
지식공유자

내일 출근해서 확인해 보고 답변 달도록 하겠습니다.

0

이재윤님의 프로필 이미지
이재윤
질문자

올려주신 깃헙에 main이랑 비교하고 performAction() 메소드부분은 복붙까지해봤는데도 여기먼저안타고 뷰모델을 타네요.. 
제 올린 코드 한번 복붙해서 확인해주실수있나요? 

0

이재윤님의 프로필 이미지
이재윤
질문자

리프레시버튼 안누르고 앱 진입하자마자 죽습니다 ㅠㅠ 그래서 fecthStoreInfo에서 널체크도 해봤는데 그냥 아무것도 안나오더라구요 fail 리스너도 넣어봤었는데 success로 탑니다

0

오준석님의 프로필 이미지
오준석
지식공유자

오잉. 브레이크포인트 잡고 했을 때의 흐름이 viewmodel.location = location 를 타지도 않고 다음라인을 탄다는 것이 이상하네요.

그리고 안 죽도록 null 체크까지 하고 있는데도요.

혹시 옵션메뉴의 리프레시 버튼을 누르셨을까요? 지금 코드 살펴보니 location 이 null로 들어오는 상황에서 옵션메뉴를 누르면 NullPointerException이 발생하겠네요.

이 부분은 제가 놓쳤네요. null 체크를 fetchStoreInfo() 메서드 안에서 해 줘야할 것 같습니다.

이런 상황이라면 fusedLocationClient 에서 addOnFailureListener 를 추가해서 어떤 에러가 들어오는지 확인해 볼 필요가 있을 듯 합니다.

https://github.com/junsuk5/android-java-maskinfo/blob/master/app/src/main/java/com/example/maskinfo/MainActivity.java

0

이재윤님의 프로필 이미지
이재윤
질문자

그래서 강의에 있는것처럼 setlocation으로 위도경도 줘도 viewmodel에서는 null이 찍힙니다

0

이재윤님의 프로필 이미지
이재윤
질문자

메인에 viewmodel.location = location 이부분이랑 service.fetchStoreInfo(location.getLatitude(), location.getLongitude()).enqueue(new Callback<StoreInfo>() {

이부분을 브레이크포인트 잡고 돌려보면 service.fetchStoreInfo(location.getLatitude(), location.getLongitude()).enqueue(new Callback<StoreInfo>() { 

여기부분이 먼저 돌면서 null을 찍어서 앱이 죽고  viewmodel.location = location 여기는 아예 타지도 않더라구요..

레트로핏 통신부분을 주석하면 location 들어간건 확인됩니다

0

이재윤님의 프로필 이미지
이재윤
질문자

public class MainViewModel extends ViewModel {
public MutableLiveData<List<Store>> itemLiveData = new MutableLiveData<>();
public Location location;

private Retrofit retrofit = new Retrofit.Builder()
.baseUrl(MaskService.BASE_URL)
.addConverterFactory(MoshiConverterFactory.create())
.build();

private MaskService service = retrofit.create(MaskService.class);

public MainViewModel(){
fetchStoreInfo();
}
public void fetchStoreInfo() {
service.fetchStoreInfo(location.getLatitude(), location.getLongitude()).enqueue(new Callback<StoreInfo>() {
@Override
public void onResponse(Call<StoreInfo> call, Response<StoreInfo> response) {
List<Store> items = response.body().getStores()
.stream()
.filter(item -> item.getRemainStat() != null)
.collect(Collectors.toList());

itemLiveData.postValue(items);
}

@Override
public void onFailure(Call<StoreInfo> call, Throwable t) {
Log.e("tag", "fail ", t);
itemLiveData.postValue(Collections.emptyList());
}
});
}
}

0

이재윤님의 프로필 이미지
이재윤
질문자

아직도 해결을 찾지 못해서 답글답니다 ㅠㅠ 전체소스를 올려보겠습니다 (메인, 뷰모델만요 어댑터는 따로 분리해서 메인에 없습니다)

public class MainActivity extends AppCompatActivity {
private MainViewModel viewModel;

private FusedLocationProviderClient fusedLocationClient;

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

viewModel = new ViewModelProvider(this).get(MainViewModel.class);

fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

PermissionListener permissionlistener = new PermissionListener() {
@Override
public void onPermissionGranted() {
performAction();
}

@Override
public void onPermissionDenied(List<String> deniedPermissions) {
}
};
TedPermission.with(this)
.setPermissionListener(permissionlistener)
.setDeniedMessage("If you reject permission,you can not use this service\n\nPlease turn on permissions at [Setting] > [Permission]")
.setPermissions(Manifest.permission.ACCESS_FINE_LOCATION)
.check();
}

@SuppressLint("MissingPermission")
private void performAction() {

fusedLocationClient.getLastLocation()
.addOnSuccessListener(this, location -> {
if (location != null) {
Log.e("tag", "location" + location.getLatitude());
viewModel.location = location;
viewModel.fetchStoreInfo();
}
});

RecyclerView recyclerView = findViewById(R.id.recycler_view);

recyclerView.setLayoutManager(new LinearLayoutManager(this, RecyclerView.VERTICAL, false));

final StoreAdapter adapter = new StoreAdapter();
recyclerView.setAdapter(adapter);

// ui 변경 감지
viewModel.itemLiveData.observe(this, stores -> {
adapter.updateItems(stores);
getSupportActionBar().setTitle("마스크 재고 있는 곳 : " + stores.size());
});
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.action_refresh:
viewModel.fetchStoreInfo();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

0

오준석님의 프로필 이미지
오준석
지식공유자

메인에서 값이 나왔으면 ViewModel로 넘길때 잘 안 넘어갔다는 것 같은데 그 부분을 확인해 보시지요

0

이재윤님의 프로필 이미지
이재윤
질문자

위치권한, gps 켜져있고 밖에도나가보고 실기기에 플레이스토어 잘되있습니다 메인에 location 디버깅하면 위도경도값도 나오는데.. 또 확인해볼게있을까요

0

오준석님의 프로필 이미지
오준석
지식공유자

위도 경도가 null이 나오는 경우에 확인해 볼 부분은 다음과 같습니다.

1. 위치 정보 권한을 수락 했는지

2. 기기의 GPS와 네트워크가 켜져 있는지 (수업에서는 이런 검사 로직이 없어요)

3. 실내에서 정말로 위치 검색이 잘 안 될 수 있음 (밖으로 나가서 테스트)

4. Google Play Services에 연결 되어 있는지 (플레이 스토어 앱이 사용 가능해야 위치 정보를 사용할 수 있음)

확인해 보시기 바랍니다.

저도 안드로이드 10으로 테스트 했기 때문에 문제 없고, url도 문제 없습니다.

이재윤님의 프로필 이미지
이재윤

작성한 질문수

질문하기