Retrofit 2: error in my GET request - android

I'm developing an Android app that shows movie posters for top rated movies. I want to build this by using Retrofit 2. However, I keep getting the error 'Service methods cannot return void'. Here's the stack trace:
FATAL EXCEPTION: main
Process: com.hfad.popularmovies, PID: 17921
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.hfad.popularmovies/com.hfad.popularmovies.MainActivity}: java.lang.IllegalArgumentException: Service methods cannot return void.
for method MoviesAPI.getFeedPopular
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.IllegalArgumentException: Service methods cannot return void.
I have created a POJO containing the fields I need & the necessary interface containing the get request =>
public interface MoviesAPI {
#GET("/movie/top_rated?api_key=XXXXXXX")
void getFeedTopRated(Callback <List<Movie>> response);
#GET("/movie/popular?api_key=XXXXXXX")
void getFeedPopular(Callback<List<Movie>> response);
}
Here's the fragment that should display the posters through a RecyclerView:
public class TopRatedFragment extends Fragment {
private static final String ENDPOINT = "http://api.themoviedb.org/3/";
private PosterAdapter adapter;
private List<Movie> movieList;
public TopRatedFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
RecyclerView recyclerView = (RecyclerView) inflater.inflate(R.layout.fragment_top_rated, container, false);
adapter = new PosterAdapter(getActivity());
recyclerView.setAdapter(adapter);
GridLayoutManager layoutManager = new GridLayoutManager(getActivity(), 2);
recyclerView.setLayoutManager(layoutManager);
getTopRatedMovies();
return recyclerView;
}
private void getTopRatedMovies() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ENDPOINT)
.build();
MoviesAPI api = retrofit.create(MoviesAPI.class);
api.getFeedTopRated(new Callback<List<Movie>>() {
#Override
public void onResponse(Call<List<Movie>> call, Response<List<Movie>> response) {
movieList = response.body();
for (Movie movie : movieList) {
movie.getPoster_path(); //I get the same error when I use
}
}
#Override
public void onFailure(Call<List<Movie>> call, Throwable t) {
}
});
}
}
Please, let me know if I should provide more code or background information.

Your interface method needs to return an object from the type
Call<Expected Result Object>
For example
#GET("/movie/top_rated?api_key=XXXXXXX")
Call<List<Movie>> getFeedTopRated();
And in the method you need to write the function as following:
api.getFeedTopRated().enque(new Callback<List<Movie>>() { /* */ });

Related

How to resolve error findViewById error in android fragment

I'm trying to add recyclerview in my fragment but I'm getting error when I click on navigation drawer item.
Attempt to invoke virtual method 'android.view.View android.view.View.findViewById(int)' on a null object reference
at com.example.myapplication.fragment.Books.onCreate(Books.java:45)
How to resolve error or suggest tutorial to load json data in fragment using recyclerview. with click event on recyclerview. on click item open new fragment with data.
This is my code
public class Books extends Fragment {
private BooksModel booksViewModel;
private RecyclerView recyclerView;
private RecyclerView.Adapter adapter;
private List<BooksModel> bookLists;
// Context context;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
recyclerView = (RecyclerView) getView().findViewById(R.id.recyclerViewBook); //Line 45 Error
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
bookLists = new ArrayList<>();
for(int i=0; i<=10; i++){
BooksModel bookList = new BooksModel(
"",
"Title " + (i + 1),
"This is Auther"
);
bookLists.add(bookList);
adapter = new BooksAdapter(bookLists,this);
recyclerView.setAdapter(adapter);
}
}
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
booksViewModel =
new ViewModelProvider(this).get(BooksModel.class);
View root = inflater.inflate(R.layout.fragment_books, container, false);
final TextView textView = root.findViewById(R.id.text_book );
booksViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
#Override
public void onChanged(#Nullable String s) {
textView.setText(s);
}
});
return root;
}
}
onCreate() runs before onCreateView(). You should move all of that code to onViewCreated(), which passes you the View directly (meaning you don't have to call getView() at all).

Acces BottomNavigationView item from onItemClick in a fragment

I have a MainActivity with a BottomNavigationView with 3 items in it. When I first open the app, only one is enable, the first one.
I have a RecyclerView on the first fragment (the first item in the menu). When I click on one item of the RecyclerView, I want to switch to the second Fragment and to enable the second and third item.
I am able to switch to the second Fragment, but I can not set the items enable again.
The first Fragment with the RecyclerView is:
public class Homefragment extends Fragment implements OnItemClickListener {
private ArrayList<fileItem> mfileList = new ArrayList<>();
private RecyclerView mRecyclerView;
private fileAdapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private BottomNavigationView bottomNav;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home, container, false);
Context context = getActivity();
bottomNav = view.findViewById(R.id.bottom_navigation);
// Listing all text files
String path = Environment.getExternalStorageDirectory().toString()+"/FlexiCounts";
File directory = new File(path);
File[] filesList = directory.listFiles(new FilenameFilter() {
public boolean accept(File directory, String name) {
return name.toLowerCase().endsWith(".txt");
}
});
setRecyclerView(view, filesList);
return view;
}
private void setRecyclerView(View view, File[] files){
if (files.length > 0) {
for (int i = 0; i < files.length; i++) {
mfileList.add(new fileItem(R.drawable.ic_account_balance_black_24dp, files[i].getName().replace(".txt", ""), "25-03-2020", "07-04-2020"));
}
mRecyclerView = view.findViewById(R.id.fileRecycler);
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(getActivity());
mAdapter = new fileAdapter(mfileList, this);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
}
}
// the magic should happen here !
#Override
public void onItemClick(int position) {
mfileList.get(position);
getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container_primary, new Dashboardfragment()).commit();
bottomNav.getMenu().getItem(1).setEnabled(true);
//bottomNav.getMenu().getItem(2).setEnabled(true);
}
}
The following lines does not work:
bottomNav.getMenu().getItem(1).setEnabled(true);
It seems to point to a null reference. I think it does not find the bottomNav define with R.id.bottom_navigation in the onCreateView method. In fact, the bottom_navigation is contained in the MainActivity layout, but that should not be a problem. I get this error:
--------- beginning of crash
2020-04-15 20:09:20.202 8673-8673/com.flexicounts.flexicounts E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.flexicounts.flexicounts, PID: 8673
java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.Menu android.support.design.widget.BottomNavigationView.getMenu()' on a null object reference
at com.flexicounts.flexicounts.Homefragment.onItemClick(Homefragment.java:145)
at com.flexicounts.flexicounts.fileAdapter$fileViewHolder.onClick(fileAdapter.java:50)
at android.view.View.performClick(View.java:5637)
at android.view.View$PerformClick.run(View.java:22429)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
create a BottomNavigationView getBottomNav() method in main activity then get it from onItemClick
in MainActivity:
public BottomNavigationView getBottomNav(){ return findViewById(R.id.bottom_navigation); }
in Homefragment:
// the magic should happen here !
#Override
public void onItemClick(int position) {
mfileList.get(position);
getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container_primary, new Dashboardfragment()).commit();
((MainActivity) getActivity()).getBottomNav().getMenu().getItem(1).setEnabled(true);
//bottomNav.getMenu().getItem(2).setEnabled(true);
}

