Passing current location data to my asynctask class - android

I'm trying to pass current location of the device to my asynctask class to be used to filter out a list based on their distance before it is populated in my recyclerview. Anytime I run this code I get an empty list and my current location is null. Am I doing something wrong? It works only when I manually enter location co-ordinates.
This are the permissions in my manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="com.example.kwao.roninsnradars.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
This contains my Fragment and My AsyncTask Class:
public class MyListFragment extends Fragment implements SearchView.OnQueryTextListener,GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener{
// TODO: Rename parameter arguments, choose names that match
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private static final String ARG_PARAM3 = "param3";
private int mParam1;
private List<Data> totalData = new ArrayList<>();
private BackendlessCollection<Data> Data;
private MyRecyclerAdapter adapter;
private View view;
public RecyclerView recyclerView;
RecyclerView.LayoutManager gridLayoutManager, linearLayoutManager;
private ProgressDialog progressDialog;
private SwipeRefreshLayout swipeRefreshLayout;
private MyRecyclerAdapter.OnListFragmentInteractionListener mListener;
private GoogleApiClient mGoogleApiClient;
private Location mLocation;
private LocationRequest locationRequest;
private Double mLatitude;
private Double mLongitude;
public MyListFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #return A new instance of fragment MyListFragment.
*/
// TODO: Rename and change types and number of parameters
public static MyListFragment newInstance(int param1) {
MyListFragment fragment = new MyListFragment();
Bundle args = new Bundle();
args.putInt(ARG_PARAM1, param1);
//args.putDouble(ARG_PARAM2, param2);
//args.putDouble(ARG_PARAM3, param3);
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
setHasOptionsMenu(true);
if (view != null) {
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null)
parent.removeView(view);
}
// Defining Linear Layout Manager
linearLayoutManager = new LinearLayoutManager(getContext());
view = inflater.inflate(R.layout.Data_fragment_list_view, container, false);
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
recyclerView.setLayoutManager(linearLayoutManager);
try {
Data = new FindDataAndPopulate(mLatitude,mLongitude).execute().get(30, TimeUnit.SECONDS);
} catch ( CancellationException | ExecutionException | InterruptedException | TimeoutException e ){
Toast.makeText( getActivity(), "Failed to load Data: " + e.getMessage(), Toast.LENGTH_LONG ).show();
}
swipeRefreshLayout = (SwipeRefreshLayout)view.findViewById(R.id.refresh_layout);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
clear();
try {
Data = new FindDataAndPopulate(mLatitude,mLongitude).execute().get(30, TimeUnit.SECONDS);
} catch (CancellationException | ExecutionException | InterruptedException | TimeoutException e) {
Toast.makeText(getActivity(), "Failed to load Data: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
refreshItems();
}
});
mGoogleApiClient = new GoogleApiClient.Builder(getContext())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
return view;
}
public void clear() {
totalData.clear();
adapter.notifyDataSetChanged();
}
private void addMore(BackendlessCollection<Data> next) {
totalData.addAll(next.getCurrentPage());
adapter.notifyDataSetChanged();
}
private void refreshItems() {
onItemsLoadComplete();
}
void onItemsLoadComplete() {
adapter.notifyDataSetChanged();
swipeRefreshLayout.setRefreshing(false);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Inflate the menu; this adds items to the action bar if it is present.
inflater.inflate(R.menu.main_page, menu);
final MenuItem item = menu.findItem(R.id.search);
final SearchView searchView = (SearchView) MenuItemCompat.getActionView(item);
searchView.setQueryHint("Search Data Around You");
searchView.setOnQueryTextListener(this);
MenuItemCompat.setOnActionExpandListener(item,new MenuItemCompat.OnActionExpandListener() {
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
return true;
}
#Override
public boolean onMenuItemActionCollapse(MenuItem item) {
adapter.setFilter(totalData);
return true;
}
});
}
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
final List<Data> filteredRoninList = filter(totalData, newText);
adapter.setFilter(filteredRoninList);
return true;
}
private List<Data> filter(List<Data> areaData, String query) {
query = query.toLowerCase();
final List<Data> filteredDataList = new ArrayList<>();
for (Data ronin : areaData) {
final String text = ronin.getRoninName().toLowerCase();
if (text.contains(query)) {
filteredDataList.add(ronin);
}
}
return filteredDataList;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof MyRecyclerAdapter.OnListFragmentInteractionListener) {
mListener = (MyRecyclerAdapter.OnListFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
#Override
public void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
public void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
#Override
public void onConnected(#Nullable Bundle bundle) {
if (ActivityCompat.checkSelfPermission(getContext(), android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getContext(), android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mLocation != null) {
mLatitude = mLocation.getLatitude();
mLongitude = mLocation.getLongitude();
} else {
Toast.makeText(getContext(), "Location not Detected", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onConnectionSuspended(int i) {
Log.i("Pius", "Connection Suspended");
mGoogleApiClient.connect();
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.i("Pius", "Connection failed. Error: " + connectionResult.getErrorCode());
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p/>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public class FindDataAndPopulate extends AsyncTask<Void, Void,BackendlessCollection<Data>>
{
Double myLatitude;
Double myLongitude;
public FindDataAndPopulate(Double myLatitude,Double myLongitude){
this.myLatitude = myLatitude;
this.myLongitude = myLongitude;
}
private Context context ;
#Override
protected BackendlessCollection<Data> doInBackground(Void... params) {
String query = "distance( %f, %f, location.latitude, location.longitude ) < mi(5) = true";
String whereClause = String.format( query, mLatitude, mLongitude );
BackendlessDataQuery dataQuery = new BackendlessDataQuery( whereClause );
QueryOptions queryOptions = new QueryOptions();
queryOptions.addRelated( "location" );
dataQuery.setQueryOptions( queryOptions );
Data = Backendless.Data.of(Data.class ).find(dataQuery);
return Data;
}
#Override
protected void onPreExecute() {
// progressDialog = ProgressDialog.show(context, "", "Loading...", true);
}
#Override
protected void onPostExecute(BackendlessCollection<Data> DataBackendlessCollection) {
Data = DataBackendlessCollection;
adapter = new MyRecyclerAdapter(getContext(),totalData, mListener);
recyclerView.setAdapter(adapter);
addMore(Data);
}
};
}

The problem is here :
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
getLastLocation() will not return any result immediately if location was not enabled in settings. That's why you should never rely on getLastKnownLocation() for getting recent location.
What you can do is : If location returns null - you need to create a LocationRequest and check for location settings. If location is enabled in settings, you need to call requestLocationUpdates with some interval. once you get the latest location in onLocationUpdated, stop the location updates and do whatever you want with that location.
Another thing to notice : Do not use nested classes for Asynctask as they can easily create memory leaks.

Related

Android recycler view not updating when I click button

I have this fragment where I have and edit text , a button and a recycler view. When I click the button for the first time it has the expected behavior but if I change the edit text content and click the button again it doesn´t update my recycler view. What am I doing wrong? Since I am repeating the process
of making an Api call every click
Fragment
public class SearchFragment extends Fragment implements View.OnClickListener {
private RestaurantAdapter mAdapter;
private RecyclerView mRecyclerView;
protected static List<Restaurant_> restaurantsList;
private Context context;
private static OnRestaurantClickedListener listener;
private FirebaseAuth mAuth;
private EditText keyword;
private FusedLocationProviderClient mFusedLocationClient;
public SearchFragment() {
}
public static OnRestaurantClickedListener getListener() {
return listener;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = getContext();
mAuth = FirebaseAuth.getInstance();
restaurantsList = new ArrayList<>();
mAdapter = new RestaurantAdapter(context, restaurantsList, getActivity());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View mContentView = inflater.inflate(R.layout.fragment_search, container, false);
mRecyclerView = mContentView.findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(mContentView.getContext()));
mRecyclerView.setAdapter(mAdapter);
keyword = mContentView.findViewById(R.id.keyword);
keyword.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
if ((keyEvent != null && keyEvent.getKeyCode() == KeyEvent.KEYCODE_ENTER) || (actionId == EditorInfo.IME_ACTION_SEARCH))
getRestaurants();
return false;
}
});
ImageButton searchButton = mContentView.findViewById(R.id.search);
searchButton.setOnClickListener(this);
return mContentView;
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
listener = (OnRestaurantClickedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnButtonClicked");
}
}
#SuppressLint("MissingPermission")
private void getRestaurants() {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(getActivity());
mFusedLocationClient.getLastLocation().addOnSuccessListener(getActivity(), new OnSuccessListener<Location>() {
#Override
public void onSuccess(final Location location) {
if (location != null) {
SharedPreferences mSettings = PreferenceManager.getDefaultSharedPreferences(context);
String sort = mSettings.getString("sort", "rating");
String order = mSettings.getString("order", "desc");
double radius = Double.parseDouble(mSettings.getString("radius", "10"));
radius = radius * 1000;
RetrofitZomato.getApi().searchByName(keyword.getText().toString(), location.getLatitude(), location.getLongitude(),
20, radius, sort, order, getActivity().getResources().getString(R.string.user_key))
.enqueue(new Callback<SearchResponse>() {
#Override
public void onResponse(Call<SearchResponse> call, Response<SearchResponse> response) {
if (restaurantsList.size() != 0) {
restaurantsList.clear();
mAdapter.notifyDataSetChanged();
}
List<Restaurant> restaurants = response.body().getRestaurants();
for (int i = 0; i < restaurants.size(); i++) {
double distance = calculateDistance(Double.parseDouble(restaurants.get(i).getRestaurant().getLocation().getLatitude()),
Double.parseDouble(restaurants.get(i).getRestaurant().getLocation().getLongitude()),
location.getLatitude(), location.getLongitude());
distance = (double) Math.round(distance * 100d) / 100d;
restaurants.get(i).getRestaurant().setDistance(distance);
restaurantsList.add(restaurants.get(i).getRestaurant());
mAdapter.notifyItemInserted(i);
}
}
#Override
public void onFailure(Call<SearchResponse> call, Throwable t) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Couldn't find any nearby restaurants");
AlertDialog mDialog = builder.create();
mDialog.show();
}
});
}
}
}).addOnFailureListener(getActivity(), new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(getActivity(), "It wasn't possible to determine your location", Toast.LENGTH_LONG).show();
}
});
}
private double calculateDistance(double latRestaurant, double lonRestaurant, double myLat, double myLon) {
if ((myLat == latRestaurant) && (myLon == lonRestaurant)) {
return 0;
} else {
double theta = myLon - lonRestaurant;
double dist = Math.sin(Math.toRadians(myLat)) * Math.sin(Math.toRadians(latRestaurant))
+ Math.cos(Math.toRadians(myLat)) * Math.cos(Math.toRadians(latRestaurant)) * Math.cos(Math.toRadians(theta));
dist = Math.acos(dist);
dist = Math.toDegrees(dist);
dist = dist * 60 * 1.1515;
dist = dist * 1.609344;
return dist;
}
}
#Override
public void onClick(View view) {
int id = view.getId();
if (id == R.id.search) {
getRestaurants();
}
}
// #Override
// public void onActivityCreated(#Nullable Bundle savedInstanceState) {
// super.onActivityCreated(savedInstanceState);
// searchViewModel = ViewModelProviders.of(this).get(SearchViewModel.class);
// // TODO: Use the ViewModel
// }
}
note that with every getRestaurants call you are calling getFusedLocationProviderClient and addOnSuccessListener, keeping old one registered and left... maybe these multiple instances of listeners are reason of this behavior?
move this line to onAttach
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(getActivity());
for getting called once. then make your SearchFragment implementing OnSuccessListener and set for FusedLocationProviderClient. your click should fire request for new location, and your current code with getLastLocation may be also handled in onAttach
edit: real answer - comment copy
try to remove mAdapter.notifyItemInserted(i); line and move mAdapter.notifyDataSetChanged(); out of if condition on the end of method (after for loop). I don't see nothing suspicious in your code, looks fine...

