Gadosey P. Gadosey P. - 3 months ago 25
Android Question

Passing current location data to my asynctask class

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

}
};


}

Answer

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.

Comments