Why can't I access adapter submitList() method from within onChanged()?

Can someone tell me why the submitList() method can't be accessed in the following code? Similar code is working fine in another test app, although that's in an Activity.
public class MyFFBooksFragment extends Fragment {
private int currentBook;
private RecyclerView mRecyclerView;
private RecyclerView.LayoutManager mLayoutManager;
private GamebookViewModel gamebookViewModel;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable
ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.myffbooks_fragment, container, false);
mLayoutManager = new LinearLayoutManager(getActivity());
final ArrayList<BookItem> bookList = new ArrayList<>();
final BookItemAdapter maAdapter = new BookItemAdapter(bookList);
mRecyclerView = view.findViewById(R.id.recyclerView);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setAdapter(maAdapter);
gamebookViewModel = ViewModelProviders.of(this).get(GamebookViewModel.class);
gamebookViewModel.getAllGamebooks().observe(this, new Observer<List<Gamebook>>() {
#Override
public void onChanged(#Nullable List<Gamebook> gamebooks) {
maAdapter.submitList(bookList);
}
});
return view;
}
}
Perhaps you should not use it in onCreateView(). Try use call method that triggers observation of VM after an Activity had been created, near onStart(). Maybe it will help.
When a new page is available, we call submitList() method of the PagedListAdapter class
override fun onStart() {
super.onStart()
gamebookViewModel.callFunc()
}
Also as I understand, you call getAllGamebooks() which triggers some actions and return you LiveData<*> and you subscribe on it with observe(). I recommend you to separate this on 2 methods:
subscribe
action
Use PagedList instead of list like below:
gamebookViewModel.getAllGamebooks().observe(this, new Observer<PagedList<Gamebook>>() {
#Override
public void onChanged(#Nullable PagedList<Gamebook> gamebooks) {
maAdapter.submitList(bookList);
}
});
And in your viewmodel too.
Found the problem. My adapter wasn't extending ListAdapter, so no wonder it couldn't find the submitList() method. Rookie error.

Retrofit2 in Android Fragment how to implement correctly?

