0

I've tried to look for a solution but I have not been able to find one with my specific situation. I'm using a recyclerview with GSON and I'm getting the message of skipping layout. My code looks correct but I know I should set an empty adapter in the onCreateView section. I'm not sure how to exactly do that. Any help will be appreciated. My fragment activity is below.

  @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
                     Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_weather_app, container, false);

mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mRecyclerView.addItemDecoration(new DividerItemDecoration(mRecyclerView.getContext(), DividerItemDecoration.VERTICAL));

new GetWeatherAync().execute(getActivity());
return view;


 }
 private class GetWeatherAync extends AsyncTask<Context, Void,      
 List<ForecastWeatherList>> {
private String TAG = GetWeatherAync.class.getSimpleName();
private Context mContext;

@Override
protected void onPreExecute() {
    super.onPreExecute();
}

@Override
protected List<ForecastWeatherList> doInBackground(Context...params) {
    mContext = params[0];
    return getWeatherFromServer();
}

@Override
protected void onPostExecute(List<ForecastWeatherList> result) {
    super.onPostExecute(result);

    if (result != null) {
        Log.e(TAG, "populate UI recycler view with gson converted data");

        RecyclerViewAdapter weatherRecyclerViewAdapter = new RecyclerViewAdapter(result, mContext);
        mRecyclerView.setAdapter(weatherRecyclerViewAdapter);
    }

}
 }

 public List<ForecastWeatherList> getWeatherFromServer(){
String serviceUrl = "http://api.openweathermap.org/data/2.5/forecast?q=" + searchView + api_key;
URL url = null;
try {
    url = new URL(serviceUrl);

    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setRequestMethod("GET");
    connection.setDoOutput(true);
    connection.setConnectTimeout(4000);
    connection.setReadTimeout(4000);
    connection.connect();

    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));

    //pass buffered reader to convert json to javaobject using gson
    return convertJsonToObject(bufferedReader);

}catch (Exception e){

}

return null;
 }

 public List<ForecastWeatherList> convertJsonToObject(BufferedReader bufferedReader){
final Gson gson = new Gson();

//pass root element type to fromJson method along with input stream

ForecastWeatherListWrapper weatherWrapper = gson.fromJson(bufferedReader,ForecastWeatherListWrapper.class);

List<ForecastWeatherList> weatherlst = weatherWrapper.getforecastWeatherLists();

return weatherlst;
}

EDIT:

So I've implemented the following changes:

Listener Interface.

     import com.ksburneytwo.weathertest.ForecastWeather.ForecastWeatherList;

   import java.util.List;

   public interface Listener {
void afterSearch(List<ForecastWeatherList> result);
 }

Fragment:

   public static WeatherAppFragment newInstance(String param1, String param2) {
    WeatherAppFragment fragment = new WeatherAppFragment();
    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);
    }


}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.fragment_weather_app, container, false);

    mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    mRecyclerView.addItemDecoration(new DividerItemDecoration(mRecyclerView.getContext(), DividerItemDecoration.VERTICAL));

    new GetWeatherAync().execute(getActivity());
    return view;
}





@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.menu, menu);
    MenuItem searchItem = menu.findItem(R.id.menu_search);
    SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);

    if (searchItem != null) {
        searchView = (SearchView) searchItem.getActionView();
    }
    if (searchView != null) {
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName()));

        queryTextListener = new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextChange(String newText) {
                Log.i("onQueryTextChange", newText);

                return true;
            }

            @Override
            public boolean onQueryTextSubmit(String query) {
                Log.i("onQueryTextSubmit", query);

                return true;
            }
        };
        searchView.setOnQueryTextListener(queryTextListener);
    }
    super.onCreateOptionsMenu(menu, inflater);
}

@Override
public void afterSearch(List<ForecastWeatherList> result) {
    mRecyclerView.setAdapter(new RecyclerViewAdapter(result, mRecyclerView.getContext()));

}



private static class GetWeatherAync extends AsyncTask<Context, Void, List<ForecastWeatherList>> {
    private String TAG = GetWeatherAync.class.getSimpleName();
    private final String serviceUrl;
    private Context mContext;
    private Listener listener;

    GetWeatherAync(Listener listener,String searchView, String api_key) {
        this.listener = listener;
        this.serviceUrl = "http://api.openweathermap.org/data/2.5/forecast?q=" + searchView + api_key;
    }

    @Override
    protected List<ForecastWeatherList> doInBackground(Context...params) {
        try {
            URL url = new URL(serviceUrl);

            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setDoOutput(true);
            connection.setConnectTimeout(4000);
            connection.setReadTimeout(4000);
            connection.connect();

            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            ForecastWeatherListWrapper weatherWrapper = new Gson().fromJson(bufferedReader, ForecastWeatherListWrapper.class);
            return weatherWrapper.getforecastWeatherLists();
        } catch (Exception e) {}
        return null;
    }

    @Override
    protected void onPostExecute(List<ForecastWeatherList> result) {
        super.onPostExecute(result);
        if (result != null) {
            Log.e(TAG, "populate UI recycler view with gson converted data");
            listener.afterSearch(result);
        }
    }
}