Wait for Retrofit API to update before creating Android fragment view

I'm trying to use geolocation to get the lat/lon coordinates and use them to fetch weather data using an API, but the android view finishes before it can update the coordinates. It ends up using 0.0 by default, and that gets passed into the API link. What method could I use to either force the thread to wait or perhaps update the view once the coordinates are returned?
public class Frag1 extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
OnHeadlineSelectedListener callback;
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
private static final String FINE_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION;
private static final String COURSE_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION;
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1234;
private Boolean mLocationPermissionsGranted = false;
private FusedLocationProviderClient mFusedLocationProviderClient;
public Button sendButton;
TextView description, tempTextView, cityNameTextView, humidityTextView, pressureTextView, windSpeedTextView;;
private WebView MapsView;
ImageView weatherIcon;
public Frag1() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment Frag1.
*/
// TODO: Rename and change types and number of parameters
public static Frag1 newInstance(String param1, String param2) {
Frag1 fragment = new Frag1();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
public void setOnHeadlineSelectedListener(OnHeadlineSelectedListener callback) {
this.callback = callback;
}
// This interface can be implemented by the Activity, parent Fragment,
// or a separate test implementation.
public interface OnHeadlineSelectedListener {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_frag1, container, false);
sendButton = v.findViewById(R.id.sendButton);
pressureTextView = v.findViewById(R.id.pressureTextView);
windSpeedTextView = v.findViewById(R.id.windSpeedTextView);
humidityTextView = v.findViewById(R.id.humidityTextView);
cityNameTextView = v.findViewById(R.id.cityNameTextView);
description = v.findViewById(R.id.descriptionTextView);
tempTextView = v.findViewById(R.id.tempTextView);
((MainActivity)getActivity()).getLocationPermission();
((MainActivity)getActivity()).getDeviceLocation();
//final WeatherForcast forcast = retrofit.create(WeatherForcast.class);
return v;
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onViewCreated(#NonNull final View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.openweathermap.org")
.addConverterFactory(JacksonConverterFactory.create())
.build();
final WeatherService service = retrofit.create(WeatherService.class);
Call<WeatherOutputData> callRequest = service.getWeatherInfo(Double.toString(lat), Double.toString(lon), "imperial", "API_ID");
callRequest.enqueue(new Callback<WeatherOutputData>() {
#Override
public void onResponse(Call<WeatherOutputData> call, Response<WeatherOutputData> response) {
WeatherOutputData data = response.body();
cityNameTextView.setText(data.getName());
tempTextView.setText(data.getMain().getTemp() + "°F");
description.setText("Clouds: " + data.getWeather().get(0).getDescription());
humidityTextView.setText("Humidity: " + data.getMain().getHumidity() + "%");
pressureTextView.setText("Pressure: " + data.getMain().getPressure() + "ppi");
windSpeedTextView.setText("Wind Speed: " + data.getWind().getSpeed() + " MPH");
String icon = data.getWeather().get(0).getIcon();
String iconUrl = "http://openweathermap.org/img/w/" + icon + ".png";
//Picasso.get().load(iconUrl).into(weatherIcon);
}
#Override
public void onFailure(Call<WeatherOutputData> call, Throwable t) {
Log.d("null", t.getMessage());
}
});
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
public class MainActivity extends AppCompatActivity implements Frag1.OnHeadlineSelectedListener {
private static final String FINE_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION;
private static final String COURSE_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION;
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1234;
private Boolean mLocationPermissionsGranted = false;
private FusedLocationProviderClient mFusedLocationProviderClient;
public static double lat, lon;
public FragmentRefreshListener getFragmentRefreshListener() {
return fragmentRefreshListener;
}
public void setFragmentRefreshListener(FragmentRefreshListener fragmentRefreshListener) {
this.fragmentRefreshListener = fragmentRefreshListener;
}
private FragmentRefreshListener fragmentRefreshListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getLocationPermission();
getDeviceLocation();
SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());
ViewPager viewPager = findViewById(R.id.view_pager);
viewPager.setAdapter(sectionsPagerAdapter);
TabLayout tabs = findViewById(R.id.tabs);
tabs.setupWithViewPager(viewPager);
FloatingActionButton fab = findViewById(R.id.fab);
}
public void onAttachFragment(Fragment fragment) {
if (fragment instanceof Frag1) {
Frag1 headlinesFragment = (Frag1) fragment;
headlinesFragment.setOnHeadlineSelectedListener(this);
}
}
public interface FragmentRefreshListener{
void onRefresh();
}
public void getDeviceLocation(){
mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
try{
if(mLocationPermissionsGranted){
final Task location = mFusedLocationProviderClient.getLastLocation();
location.addOnCompleteListener(new OnCompleteListener() {
#Override
public void onComplete(#NonNull Task task) {
if(task.isSuccessful()){
Log.d("YAY", "GOT LOCATION");
Location currentLocation = (Location) task.getResult();
lat = currentLocation.getLatitude();
lon = currentLocation.getLongitude();
}else{
Log.d("null", "onComplete: current location is null");
}
}
});
}
}catch (SecurityException e){
Log.e("tag", "getDeviceLocation: SecurityException: " + e.getMessage() );
}
}
public void getLocationPermission(){
Log.d("tag", "getLocationPermission: getting location permissions");
String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION};
if(ContextCompat.checkSelfPermission(this.getApplicationContext(),
FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
if(ContextCompat.checkSelfPermission(this.getApplicationContext(),
COURSE_LOCATION) == PackageManager.PERMISSION_GRANTED){
mLocationPermissionsGranted = true;
}else{
ActivityCompat.requestPermissions(this,
permissions,
LOCATION_PERMISSION_REQUEST_CODE);
}
}else{
ActivityCompat.requestPermissions(this,
permissions,
LOCATION_PERMISSION_REQUEST_CODE);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
Log.d("tag", "onRequestPermissionsResult: called.");
boolean mLocationPermissionsGranted = false;
switch(requestCode){
case LOCATION_PERMISSION_REQUEST_CODE:{
if(grantResults.length > 0){
for(int i = 0; i < grantResults.length; i++){
if(grantResults[i] != PackageManager.PERMISSION_GRANTED){
mLocationPermissionsGranted = false;
Log.d("tag", "onRequestPermissionsResult: permission failed");
return;
}
}
Log.d("tag", "onRequestPermissionsResult: permission granted");
mLocationPermissionsGranted = true;
}
}
}
}
}
Looks like a job for RXJava, then you can proceed on success or show some error on failure.

Recycler View Adapter: Best practice to notify that data set has updated

I am trying to make a volley request to api's url. The problem is that data is fetched appropriately, but every time data set updates, the whole recycler view refreshes again and begins from the start; in the docs it is mentioned that use notifyDataSetChanged() as the last resort. How can it be avoided and what are the best practices for such tasks? Any design pattern that should be followed?
Here is the Fragment Code :-
public class PageFragment extends Fragment implements SortDialogCallback {
private static final String TAG = PageFragment.class.getSimpleName();
/**
* Unsplash API, By Default=10
*/
private static final String per_page = "10";
public static String order_By;
/**
* Unsplash API call parameter, By Default=latest
* Change it in Pager Fragment, based on Tab tapped
*/
RecyclerView recyclerView;
ImageAdapter imageAdapter;
GridLayoutManager layoutManager;
EndlessRecyclerViewScrollListener scrollListener;
FloatingActionButton actionButton;
FrameLayout no_internet_container;
Bundle savedInstanceState;
// Attaching Handler to the main thread
Handler handler = new Handler();
boolean shouldHandlerRunAgain = true;
private ArrayList<DataModel> model;
/**
* Handler is attached to the Main Thread and it's message queue, because it is the one who created it.
* <p>
* Handler is responsible for checking every second that are we connected to internet, and if we are, then :-
* 1. Then we remove empty view
* 2. Make the network call
* 3. Stop handler from posting the code again using shouldHandlerRunAgain variable
* 3.1 This is a kill switch otherwise handler will post the runnable again and again to the message queue, which will be executed as soon as it reaches the looper
* <p>
* Handler removeCallbacks is used to remove all the pending runnables in the Message Queue
*/
Runnable job = new Runnable() {
#Override
public void run() {
Log.d(TAG, "Thread run " + job.hashCode());
swapViews();
if (shouldHandlerRunAgain)
handler.postDelayed(job, HANDLER_DELAY_TIME);
}
};
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("ORDER_BY", order_By);
}
#Override
public void onResume() {
super.onResume();
if (handler != null)
handler.post(job);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "Starting Handler");
layoutManager = new GridLayoutManager(getContext(), 2);
scrollListener = new EndlessRecyclerViewScrollListener(layoutManager) {
public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
Log.w(TAG, "On load More Called with page number " + page);
loadDataUsingVolley(page, order_By);
}
};
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.search:
Toast.makeText(getContext(), "Async task", Toast.LENGTH_SHORT).show();
break;
default:
Toast.makeText(getContext(), "Invalid Options", Toast.LENGTH_SHORT).show();
}
return true;
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_page_fragment, menu);
}
private void swapViews() {
if (detectConnection(getContext()) == false) {
recyclerView.setVisibility(View.INVISIBLE);
actionButton.setVisibility(View.INVISIBLE);
no_internet_container.setVisibility(View.VISIBLE);
} else {
Log.d(TAG, "Removing callbacks from handler and stopping it from posting");
shouldHandlerRunAgain = false;
handler.removeCallbacks(job, null);
handler = null;
recyclerView.setVisibility(View.VISIBLE);
actionButton.setVisibility(View.VISIBLE);
no_internet_container.setVisibility(View.INVISIBLE);
if (savedInstanceState != null) {
loadDataUsingVolley(1, savedInstanceState.getString("ORDER_BY"));
} else {
order_By = "latest";
loadDataUsingVolley(1, order_By);
}
}
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, final Bundle savedInstanceState) {
this.savedInstanceState = savedInstanceState;
View view = inflater.inflate(R.layout.fragment_page, container, false);
actionButton = (FloatingActionButton) view.findViewById(R.id.sort_button);
actionButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
SortDialog sortDialog = new SortDialog();
sortDialog.setTargetFragment(PageFragment.this, 911);
sortDialog.show(getChildFragmentManager(), "sortfragment");
}
});
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
recyclerView.setHasFixedSize(true);
no_internet_container = (FrameLayout) view.findViewById(R.id.no_internet_container);
return view;
}
void setUpRecyclerView() {
if (imageAdapter == null)
imageAdapter = new ImageAdapter(getContext(), (model==null)?new ArrayList<DataModel>():model);
recyclerView.setAdapter(imageAdapter);
recyclerView.setLayoutManager(layoutManager);
recyclerView.addOnScrollListener(scrollListener);
}
void loadDataUsingVolley(int page, String order_by) {
final ProgressDialog dialog = ProgressDialog.show(getContext(), "Wallser", "Loading");
RequestQueue requestQueue = Volley.newRequestQueue(getContext());
String URL = "https://api.unsplash.com/photos/?page=" + page + "&client_id=" + api_key + "&per_page=" + per_page + "&order_by=" + order_by;
Log.d(TAG, URL);
JsonArrayRequest objectRequest = new JsonArrayRequest(Request.Method.GET, URL, null, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray array) {
int len = array.length();
if (model == null)
model = new ArrayList<>();
for (int i = 0; i < len; i++) {
try {
JSONObject object = array.getJSONObject(i);
String id = object.getString("id");
JSONObject object1 = object.getJSONObject("urls");
String imageURL = object1.getString("regular");
JSONObject object2 = object.getJSONObject("links");
String downloadURL = object2.getString("download");
model.add(new DataModel(imageURL, downloadURL, id));
Log.d(TAG, downloadURL);
} catch (JSONException e) {
e.printStackTrace();
}
}
if (dialog != null) {
dialog.dismiss();
}
Log.d(TAG, model.size() + "");
setUpRecyclerView();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
dialog.dismiss();
Toast.makeText(getContext(), "" + error.getMessage(), Toast.LENGTH_SHORT).show();
}
});
requestQueue.add(objectRequest);
}
/**
* marks a new network call to Unsplash API
* Thus, set model array list to null, to start fresh.
* as model is reset, ImageAdapter also needs to start fresh.
*
* #param order_by
*/
#Override
public void onDialogFinish(String order_by) {
model = null;
imageAdapter=null;
order_By = order_by;
loadDataUsingVolley(1, order_By);
}
}

