Обновление данных в фрагменте с помощью Navigation Architecture Component

172
27 мая 2021, 03:50

Пытаюсь сделать, так чтобы после выбора города в AutoCompleteSearchView(данный компонент я определил в MainActivity), который кладу в Bundle и передаю во фрагмент, где необходимо выполнить новый запрос и обновить данные во фрагменте, но этого не происходит. Или это необходимо реализовать как-то по другому? Так же пытался сделать с помощью Sharedpreferences, получал Nullpointerexception, когда вызывал стандартным способом фрагмент(getsupportfragmentmanager).

MainActivity:

public class MainActivity extends AppCompatActivity {
@BindView(R.id.bottom_nav)
BottomNavigationView bottom_nav;
@BindView(R.id.toolbar)
Toolbar toolbar;
private NavController navController;
private AutoCompleteSearchView searchView;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.bind(this);
    setSupportActionBar(toolbar);
    navController = Navigation.findNavController(this, R.id.nav_host_fragment);
    NavigationUI.setupWithNavController(bottom_nav, navController);
    NavigationUI.setupActionBarWithNavController(this, navController);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.search_menu, menu);
    MenuItem searchViewItem = menu.findItem(R.id.action_search);
    searchView = (AutoCompleteSearchView) searchViewItem.getActionView();
    searchView.setUseDefaultProgressBar(true);
    searchView.setOnPredictionClickListener((position, prediction) -> {
        Bundle bundle = new Bundle();
        bundle.putString("city", prediction.displayString);
        navController.navigate(R.id.currentWeatherFragment, bundle);
        searchViewItem.collapseActionView();
    });
    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            return true;
        }
        @Override
        public boolean onQueryTextChange(String newText) {
            if (newText.length() >= 3) {
                searchView.showProgressBar();
                NetworkPredictions(newText);
            }
            return true;
        }
    });
    return true;
}
private void NetworkPredictions(String newText) {
    ServiceGenerator serviceGenerator = ServiceGenerator.getInstance();
    Call<List<CityWeatherResponse>> call = serviceGenerator.getApi().getCity(newText);
    call.enqueue(new Callback<List<CityWeatherResponse>>() {
        @Override
        public void onResponse(Call<List<CityWeatherResponse>> call, Response<List<CityWeatherResponse>> response) {
            if (response.isSuccessful() && response.body() != null) {
                List<CityWeatherResponse> rawPredictions = new ArrayList<>();
                rawPredictions.addAll(response.body());
                List<Prediction> predictions = toSearchViewPredictions(rawPredictions);
                searchView.applyPredictions(predictions);
                searchView.hideProgressBar();
            }
        }
        @Override
        public void onFailure(Call<List<CityWeatherResponse>> call, Throwable t) {
        }
    });
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            navController.popBackStack();
            return true;
    }
    return super.onOptionsItemSelected(item);
}
private List<com.amsen.par.searchview.prediction.Prediction> toSearchViewPredictions(List<CityWeatherResponse> predictions) {
    List<Prediction> forSearchView = new ArrayList<>();
    for (CityWeatherResponse prediction : predictions) {
        forSearchView.add(new Prediction(prediction, prediction.name));
    }
    return forSearchView;
}}

Фрагмент:

public class CurrentWeatherFragment extends Fragment implements CurrentWeatherView {
@BindView(R.id.city_field)
TextView current_city;
@BindView(R.id.weather_icon)
ImageView weather_icon;
@BindView(R.id.current_temperature_field)
TextView current_temperature;
private CurrentWeatherPresenter presenter;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    presenter = new CurrentWeatherPresenter(this);
    presenter.getData(getArguments().getString("city"));
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                         @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.current_weather_fragment, container, false);
    ButterKnife.bind(this, view);
    return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
}
@Override
public void setLocation(CurrentWeatherResponse.Location data) {
    if (data != null) {
        current_city.setText(getArguments().getString("city"));
        current_city.setText(data.getName());
        Toast.makeText(getContext(), data.getName(), Toast.LENGTH_LONG).show();
    }
}
@Override
public void setCurrentWeather(CurrentWeatherResponse.CurrentWeatherEnter currentWeather) {
        if (currentWeather != null) {
            current_temperature.setText(String.valueOf(currentWeather.getTempC()));
            Picasso.get()
                    .load("http:"+currentWeather.getCondition().getIcon())
                    .into(weather_icon);
        }
}
@Override
public void onErrorLoading(String message) {
}}
Answer 1

Текущий способ передачи данных некорректен, так как Вы пытаетесь открыть уже открытый фрагмент и передать в него данные. Для более корректного способа передачи данных в данном случае необходимо реализовать подписку фрагмента на элемент, к которому имеет доступ и MainActivity, и CurrentWeatherFragment. Я бы порекомендовал Вам разобраться с Гугловсикими ViewModel и LiveData и выполнить следующий алгоритм действий:

  1. Перевести приложение на архитектуру MVVM
  2. Реализовать SharedWeatherViewModel, к которой будут иметь доступ MainActivity и CurrentWeatherFragment
  3. Внутри SharedWeatherViewModel положить MutableLiveData, в который MainActivity будет кидать новую строку для обновления информации во фрагменте
  4. CurrentWeatherFragment подпишется на MutableLiveData, лежащий внутри SharedWeatherViewModel и будет моментально получать актуальные данные!
READ ALSO
Как использовать JColorChooser?

Как использовать JColorChooser?

Как добавлять JColorChooser, я разобрался, а как его именно использовать, чтобы, к примеру, я выбрал цвет, и поменялся фон?

102
Callback во фрагмент

Callback во фрагмент

Есть активити A, фрагменты B и C

121
добавление элементов в коллекцию типа &ldquo;класс&rdquo;

добавление элементов в коллекцию типа “класс”

День добрыйРеализовываю добавление элементов в коллекцию, есть такой код:

106
Как в JOGL отрисовывать данные из массива вершин, а не из буфера в GPU?

Как в JOGL отрисовывать данные из массива вершин, а не из буфера в GPU?

В java-приложении с использованием JOGL рисую например треугольник (сильно сокращенный код):

132