Here is the recyclerview adapter.

 public class RecyclerViewAdapter  extends        
 RecyclerView.Adapter<RecyclerViewAdapter.ForecastRecycler> {

List<ForecastWeatherList> mForecastWeatherDataList;

public static class ForecastRecycler extends RecyclerView.ViewHolder{

public TextView currentTemp;
public TextView currentHumidity;
public TextView currentDescription;
public ImageView currentIcon;

public ForecastRecycler (View view) {
    super (view);

    currentTemp = (TextView) view.findViewById(R.id.current_temperature);
    currentHumidity = (TextView) view.findViewById(R.id.current_humidity);
    currentDescription = (TextView) view.findViewById(R.id.current_weather_description);
    currentIcon = (ImageView) view.findViewById(R.id.current_weather_icon);

}

}

public RecyclerViewAdapter(List<ForecastWeatherList> mForecastWeatherDataList, Context mContext) {
    this.mForecastWeatherDataList = mForecastWeatherDataList;
}

@Override
public ForecastRecycler onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item, parent, false);

        final ForecastRecycler  currentRecycler = new ForecastRecycler(view);

        return currentRecycler;
}

@Override
public void onBindViewHolder( ForecastRecycler holder, int position) {

    final ForecastWeatherList currentRecycler = mForecastWeatherDataList.get(position);
    holder.currentTemp.setText((currentRecycler.getMain().getTempKf()));
    holder.currentHumidity.setText(currentRecycler.getMain().getHumidity());
    holder.currentDescription.setText(currentRecycler.getWeather().getDescription());
    Picasso.with(holder.currentIcon.getContext()).load(currentRecycler.getWeather().getIcon());


}

@Override
public int getItemCount() {
    return mForecastWeatherDataList.size();
}

}

Here are my current logs. I know its connecting to the server but I'm still getting no adapter attached error.

11371-11371/com.ksburneytwo.weathertest D/debugMode: The application is in onCreateView

11371-11396/com.ksburneytwo.weathertest D/debugMode: The application is in doInBackground

11371-11371/com.ksburneytwo.weathertest E/RecyclerView: No adapter attached; skipping layout

11371-11396/com.ksburneytwo.weathertest D/NetworkSecurityConfig: No Network Security Config specified, using platform default

11371-11396/com.ksburneytwo.weathertest D/debugMode: The application stopped after catch

ksb
  • 87
  • 1
  • 8
  • 1
    initialize your adapter and recyclerview in onCreateview() with an empty list, then when your async task load your data list then simply add the response to the list and notify the adapter – Devil10 Aug 16 '18 at 16:04
  • Possible duplicate of [recyclerview No adapter attached; skipping layout](https://stackoverflow.com/questions/29141729/recyclerview-no-adapter-attached-skipping-layout) – Mosius Aug 19 '18 at 04:26

1 Answers1

1

Try notifyDataSetChanged() in adapter after initializing in onCreateView() method.

or use this approach:

Listener:

public interface Listener {
    void afterSearch(List<ForecastWeatherList> result);
}

Fragment:

 public class MyFragment extends Fragment implements Listener {
    RecyclerView mRecyclerView;
    List<ForecastWeatherList> items = new ArrayList<>();
    RecyclerViewAdapter adapter;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_weather_app, container, false);

        mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        mRecyclerView.addItemDecoration(new DividerItemDecoration(mRecyclerView.getContext(), DividerItemDecoration.VERTICAL));

        adapter = new RecyclerViewAdapter(items, mRecyclerView.getContext());
        mRecyclerView.setAdapter(adapter);

        new GetWeatherAync(this, searchView, api_key).execute();
        return view;
    }

    public afterSearch(List<ForecastWeatherList> result) {
        items = result;
        adapter.notifyDataSetChanged();
    }
}

AsyncTask:

private static class GetWeatherAync extends AsyncTask<Context, Void, List<ForecastWeatherList>> {
    private String TAG = GetWeatherAync.class.getSimpleName();
    private final String serviceUrl;
    private Context mContext;
    private Listener listener;

    public GetWeatherAync(Listener listener, Object searchView, Object api_key) {
        this.listener = listener;
        this.serviceUrl = "http://api.openweathermap.org/data/2.5/forecast?q=" + searchView + api_key;
    }

    @Override
    protected List<ForecastWeatherList> doInBackground(Context...params) {
        try {
            URL url = new URL(serviceUrl);

            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setDoOutput(true);
            connection.setConnectTimeout(4000);
            connection.setReadTimeout(4000);
            connection.connect();

            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            ForecastWeatherListWrapper weatherWrapper = new Gson().fromJson(bufferedReader, ForecastWeatherListWrapper.class);
            return weatherWrapper.getforecastWeatherLists();
        } catch (Exception e) {}
        return null;
    }

    @Override
    protected void onPostExecute(List<ForecastWeatherList> result) {
       super.onPostExecute(result);
       if (result != null) {
           Log.e(TAG, "populate UI recycler view with gson converted data");
           listener.afterSearch(result);
       }
    }
}
The Badak
  • 2,010
  • 2
  • 16
  • 28
  • I tried to use the second method but android studio is not recognizing the implementation of the listener (the public class WeatherAppFragment line is in red) and the empty GetWeatherAync(). The parenthesis have a red underline. – ksb Aug 16 '18 at 17:52
  • make different classes and also change ```MyFragment``` to whatever your fragment's name is – The Badak Aug 17 '18 at 01:53
  • I made the changes but I'm still getting a warning about the GetWeatherAync. Studio is telling me that GetWeatherAync() in GetWeatherAync cannot be applied to expected and actual arguments. I've updated my question with the revised code above. – ksb Aug 17 '18 at 02:55
  • I'm still getting the skipping layouts in my logcat. I've added my recyclerviewadapter since I think that may have something to do with it. – ksb Aug 17 '18 at 17:16
  • I added some tags and apparently its getting to the doInBackground before it states that there is no adapter attached. – ksb Aug 17 '18 at 18:47
  • Yes there is still a problem. I put the logs in the main post for analysis. – ksb Aug 19 '18 at 04:05
  • glad to help you out :) – The Badak Aug 20 '18 at 06:51