Retrieve a GoogleMap from a fragment in backstack

I've a class "MainActivity" which calls the different fragments in particular a fragment which display a GoogleMap called MapsFragment.
When this fragment is called for the first time, I had some markers (which are refresh every timeToRefresh. The method startDrawingBomb() is called from the MainActivity class) and everything works perfectly when the user do not change to another fragment.
When a user ask to move to an other fragment I save the the MapsFragment created before in the backStack of the MainActivity (to retrieve it later)
The problem happens when I call this MapsFragment a second time, the fragment is displaying the map but not all the markers I've added before.
I imagine it's because the MapView, and the GoogleMap created by the MapsFragment are not the same as before.
My question is : How can I retrieve the map that I draw before easily ? Or I had to stop all my threads (in onPause() for example), create a new MapsFragment, obtain a new MapView, a new GoogleMap object and apply again all the previous threads ?
This is a part of my MapsFragment :
public class MapsFragment extends Fragment implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener, LocationListener {
private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
private OnMessageListener mCallback;
private GoogleMap _googleMap;
private MapView mMapView;
private ArrayList<Marker> markerArrayListScout = new ArrayList<>();
private ArrayList<Circle> markerArrayListBomb= new ArrayList<>();
private ArrayList<String> idToCircleId = new ArrayList<>();
private ArrayList<Integer> idArray = new ArrayList<>();
private boolean isfirstLocation = true;
boolean mustBeScoutLocationEnabled;
boolean mustDrawCircle;
public MapsFragment(){
super();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v("MAPS_FRAGMENT","onCreate() called");
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.v("MAPS_FRAGMENT","onCreateView() called");
View rootView = inflater.inflate(R.layout.map, container, false);
mMapView = (MapView) rootView.findViewById(R.id.mapView);
mMapView.onCreate(savedInstanceState);
mMapView.onResume(); // needed to get the map to display immediately
try {
MapsInitializer.initialize(getActivity().getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
mMapView.getMapAsync(this);
return rootView;
}
#Override
public void onResume() {
super.onResume();
mMapView.onResume();
}
#Override
public void onPause() {
super.onPause();
mMapView.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}
#Override
public void onMapReady(GoogleMap googleMap) {
Log.v("MAPS_FRAGMENT","onMapReady() called");
_googleMap = googleMap;
_googleMap.setMyLocationEnabled(true);
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.v("Location","onConnected");
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(1000); // Update location every second
//Execute location service call if user has explicitly granted ACCESS_FINE_LOCATION..
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
}
#Override
public void onConnectionSuspended(int i) {
Log.v("Location","onConnectionSuspended");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.v("Location","onConnectionFailed");
}
#Override
public void onLocationChanged(Location location) {
Log.v("Location","location : " + location.toString());
// Add a marker and move the camera
if(isfirstLocation) {
LatLng currentLat = new LatLng(location.getLatitude(), location.getLongitude());
_googleMap.moveCamera(CameraUpdateFactory.newLatLng(currentLat));
_googleMap.moveCamera(CameraUpdateFactory.zoomTo(19));
isfirstLocation = false;
}
//if(mCallback != null)
mCallback.onUpdateLocation(location.getLatitude(),location.getLongitude());
}
/**
* Draw Bomb and update its view all the timeToRefresh milliseconds.
* #param timeToRefresh the time in milliseconds which the marker needs to refresh
* #param id the id of the current bomb we need to work with
*/
public void startDrawingBomb(final int timeToRefresh,final int id){
mustDrawCircle = true;
Log.v("JOSE","passe1");
final Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
while (mustDrawCircle) {
Log.v("JOSE","update bomb");
mCallback.updateBombs();
//Log.v("JOSE","bomb updated ?");
Thread.sleep(timeToRefresh);
// This method is called from the MainActivity
final CircleOptions circleOptions = mCallback.drawBombCircle(id);
final String idToCompare = getIdCircle(id);
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
boolean isCenterSet = false;
if (circleOptions != null) {
Log.v("JOSE","size marker : " +markerArrayListBomb.size());
for(int i=0;i<markerArrayListBomb.size();i++){
Log.v("JOSE","Id to compare : " +idToCompare);
Log.v("JOSE","Id markearray : " +markerArrayListBomb.get(i).getId());
if((markerArrayListBomb.get(i).getId()).equals(idToCompare)){
// si c'est la même chose, il suffit de updater
markerArrayListBomb.get(i).setCenter(circleOptions.getCenter());
markerArrayListBomb.get(i).setVisible(true);
isCenterSet = true;
}
}
// il faut creer une nouvelle bombe
if(!isCenterSet) {
Circle newCircle = _googleMap.addCircle(circleOptions);
markerArrayListBomb.add(newCircle);
newIdCircle(id, newCircle.getId());
//Log.v("JOSE", "New bomb drawn id : " + newCircle.getId());
}
}
}
});
}
String idToCompare = getIdCircle(id);
for(int i=0;i<markerArrayListBomb.size();i++){
if((markerArrayListBomb.get(i).getId()).equals(idToCompare)){
final int index = i;
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
markerArrayListBomb.get(index).setVisible(false);
}
});
}
}
}
catch (InterruptedException e){
e.printStackTrace();
}
}
});
thread.start();
}
public void cancelDrawingBomb(){mustDrawCircle = false;}
// Container Activity must implement this interface
public interface OnMessageListener {
public void onUpdateLocation(double lat,double lon);
public void getAllOtherScoutsLocation();
public void updateBombs();
public CircleOptions drawBombCircle(int id);
}
/**
*
* #param id de la bombe dans la classe Bomb
* #return le cercle créé associé. Sinon, return null
*/
private String getIdCircle(int id){
if(idArray.size() == 0)
return null;
for(int i=0 ; i<idArray.size();i++){
if(idArray.get(i) == id)
return idToCircleId.get(i);
}
return null;
}
/**
* Si une bombe est supprimée, il faut appeler cette méthode
* #param id
*/
private void removeIdCircle(int id){
for(int i=0 ; i<idArray.size();i++){
if(idArray.get(i) == id) {
idToCircleId.remove(i);
idArray.remove(i);
}
}
}
/**
* A appeler à chaque fois u'une bombe est créée
* #param id l'id de la classe BOMB
* #param ids l'id créé grâce à la classe Circle de google
*/
private void newIdCircle(int id,String ids){
idToCircleId.add(ids);
idArray.add(id);
}
}
And this how I called the second time my MapsFragment :
if (id == R.id.map) {
if(fragmentManager.findFragmentByTag(MAPS_FRAGMENT) != null){
MapsFragment fragment = (MapsFragment)fragmentManager.findFragmentByTag(MAPS_FRAGMENT);
fragmentManager.beginTransaction().replace(R.id.frame_container, fragment,MAPS_FRAGMENT).addToBackStack(MAPS_FRAGMENT).commit();
}
}
Thanks a lot everyone, and sorry for my bad English.
If you want more information, or a better explanation, don't hesitate to tell me !
Implement save to bundle functionality at Onpause() for your MapFragment. Then in onCreateView() always check your bundle.
If the bundle is empty then it's a new fragment. If the bundle is not empty this means it was previously created.
Hope this helps :
For saving and restoring to bundle : Saving Android Activity state using Save Instance State