I'm using Retrofit 2 to consume an API. I have a service (interface) which returns a list:
#GET("atenciones")
Call<List<Atencion>> getAtenciones(#Query("medico_id") int id, #Query("date1") String date1, #Query("date2") String date2)
Where should I do the request? In the MainActivity which contains the Fragment and send the result list using Bundle? or should do the request in the Fragment? this is a list not a single object. Which is the correct way?
Edit
Try to call retrofit in Fragment, this is my code:
public class FragmentRendicion extends Fragment {
private LinearLayoutManager layoutManager;
View rootView;
APIService api;
public FragmentRendicion() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_rendicion, container, false);
api= ApiUtils.getAPIService();
getAtenciones();
return rootView;
}
private void getAtenciones() {
//using static parameters
Call<List<Atencion>> call= api.getAtenciones(293,"2014-10-13","2014-10-13");
call.enqueue(new Callback<List<Atencion>>() {
#Override
public void onResponse(Call<List<Atencion>> call, Response<List<Atencion>> response) {
System.out.println("estamos aquiiii "+response.message());
List<Atencion> atenciones= response.body();
layoutManager= new LinearLayoutManager(getActivity());
RecyclerView recycler= (RecyclerView)rootView.findViewById(R.id.rvRendicion);
recycler.setLayoutManager(layoutManager);
RvRendicionAdapter rvAdapter= new RvRendicionAdapter(atenciones);
recycler.setAdapter(rvAdapter);
}
#Override
public void onFailure(Call<List<Atencion>> call, Throwable t) {
System.out.println("FALLOOOOO: "+t.getMessage());//HERE RETUNRS NULL
}
});
}
}
Can someone tell me is if it correct way to call retrofit2 in fragment?
It depends on the structure of your code but since you are using fragments my best guess is you should do it in the Fragment.
In the onResponseOK of the Retrofit call you will have something like this:
#Override
public void onResponseOK(Response<List<Atencion>> response) {
...
//access data here
}
In the callback you get your list. Pass the list to the adapter of your (I suppose) Recycler/Listview. Access the list like this:
List<Atencion> myList = response.body();

RecyclerView with null pointer exception

I am getting some news data from my CMS,and want to display them in a RecyclerView.The problem is that I am getting a null pointer exception in the line where I using the LinearLayoutManager. Here is the logcat output.
Caused by: java.lang.NullPointerException
at testing.theo.manchesterunitedapp.newsandfeatures.FeaturesFragment.onCreateView(FeaturesFragment.java:65)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1962)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613)
at android.support.v4.app.FragmentController.execPendingActions(FragmentController.java:330)
at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:547)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1171)
at android.app.Activity.performStart(Activity.java:5241)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2157)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233) 
at android.app.ActivityThread.access$800(ActivityThread.java:135) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:136) 
at android.app.ActivityThread.main(ActivityThread.java:5001) 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:515)
The Fragment where I am doing the webservice part is quite simple. I use to callback methods. The onCreateView where I am initialising the ArrayList and the RecyclerView,and secondly the onActivityCreate where I am running the webservice.
public class FeaturesFragment extends Fragment {
public static final String TAG = "ManuApp";
private static final String IMAGE_URL = "xxxxxxxxxxxx/xxxx/features_images/" ;
private List<FeaturesObject> listItemsList;
private RecyclerView mRecyclerView;
private FeaturesAdapter adapter;
public FeaturesFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.features_row, container, false);
// Inflate the layout for this fragment
listItemsList = new ArrayList<>();
mRecyclerView = (RecyclerView)v.findViewById(R.id.features_recycler_view);
//mRecyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).color(Color.BLACK).build());
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(linearLayoutManager);
return v;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
updateFeaturesList();
}
public void updateFeaturesList() {
//declare the adapter and attach it to the recyclerview
adapter = new FeaturesAdapter(getActivity(), listItemsList);
mRecyclerView.setAdapter(adapter);
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(getActivity());
// Request a string response from the provided URL.
JsonArrayRequest jsObjRequest = new JsonArrayRequest(Request.Method.GET, Config.URL_FEATURES, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.d(TAG, response.toString());
//hidePD();
// Parse json data.
// Declare the json objects that we need and then for loop through the children array.
// Do the json parse in a try catch block to catch the exceptions
try {
for (int i = 0; i < response.length(); i++) {
JSONObject post = response.getJSONObject(i);
FeaturesObject item = new FeaturesObject();
item.setTitle(post.getString("title"));
item.setImage(IMAGE_URL + post.getString("features_image"));
item.setArticle(post.getString("article"));
listItemsList.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
// Update list by notifying the adapter of changes
adapter.notifyDataSetChanged();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
//hidePD();
}
});
jsObjRequest.setRetryPolicy(new RetryPolicy() {
#Override
public int getCurrentTimeout() {
return 50000;
}
#Override
public int getCurrentRetryCount() {
return 50000;
}
#Override
public void retry(VolleyError error) throws VolleyError {
}
});
queue.add(jsObjRequest);
}
}
This part of the code causes the problem.
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(linearLayoutManager);
This is strange,as I am using the same techiques to obtain data in another fragment of my app.
Any ideas?
Thanks.
Your RecyclerView is null. Are you sure you're looking for the correct id in the correct layout file? My guess is either you are inflating the incorrect layout file, or you're looking for the incorrect view id for the RecyclerView.
Probably this is not the case but... As a general rule all initialization that need instance of the activity must be in onActivityCreated() (or the next methods in the Fragment lifecycle). Inside onCreateView() getActivity() is not guaranteed to return non-null value. In some scenarios it returns null.
Seems like the id that you are trying to find it's not on features_row that's why you get NullPointerException on that line :
mRecyclerView = (RecyclerView)v.findViewById(R.id.features_recycler_view);
If you keep getting error you could try this :
final FragmentActivity c = getActivity();
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(c);
mRecyclerView.setLayoutManager(linearLayoutManager );

Categories

Resources