Why my SwipeRefreshLayout is null sometimes?

I have a simple app that consists of one MainActivity and 3 fragments. In each of these fragments, I have one SwipeRefreshLayout. In most of the cases when my app loads everything works fine. However, I have noticed when android decides to kill my app and then I open it it causes null pointer exceptions. OnStart I am making a HTTP request to a server and in the on Response method "toggleSwipeRefreshLayoutsOff" is causing the NPE. Unfortunately, I don't have a log since it does not happens every time:
runOnUiThread(new Runnable() {
#Override
public void run() {
toggleSwipeRefreshLayoutsOff();
}
});
This is my toggleSwipeRefreshLayputsOff method code:
public void toggleSwipeRefreshLayoutsOff() {
mHourly_forecast_fragment.mSwipeRefreshLayout.setRefreshing(false);
mCurrent_forecast_fragment.mSwipeRefreshLayout.setRefreshing(false);
mDaily_forecast_fragment.mSwipeRefreshLayout.setRefreshing(false);
}
This is my mainActivity code:
public class MainActivity extends AppCompatActivity {
ViewPager pager;
ViewPagerAdapter adapter;
SlidingTabLayout tabs;
CharSequence Titles[] = {"Current", "Hourly", "Daily"};
int Numboftabs = 3;
Current_forecast_fragment mCurrent_forecast_fragment;
Hourly_forecast_fragment mHourly_forecast_fragment;
Daily_forecast_fragment mDaily_forecast_fragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//-----------MY CODE STARTS HERE-----------------
request = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)
.setSmallestDisplacement(1000)
.setFastestInterval(10 * 1000)
.setInterval(30 * 60 * 1000);
locationProvider = new ReactiveLocationProvider(this);
mainActivityLayout = (LinearLayout)findViewById(R.id.main_activity_layout);
changeWindowTopColor();
this.mCurrent_forecast_fragment = new Current_forecast_fragment();
this.mHourly_forecast_fragment = new Hourly_forecast_fragment();
this.mDaily_forecast_fragment = new Daily_forecast_fragment();
locationListner = new MyLocationListener();
// Creating The ViewPagerAdapter and Passing Fragment Manager, Titles fot the Tabs and Number Of Tabs.
adapter = new ViewPagerAdapter(getSupportFragmentManager(), Titles, Numboftabs, mCurrent_forecast_fragment,
mHourly_forecast_fragment, mDaily_forecast_fragment);
// Assigning ViewPager View and setting the adapter
pager = (ViewPager) findViewById(R.id.pager);
pager.setOffscreenPageLimit(3);
pager.setAdapter(adapter);
// Assiging the Sliding Tab Layout View
tabs = (SlidingTabLayout) findViewById(R.id.tabs);
tabs.setDistributeEvenly(true); // To make the Tabs Fixed set this true, This makes the tabs Space Evenly in Available width
// Setting Custom Color for the Scroll bar indicator of the Tab View
tabs.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
#Override
public int getIndicatorColor(int position) {
return ContextCompat.getColor(MainActivity.this, R.color.tabsScrollColor);
}
});
// Setting the ViewPager For the SlidingTabsLayout
tabs.setViewPager(pager);
}
#Override
protected void onResume() {
super.onResume();
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
if (locationManager == null) {
getLocation();
Log.d(TAG, "OnResume locationManager == null");
}
}
#Override
protected void onStart() {
super.onStart();
if(isFirstTimeLaunchingTheApp) {
Log.d(TAG, "onStart getLocation");
getLocation();
}
}
#Override
protected void onPause() {
super.onPause();
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
if(locationManager != null) {
locationManager.removeUpdates(locationListner);
Log.d(TAG,"removeUpdates - onPause()");
}
//subscribe for background location updates...
subscription = locationProvider.getUpdatedLocation(request)
.subscribe(new Action1<Location>() {
#Override
public void call(Location location) {
Log.d(TAG, "Getting Background updates...");
MainActivity.this.latitude = location.getLatitude();
MainActivity.this.longitude = location.getLongitude();
}
});
}
#Override
protected void onDestroy() {
Log.d(TAG, "OnDestroy Called!");
subscription.unsubscribe();
super.onDestroy();
}
And this is the problematic peace of code
public void getForecast(double latitude, double longitude) {
//scedule no response from the server task...
mScheduledFuture = exec.schedule(mNotAbleToGetWeatherDataTask,12, TimeUnit.SECONDS);
Log.d(TAG, "getForecast initiated...");
String API_KEY = "3ed3a1906736c6f6c467606bd1f91e2c";
String forecast = "https://api.forecast.io/forecast/" + API_KEY + "/" + latitude + "," + longitude + "?units=auto";
if (isNetworkAvailable()) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(forecast)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
runOnUiThread(new Runnable() {
#Override
public void run() {
toggleSwipeRefreshLayoutsOff();
}
});
//on response from the server cansel the noResponseFromServer task
//on response from the server cansel the noResponseFromServer task
Log.d(TAG,"OnFailure_ scheduledFuture is CANCELED");
mScheduledFuture.cancel(true);
alertUserAboutError();
}
//when the call to the Okhttp library finishes, than calls this method:
#Override
public void onResponse(Response response) throws IOException {
runOnUiThread(new Runnable() {
#Override
public void run() {
toggleSwipeRefreshLayoutsOff();
}
});
try {
String jsonData = response.body().string();
if (response.isSuccessful()) {
mForecast = parseForecastDetails(jsonData);
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.d(TAG, "isSuccessful - run on UNI threth (update display)...");
mCurrent_forecast_fragment.updateDisplay();
mHourly_forecast_fragment.setUpHourlyFragment();
mDaily_forecast_fragment.setUpDailyFragment();
toggleSwipeRefreshLayoutsOff();
//set the isFirstTime to true so that the next refresh wont get location
isFirstTimeLaunchingTheApp = false;
}
});
} else {
alertUserAboutError();
}
} catch (IOException | JSONException e) {
Log.e(TAG, "Exception caught:", e);
}
//on response from the server cansel the noResponseFromServer task
Log.d(TAG,"OnResponse_ scheduledFuture is CANCELED");
mScheduledFuture.cancel(true);
}
});
} else {
toggleSwipeRefreshLayoutsOff();
alertForNoInternet();
Log.d(TAG,"Alert No Internet" + 220);
//is there is no internet cancel the noResponseFromServer task
Log.d(TAG,"No internet _ scheduledFuture is CANCELED");
mScheduledFuture.cancel(true);
}
}
This is the code in one of my fragments (it's very similar in all of them )
public class Current_forecast_fragment extends Fragment {
private MainActivity mActivity;
TextView mTimeLabel;
TextView mTemperatureLabel;
TextView mHumidityValue;
TextView mPrecipValue;
TextView mSummaryLabel;
TextView mLocationLabel;
TextView mWindSpeedValue;
ImageView mIconImageView;
ImageView mDegreeImageView;
public SwipeRefreshLayout mSwipeRefreshLayout;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mActivity = ((MainActivity) getActivity());
// Log.d(mActivity.getClass().getSimpleName(),"OnCreateFragment");
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.current_forefast_fragment, container, false);
mTimeLabel = (TextView)v.findViewById(R.id.timeLabel);
mTemperatureLabel = (TextView)v.findViewById(R.id.temperatureLabel);
mHumidityValue = (TextView)v.findViewById(R.id.humidityValue);
mPrecipValue = (TextView)v.findViewById(R.id.precipValue);
mSummaryLabel = (TextView)v.findViewById(R.id.summaryLabel);
mLocationLabel = (TextView)v.findViewById(R.id.locationLabel);
mWindSpeedValue = (TextView)v.findViewById(R.id.windSpeedValue);
mIconImageView = (ImageView)v.findViewById(R.id.iconImageView);
mDegreeImageView = (ImageView)v.findViewById(R.id.degreeImageView);
mSwipeRefreshLayout = (SwipeRefreshLayout)v.findViewById(R.id.current_swipe_refresh_layout);
mSwipeRefreshLayout.setColorSchemeResources(R.color.orange, R.color.blue, R.color.green);
}
my view pager adapter code:
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
private Current_forecast_fragment mCurrent_forecast_fragment;
private Hourly_forecast_fragment mHourly_forecast_fragment;
private Daily_forecast_fragment mDaily_forecast_fragment;
CharSequence Titles[]; // This will Store the Titles of the Tabs which are Going to be passed when ViewPagerAdapter is created
int NumbOfTabs; // Store the number of tabs, this will also be passed when the ViewPagerAdapter is created
// Build a Constructor and assign the passed Values to appropriate values in the class
public ViewPagerAdapter(FragmentManager fm,CharSequence mTitles[], int mNumbOfTabsumb,Current_forecast_fragment current_fragment,
Hourly_forecast_fragment hourly_fragment,
Daily_forecast_fragment daily_fragment) {
super(fm);
this.mCurrent_forecast_fragment = current_fragment;
this.mHourly_forecast_fragment = hourly_fragment;
this.mDaily_forecast_fragment = daily_fragment;
this.Titles = mTitles;
this.NumbOfTabs = mNumbOfTabsumb;
}
//This method return the fragment for the every position in the View Pager
#Override
public Fragment getItem(int position) {
if(position == 0) // if the position is 0 we are returning the First tab
{
return this.mCurrent_forecast_fragment;
}
else if (position == 1) // As we are having 2 tabs if the position is now 0 it must be 1 so we are returning second tab
{
return this.mHourly_forecast_fragment;
}else {
return this.mDaily_forecast_fragment;
}
}
// This method return the titles for the Tabs in the Tab Strip
#Override
public CharSequence getPageTitle(int position) {
return Titles[position];
}
// This method return the Number of tabs for the tabs Strip
#Override
public int getCount() {
return NumbOfTabs;
}
}

Categories

Resources