I want to know how to get a URL in a json and open it in a setOnClickListener of a RecyclerView
My API Json
{
{
"link": "https://example.com"
},
{
...
}
}
My URLModel
public class URLModel {
String Link;
public MonlixModel(String link) {
Link = link;
}
public String getLink() {
return Link;
}
public void setLink(String link) {
Link = link;
}
}
I think the problem comes from my Adapter but I don't know where and how to fix it
public class URLAdapter extends RecyclerView.Adapter<URLAdapter.URLHolder> {
Context mContext;
List<URLModel> urlModels;
public URLAdapter(Context mContext, List<URLAdapter> urlModels) {
this.mContext = mContext;
this.urlModels= urlModels;
}
#NonNull
#Override
public URLHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.recycler_view, parent, false);
return new URLHolder(view);
}
#Override
public void onBindViewHolder(#NonNull URLHolder holder, int position) {
holder.recyclerUrl.setOnClickListener(view -> {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(urlModels.get(position).getLink()));
mContext.startActivity(intent);
});
}
#Override
public int getItemCount() {
return urlModels.size();
}
public static class URLHolder extends RecyclerView.ViewHolder {
private final RecyclerView recyclerUrl;
public URLHolder(#NonNull View itemView) {
super(itemView);
recyclerUrl = itemView.findViewById(R.id.recycler_url);
}
}
}
And finally my Main.java
private void getData() {
RequestQueue requestQueue = Volley.newRequestQueue(this);
#SuppressLint("NotifyDataSetChanged") JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.GET, Apis.JSON_API, null, response -> {
for(int i = 0; i <=response.length(); i++){
try {
JSONObject jsonObject = response.getJSONObject(i);
URLModelList.add(new URLModel(
jsonObject.getString("link")
));
} catch (JSONException e) {
e.printStackTrace();
}
}
URLAdapter adapter = new URLAdapter(getApplicationContext(), URLModelList);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
Toast.makeText(Main.this, "Success", Toast.LENGTH_SHORT).show();
}, error -> Toast.makeText(Main.this, error.getMessage(), Toast.LENGTH_SHORT).show());
requestQueue.add(jsonArrayRequest);
}
I use Volley, I don't know if it's the most adapted but I succeeded with that, I also tried to change in my URLModel the String by a Uri. But I noticed that the JSONObject didn't have a getUri or something like that
In my Logcat it tells me it's a null object reference
Any help will be much appreciated!
Please check your JSON format first,
{
"key_name1": {
"link": "https://example.com"
},
"key_name2":{
...
}
}
make sure your inner object should have key_name as above example or make this JSONObject to JSONArray like this
[
{
"link": "https://example.com"
},
{
}
]
Related
I am trying to parse a Block of JSON into a RecyclerView. So far I was able to achieve this with a quite flat JSON Structure. But now I have an Array-Entry in my JSON File where I always want to get the first Entry.
The JSON looks like this:
[
{
"MatchID": 60989,
"Team1": {
"TeamName": "FC Bayern München",
"TeamIconUrl": "https://i.imgur.com/jJEsJrj.png"
},
"Team2": {
"TeamName": "VfL Wolfsburg",
"TeamIconUrl": "https://i.imgur.com/ucqKV4B.png"
},
"MatchResults": [
{
"PointsTeam1": 4,
"PointsTeam2": 0,
"ResultOrderID": 1
},
{
"PointsTeam1": 1,
"PointsTeam2": 0,
"ResultOrderID": 2
}
]
},
{
"MatchID": 60990,
"Team1": {
"TeamName": "VfL Bochum",
"TeamIconUrl": "https://i.imgur.com/5jy3Gfr.png"
},
"Team2": {
"TeamName": "1. FC Union Berlin",
"TeamIconUrl": "https://upload.wikimedia.org/wikipedia/commons/4/44/1._FC_Union_Berlin_Logo.svg"
},
"MatchResults": [
{
"PointsTeam1": 0,
"PointsTeam2": 1,
"ResultOrderID": 1
},
{
"PointsTeam1": 0,
"PointsTeam2": 1,
"ResultOrderID": 2
}
]
}
]
My Activity fetches this JSON from an API using Retrofit2
private void parseJson() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://www.openligadb.de/api/")
.addConverterFactory(GsonConverterFactory.create())
.build();
RequestInterface request = retrofit.create(RequestInterface.class);
Call<List<Match>> call=request.getMatchJson();
call.enqueue(new Callback<List<Match>>() {
#Override
public void onResponse(Call<List<Match>> call, Response<List<Match>> response) {
if (response.isSuccessful() && response.body() != null) {
matchList = new ArrayList<>(response.body());
matchAdapter = new MatchAdapter(matchList, ActivityMatch.this);
mRecyclerView.setAdapter(matchAdapter);
}
}
#Override
public void onFailure(Call<List<Match>> call, Throwable t) {
Log.println(Log.ERROR, "FAILED", String.valueOf(t));
Toast.makeText(ActivityMatch.this, "Oops! Somehting went wrong!", Toast.LENGTH_SHORT).show();
}
});
}
My MatchAdapter is then parsing this Data for the View. Here I want to display whatever is the first in MatchResults then using PointsTeam1 and PointsTeam2 to display something like "4 : 0"
Now in my ModelClass accessing direct Values like the TeamName and TeamIconUrl worked but I am struggeling to get to the first entry of the Array and am really stuck on even how to properly approach this issue.
The Adapter Class:
public class MatchAdapter extends RecyclerView.Adapter<MatchAdapter.MatchHolder>{
private ArrayList<Match> matchList;
private Context context;
public MatchAdapter(ArrayList<Match> matchList, Context context) {
this.context = context;
this.matchList = matchList;
}
#NonNull
#Override
public MatchAdapter.MatchHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int viewType) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.match_list_row_layout, viewGroup, false);
return new MatchHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MatchAdapter.MatchHolder holder, int position) {
holder.tvTeam1name.setText(matchList.get(position).Team1.TeamName);
holder.tvTeam2name.setText(matchList.get(position).Team2.TeamName);
Glide.with(context).load(matchList.get(position).Team1.TeamIconUrl).into(holder.ivTeam1Logo);
Glide.with(context).load(matchList.get(position).Team2.TeamIconUrl).into(holder.ivTeam2Logo);
//This is not working
holder.tvResult.setText(matchList.get(position).MatchResults.PointsTeam1 + " : " + matchList.get(position).MatchResults.PointsTeam2);
}
#Override
public int getItemCount() {
return matchList.size();
}
public class MatchHolder extends RecyclerView.ViewHolder {
private TextView tvTeam1name, tvTeam2name, tvResult;
private ImageView ivTeam1Logo, ivTeam2Logo;
public MatchHolder(#NonNull View itemView) {
super(itemView);
tvTeam1name = itemView.findViewById(R.id.tv_team1name);
tvTeam2name = itemView.findViewById(R.id.tv_team2name);
tvResult = itemView.findViewById(R.id.tv_result);
ivTeam1Logo = itemView.findViewById(R.id.iv_team1logo);
ivTeam2Logo = itemView.findViewById(R.id.iv_team2logo);
}
}
}
My ModelClass (Left out Getters/Setters for Readability)
package de.eahjena.app.wi.fussball;
public class Match {
Team Team1;
Team Team2;
MatchResults MatchResults;
public Match(Team Team1, Team Team2, MatchResults MatchResults) {
this.Team1 = Team1;
this.Team2 = Team2;
this.MatchResults = MatchResults;
}
}
class Team {
String TeamName;
String TeamIconUrl;
public Team (String TeamName, String TeamIconUrl) {
this.TeamName = TeamName;
this.TeamIconUrl = TeamIconUrl;
}
}
class MatchResults {
String PointsTeam1;
String PointsTeam2;
public MatchResults(String PointsTeam1, String PointsTeam2) {
this.PointsTeam1 = PointsTeam1;
this.PointsTeam2 = PointsTeam2;
}
}
As per the question you are suppose to use List<MatchResults> MatchResults since the API response contains a list of match results.
Further to use the first position from the matchResults array you cna use it like this in your adapter :
matchList.get(position).MatchResults.get(0).PointsTeam1
How do I remove all null and empty string values from an object in JSON java android from retrofit?
Filter out any items where "name" is blank or null.
this is my Main Activity
Api api = retrofit.create(Api.class);
Call<List<MainData>> call = api.getData();
call.enqueue(new Callback<List<MainData>>() {
#Override
public void onResponse (Call<List<MainData>> call, Response<List<MainData>> response) {
if (!response.isSuccessful()) {
Toast.makeText(MainActivity.this, response.code(), Toast.LENGTH_SHORT).show();
return;
}
List<MainData> postList = response.body();
// Filter out any items where "name" is blank or null.
List<MainData> tempList = new ArrayList<>();
for(MainData data :postList)
{
if(null!= data.getName() && !data.getName().isEmpty()) {
//sort by name
Collections.sort(tempList, (mainData, t1) -> mainData.getName().compareTo(t1.getName()));
//sort by ListId
Collections.sort(tempList, (mainData, t1) -> mainData.getListId().compareTo(t1.getListId()) );
tempList.add(data);
}
}
RecyclerViewAdapter recyclerViewAdapter = new RecyclerViewAdapter(tempList, MainActivity.this);
recyclerView.setAdapter(recyclerViewAdapter);
}
#Override
public void onFailure (Call<List<MainData>> call, Throwable t) {
Toast.makeText(MainActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
This Is My Adpater
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
//initialize variables
List<MainData> dataArrayList;
Context context;
//create constructor
public RecyclerViewAdapter (Context context, List<MainData> dataArrayList) {
this.dataArrayList = dataArrayList;
this.context = context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder (#NonNull ViewGroup parent, int viewType) {
//this method recycling the view holder
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder (#NonNull ViewHolder holder, int position) {
//initialize Main data
MainData data = dataArrayList.get(position);
//set name on text view
holder.listId.setText(String.format("list_id : %s", data.getListId()));
holder.name.setText(String.format("name : %s", data.getName()));
holder.id.setText(String.format("id : %s", data.getId()));
}
#Override
public int getItemCount () {
return dataArrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
//initialize variables
TextView listId, name, id;
public ViewHolder (#NonNull View itemView) {
super(itemView);
//assign variables
listId = itemView.findViewById(R.id.list_id);
name = itemView.findViewById(R.id.name);
id = itemView.findViewById(R.id.id);
}
}
}
this is the Data
public class MainData {
public String listId, name, id;
public String getListId () {
return listId;
}
public String getName () {
return name;
}
public String getId () {
return id;
}
}
And this is the Api
public interface Api {
#GET("hiring.json")
Call<List<MainData>> getData();
}
And this is my app I want to remove nulls and emp
enter image description here
There are two ways
(1) While inflating the data you can filter these unwanted values
(2) Create a temporary list and add only required values from the main list.
sample code:
List<MainData> tempList = new ArrayList<>();
for(MainData data :postList)
{
if(null!= data.getName() && !data.getName().isEmpty())
{ tempList.add(data);
}
}
And then pass this tempList to the adapter.
Final code would look like this.
Api api = retrofit.create(Api.class);
Call<List<MainData>> call = api.getData();
call.enqueue(new Callback<List<MainData>>() {
#Override
public void onResponse (Call<List<MainData>> call, Response<List<MainData>> response) {
if (!response.isSuccessful()) {
Toast.makeText(MainActivity.this, response.code(), Toast.LENGTH_SHORT).show();
return;
}
List<MainData> postList = response.body();
//sort by ListId
Collections.sort(postList, (mainData, t1) -> mainData.getListId().compareTo(t1.getListId()));
// Filter out any items where "name" is blank or null.
List<MainData> tempList = new ArrayList<>();
for(MainData data :postList)
{
if(null!= data.getName() && !data.getName().isEmpty())
{ tempList.add(data);
}
}
RecyclerViewAdapter recyclerViewAdapter = new RecyclerViewAdapter(MainActivity.this, tempList );
recyclerView.setAdapter(recyclerViewAdapter);
}
#Override
public void onFailure (Call<List<MainData>> call, Throwable t) {
Toast.makeText(MainActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
Feel free to ask if something is unclear.
why my data cant show, the error in logcat is "No adapter attached; skipping layout" and "the mapper function return null",
this my viewModel i get my api in here Model.java
public class Model extends ViewModel {
private static final String API_KEY = "my-api";
private MutableLiveData<ArrayList<MoviesItems>> listMovies = new MutableLiveData<>();
void setMovies(){
AsyncHttpClient client = new AsyncHttpClient();
final ArrayList<MoviesItems> listItems = new ArrayList<>();
String url = "https://api.themoviedb.org/3/discover/movie?api_key=" + API_KEY + "&language=en-US";
client.get(url, new AsyncHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
try {
String result = new String(responseBody);
JSONObject object = new JSONObject(result);
JSONArray list = object.getJSONArray("results");
for (int i = 0;1 < list.length(); i++){
JSONObject movies = list.getJSONObject(i);
MoviesItems moviesItems = new MoviesItems(movies);
listItems.add(moviesItems);
}
listMovies.getValue();
}catch (Exception e){
Log.d("Exception", e.getMessage());
}
}
#Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
Log.d("onFailure", error.getMessage());
}
});
}
public LiveData<ArrayList<MoviesItems>> getMovies(){
return listMovies;
}
}
and this my fragment i think my error in here MoviesFragment.java
View rootView = inflater.inflate(R.layout.fragment_movies, container, false);
viewModel = ViewModelProviders.of(this).get(Model.class);
viewModel.getMovies().observe(this, getMovie);
//pb = rootView.findViewById(R.id.pb);
moviesAdapter = new MoviesAdapter(getActivity());
moviesAdapter.notifyDataSetChanged();
rv_grid_movies = rootView.findViewById(R.id.rv_grid_movies);
RecyclerView.LayoutManager manager = new GridLayoutManager(getActivity(), 2);
rv_grid_movies.setLayoutManager(manager);
rv_grid_movies.addItemDecoration(new GridSpacingItemDecoration(2, dpToPx(3), true));
rv_grid_movies.setItemAnimator(new DefaultItemAnimator());
rv_grid_movies.setAdapter(moviesAdapter);
rv_grid_movies.setHasFixedSize(true);
return rootView;
}
private Observer<ArrayList<MoviesItems>> getMovie = new Observer<ArrayList<MoviesItems>>() {
#Override
public void onChanged(#Nullable ArrayList<MoviesItems> moviesItems) {
if (moviesItems != null){
moviesAdapter.setData(moviesItems);
//loadData(false);
}
}
};
this my modelitems this place i get jsonObject MoviesItems.java
public MoviesItems(JSONObject object){
try {
//JSONArray array = object.getJSONArray("results");
int id = object.getInt("id");
String title = object.getString("title");
String overview = object.getString("overview");
String poster_path = object.getString("poster_path");
String release_date = object.getString("release_date");
this.id = id;
this.title = title;
this.overview = overview;
this.poster_path = poster_path;
this.release_date = release_date;
}catch (Exception e){
e.printStackTrace();
}
}
and this my adapter MoviesAdapter.java
public class MoviesAdapter extends RecyclerView.Adapter<MoviesAdapter.MoviesViewHolder> {
private ArrayList<MoviesItems> mItems;
private Context context;
public MoviesAdapter(Context context){
this.context = context;
}
public void setData(ArrayList<MoviesItems> mItems) {
mItems.clear();
mItems.addAll(mItems);
notifyDataSetChanged();
}
public void addItems(final MoviesItems moviesItems){
mItems.add(moviesItems);
notifyDataSetChanged();
}
#Override
public void onAttachedToRecyclerView(#NonNull RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
#Override
public void onDetachedFromRecyclerView(#NonNull RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
}
private void clearData(){
mItems.clear();
}
#NonNull
#Override
public MoviesViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.grid_movies, viewGroup, false);
final MoviesViewHolder holder = new MoviesViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(#NonNull MoviesViewHolder moviesViewHolder, int i) {
moviesViewHolder.bind(mItems.get(i));
}
#Override
public int getItemCount() {
return (mItems != null) ? mItems.size(): 0;
}
public class MoviesViewHolder extends RecyclerView.ViewHolder {
TextView txt_title_movies, txt_date_movies, txt_description_movies;
ImageView img_movies;
String url = "https://image.tmdb.org/t/p/original";
public MoviesViewHolder(#NonNull View itemView) {
super(itemView);
txt_title_movies = itemView.findViewById(R.id.txt_titlemovie);
txt_date_movies = itemView.findViewById(R.id.txt_datemovie);
txt_description_movies = itemView.findViewById(R.id.txt_descriptionmovie);
img_movies = itemView.findViewById(R.id.img_movie);
}
public void bind(MoviesItems moviesItems) {
txt_title_movies.setText(moviesItems.getTitle());
txt_date_movies.setText(moviesItems.getRelease_date());
txt_description_movies.setText(moviesItems.getOverview());
Glide.with(context)
.load(url+moviesItems.getPoster_path())
.into(img_movies);
}
}
}
and this json i want get
{
"page": 1,
"total_results": 432039,
"total_pages": 21602,
"results": [
{
"vote_count": 672,
"id": 384018,
"video": false,
"vote_average": 6.5,
"title": "Fast & Furious Presents: Hobbs & Shaw",
"popularity": 317.725,
"poster_path": "/keym7MPn1icW1wWfzMnW3HeuzWU.jpg",
"original_language": "en",
"original_title": "Fast & Furious Presents: Hobbs & Shaw",
"genre_ids": [
28
],
"backdrop_path": "/hpgda6P9GutvdkDX5MUJ92QG9aj.jpg",
"adult": false,
"overview": "A spinoff of The Fate of the Furious, focusing on Johnson's US Diplomatic Security Agent Luke Hobbs forming an unlikely alliance with Statham's Deckard Shaw.",
"release_date": "2019-08-01"
},
and this my error
java.lang.NullPointerException: The mapper function returned a null value.
at io.reactivex.d.b.b.a(ObjectHelper.java:39)
at io.reactivex.d.e.b.g$a.onNext(ObservableMap.java:59)
at io.reactivex.d.e.b.i$a.run(ObservableScalarXMap.java:248)
at io.reactivex.d.e.b.f.b(ObservableJust.java:35)
at io.reactivex.h.a(Observable.java:11442)
at io.reactivex.d.e.b.g.b(ObservableMap.java:33)
at io.reactivex.h.a(Observable.java:11442)
at io.reactivex.d.e.b.l$b.run(ObservableSubscribeOn.java:96)
at io.reactivex.a.b.b$b.run(HandlerScheduler.java:109)
at android.os.Handler.handleCallback(Handler.java:754)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:165)
at android.app.ActivityThread.main(ActivityThread.java:6375)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802)
Screen Image
In MoviesFragment.java inside observer of ArrayList<MoviesItems> onChanged() method call moviesAdapter.notifyDataSetChanged(); after the moviesAdapter.setData(moviesItems);
On response of your API, you aren't setting up newly received value in LiveData variable.
So make below changes and your code will work.
void setMovies(){
AsyncHttpClient client = new AsyncHttpClient();
final ArrayList<MoviesItems> listItems = new ArrayList<>();
String url = "https://api.themoviedb.org/3/discover/movie?api_key=" + API_KEY + "&language=en-US";
client.get(url, new AsyncHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
try {
String result = new String(responseBody);
JSONObject object = new JSONObject(result);
JSONArray list = object.getJSONArray("results");
for (int i = 0;1 < list.length(); i++){
JSONObject movies = list.getJSONObject(i);
MoviesItems moviesItems = new MoviesItems(movies);
listItems.add(moviesItems);
}
// Replace below line.
// listMovies.getValue();
// With
listMovies.setValue(listItems);
}catch (Exception e){
Log.d("Exception", e.getMessage());
}
}
#Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
Log.d("onFailure", error.getMessage());
}
});
}
UPDATE 2:
Change position of code as below in fragment.
viewModel = ViewModelProviders.of(this).get(Model.class);
//pb = rootView.findViewById(R.id.pb);
moviesAdapter = new MoviesAdapter(getActivity());
moviesAdapter.notifyDataSetChanged();
rv_grid_movies = rootView.findViewById(R.id.rv_grid_movies);
RecyclerView.LayoutManager manager = new GridLayoutManager(getActivity(), 2);
rv_grid_movies.setLayoutManager(manager);
rv_grid_movies.addItemDecoration(new GridSpacingItemDecoration(2, dpToPx(3), true));
rv_grid_movies.setItemAnimator(new DefaultItemAnimator());
rv_grid_movies.setAdapter(moviesAdapter);
rv_grid_movies.setHasFixedSize(true);
// Add observer here, after initialising adapter and recyclerview.
viewModel.getMovies().observe(this, getMovie);
I am new to retrofit 2 and i am trying to get json array data but getting null, this is the url for getting the data.
But the funny thing is when i try to debug inside onResponse i am getting success message as well as response.body data. What is the problem here?
https://xenzet.com/GameCheat/viewgamesjson.php
this is json data
[
{
"gameid":"2",
"gameIcon":"https:\/\/xenzet.com\/GameCheat\/uploads\/counter strike 1.6.png",
"Games_Name":"1"
},
{
"gameid":"3",
"gameIcon":"https:\/\/xenzet.com\/GameCheat\/uploads\/gta.ico",
"Games_Name":"vice city sucjlfsdrgefdsrhag"
},
{
"gameid":"4",
"gameIcon":"https:\/\/xenzet.com\/GameCheat\/uploads\/pubg.png",
"Games_Name":"pubg"
},
{
"gameid":"5",
"gameIcon":"https:\/\/xenzet.com\/GameCheat\/uploads\/doom.png",
"Games_Name":"Doom Enternal"
},
{
"gameid":"6",
"gameIcon":"https:\/\/xenzet.com\/GameCheat\/uploads\/for.png",
"Games_Name":"Fornite"
},
{
"gameid":"9",
"gameIcon":"https:\/\/xenzet.com\/GameCheat\/uploads\/dota2.png",
"Games_Name":"dota2"
}
]
this is the method which is trying to get data
public void fetch_information() {
ApiInterface = ApiClient.getApiClient().create(Api.class);
Call<List<Games>> call = ApiInterface.GetGames();
call.enqueue(new Callback<List<Games>>() {
#Override
public void onResponse(Call<List<Games>> call, Response<List<Games>> response) {
if(response.isSuccessful()) {
gameslist = response.body();
gamescounter = gameslist.size();
adapter = new GameRecyclerViewAdapter(GamesActivity.this, gameslist);
recyclerView.setAdapter(adapter);
}
}
#Override
public void onFailure(Call<List<Games>> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
this is ApiClient
public class ApiClient {
public static String Base_URL ;
public static Retrofit retrofit;
public static Retrofit getApiClient()
{
if (retrofit == null)
{
Base_URL ="https://xenzet.com/GameCheat/";
retrofit = new Retrofit.Builder().baseUrl(Base_URL)
.addConverterFactory(GsonConverterFactory.create()).build();
}
return retrofit;
}
}
and Api
public interface Api {
#GET("viewgamesjson.php")
Call<List<Games>> GetGames();
}
and in OnCreate i am calling fetch information method.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_games);
gameslist = new ArrayList<Games>();
RecyclerView recyclerView = findViewById(R.id.recyclerview_gameslist);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
fetch_information();
Toast.makeText(getApplicationContext(),"" +gamescounter, Toast.LENGTH_SHORT).show();
adapter = new GameRecyclerViewAdapter(this, gameslist);
recyclerView.setAdapter(adapter);
adapter.setClickListener((GameRecyclerViewAdapter.ItemClickListener) this);
}
trying to fill data of game list in recycler view but fails as it null.
this is logcat
2019-05-27 14:03:43.261 1261-1261/com.example.quizgames E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.quizgames, PID: 1261
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setAdapter(android.support.v7.widget.RecyclerView$Adapter)' on a null object reference
at com.example.quizgames.GamesActivity$1.onResponse(GamesActivity.java:109)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:70)
at android.os.Handler.handleCallback(Handler.java:836)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6251)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
This is class Games
public class Games {
#SerializedName("gameid")
#Expose
private String gameid;
#SerializedName("gameIcon")
#Expose
private String gameIcon;
#SerializedName("Games_Name")
#Expose
private String gamesName;
public String getGameid() {
return gameid;
}
public void setGameid(String gameid) {
this.gameid = gameid;
}
public String getGameIcon() {
return gameIcon;
}
public void setGameIcon(String gameIcon) {
this.gameIcon = gameIcon;
}
public String getGamesName() {
return gamesName;
}
public void setGamesName(String gamesName) {
this.gamesName = gamesName;
}
// public Games(String Gameid,String Gameicon,String GameName)
// {
// this.gameid = Gameid;
// this.gameIcon = Gameicon;
// this.gamesName = GameName;
//
// }
}
This is recycler view
class GameRecyclerViewAdapter extends RecyclerView.Adapter<GameRecyclerViewAdapter.ViewHolder> {
private List<Games> mGames;
private LayoutInflater mInflater;
private ItemClickListener mClickListener;
// data is passed into the constructor
GameRecyclerViewAdapter(Context context, List<Games> games) {
this.mInflater = LayoutInflater.from(context);
this.mGames = games;
}
// inflates the row layout from xml when needed
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.gameitem, parent, false);
return new ViewHolder(view);
}
// binds the data to the TextView in each row
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Games Game = mGames.get(position);
String Gameid = Game.getGameid();
String Gameicon = Game.getGameIcon();
String Gamename = Game.getGamesName();
holder.GameNameTxt.setText(Gamename);
Glide.with(holder.GameIconImage.getContext()).load(Game.getGameIcon()).thumbnail(0.1f).
placeholder(R.color.colorPrimary).diskCacheStrategy(DiskCacheStrategy.NONE).into(holder.GameIconImage);
}
// total number of rows
#Override
public int getItemCount() {
return mGames == null ? 0 : mGames.size();
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView GameNameTxt;
ImageView GameIconImage;
ViewHolder(View itemView) {
super(itemView);
GameNameTxt = itemView.findViewById(R.id.gamename);
GameIconImage = itemView.findViewById(R.id.imageView);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
}
}
// allows clicks events to be caught
void setClickListener(ItemClickListener itemClickListener) {
this.mClickListener = itemClickListener;
}
// parent activity will implement this method to respond to click events
public interface ItemClickListener {
void onItemClick(View view, int position);
}
}
Add data in your Adapter in side onResponse Method
add fetch_information() in oncreate
#Override
public void onResponse(Call<List<Games>> call, Response<List<Games>> response) {
if(response.isSuccessful()) {
gameslist = response.body();
adapter = new GameRecyclerViewAdapter(MainActivity.this, gameslist);
//change your Activity name here insted of MainActivity
recyclerView.setAdapter(adapter);
}
}
I didn't check where you make mistake. But this code implementation returning me list having 10 data inside list.
public interface APIInterface {
#GET()
Call<List<ViewGame>> viewgamesjson(#Url String url);
}
This is model class:
public class ViewGame {
String gameid,gameIcon,Games_Name;
public String getGameid() {
return gameid;
}
public void setGameid(String gameid) {
this.gameid = gameid;
}
public String getGameIcon() {
return gameIcon;
}
public void setGameIcon(String gameIcon) {
this.gameIcon = gameIcon;
}
public String getGames_Name() {
return Games_Name;
}
public void setGames_Name(String games_Name) {
Games_Name = games_Name;
}
}
This is APiClient Class:
public class APIClient {
static Retrofit retrofit = null;
public static String Base_URL = "https://xenzet.com/GameCheat/";
public static APIInterface getInterface() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.addInterceptor(interceptor)
.build();
retrofit = new Retrofit.Builder()
.baseUrl(Base_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
return retrofit.create(APIInterface.class);
}
}
And this is API Call:
private void viewGame() {
Call<List<ViewGame>> call = APIClient.getInterface().viewgamesjson("https://xenzet.com/GameCheat/viewgamesjson.php");
call.enqueue(new Callback<List<ViewGame>>() {
#Override
public void onResponse(Call<List<ViewGame>> call, Response<List<ViewGame>> response) {
try {
Global.dismissProgress();
if (response.isSuccessful() && response.body() != null) {
Global.dismissProgress();
Global.printLog("size===", response.body().size() + "");
} else {
Global.dismissProgress();
}
} catch (Exception e) {
e.printStackTrace();
Global.dismissProgress();
}
}
#Override
public void onFailure(Call<List<ViewGame>> call, Throwable t) {
Global.dismissProgress();
try {
Global.showToast(SplashActivity.this, getString(R.string.something_wrong));
} catch (Exception e) {
e.printStackTrace();
}
call.cancel();
t.printStackTrace();
}
});
}
The problem is, that you set up your list adapter in onCreate(), where gameslist is still null.
adapter = new GameRecyclerViewAdapter(this, gameslist);
recyclerView.setAdapter(adapter);
When you call the setAdapter() method, the recyclerView will ask the adapter for the number of items; and in getItemCount() I suppose, you have something like return gameslist.count(). Since gameslist is still null, this causes the NPE.
To fix it, change getItemCount() to something like this:
return gameslist == null ? 0 : gameslist.size()
EDIT
I checked your URL (with Postman), and it appears that the content-type of the response is text/html and not application/json as it should be. I suppose that therefore the response isn't converted using Gson and thus you end up with null.
I have three classes, my adapter class, Voting class, and an acitivty where my JSONrequest is as shown below.The problem is as you can see that I call my JSONrequest in my activity which will get a list of views, inside that view I have a mVote textview. In my adapter you can also see I have a likeButton when someone presses that I would like mVotes to change from 0 to 1. I get all my data from a server so I am assuming I would need to make a new request, do I need to make a new adapter to? and JSON parseing method? How do I do this?!??!
public class AdapterQuestion extends RecyclerView.Adapter<AdapterQuestion.ViewQuestion>{
private LayoutInflater mLayoutInflater;
private ArrayList<QuestionData> data =new ArrayList<>();
public AdapterQuestion(Context context){
//get from context
mLayoutInflater=LayoutInflater.from(context);
}
public void setBloglist(ArrayList<QuestionData> data){
this.data =data;
notifyItemRangeChanged(0, this.data.size());
}
#Override
public ViewQuestion onCreateViewHolder(ViewGroup parent, int viewType){
ViewQuestion holder=new ViewQuestion(view);
return holder;
}
#Override
public void onBindViewHolder(ViewQuestion holder, int position) {
holder.answerText.setText(currentObj.getMtext());
holder.answerId.setText(currentObj.getId());
holder.mVotes.setText(currentObj.getVotes());
holder.mLikeButton.setTag(currentObj);
}
#Override
public int getItemCount() {
return data.size();
}
public class ViewQuestion extends RecyclerView.ViewHolder{
private TextView answerText;
private TextView answerId;
private TextView mVotes;
private LikeButton mLikeButton;
public ViewQuestion (View itemView){
super(itemView);
answerText=(TextView)itemView.findViewById(R.id.answerText);
answerId=(TextView)itemView.findViewById(R.id.answerId);
mVotes=(TextView)itemView.findViewById(R.id.VoteTextView);
mLikeButton= (LikeButton)itemView.findViewById(R.id.heart_buttons);
mLikeButton.setOnLikeListener(new OnLikeListener() {
#Override
public void liked(LikeButton likeButton) {
Voting vote = new Voting();
vote.onUpVote(answerId());
System.out.print("Adapter Position"+getAdapterPosition());
}
#Override
public void unLiked(LikeButton likeButton) {
Voting onDown=new Voting();
onDown.onDownVote(answerId());
}
});
}
public String getVoteView(){
String voteView=mVotes.getText().toString();
return voteView;
}
public String answerId(){
String converted=answerId.getText().toString();
return converted;
}
public int convertToInt(){
String converted=answerId.getText().toString();
int ConvertedInt=Integer.parseInt(converted);
return ConvertedInt;
}
}
}
Voting
public class Voting {
private VolleySingleton mVolleySingleton;
private RequestQueue mRequestQueue;
private AdapterVoteUpdate mAdapterVotes;
private ArrayList<QuestionData> updateVotes = new ArrayList<>();
public void onUpVote(final String answerId) {
final RequestQueue mrequestQueue = VolleySingleton.getInstance().getRequestQueue();
final String PUT_VOTE_UP = "url" + answerId + "url\n";
StringRequest PostVoteUp = new StringRequest(Request.Method.PUT, PUT_VOTE_UP, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
mrequestQueue.add(PostVoteUp);
}
public void onDownVote(final String answerId) {
System.out.println("Voted Down");
final RequestQueue mrequestQueue = VolleySingleton.getInstance().getRequestQueue();
final String PUT_VOTE_DOWN = "url" + answerId + "urul";
StringRequest PostVoteUp = new StringRequest(Request.Method.PUT, PUT_VOTE_DOWN, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
System.out.println("************Answer" + error + "error");
}
});
mrequestQueue.add(PostVoteUp);
}
JSON RequestClass
public void JsonRequestMethod(String Id) {
mVolleySingleton = VolleySingleton.getInstance();
mRequestQueue = mVolleySingleton.getRequestQueue();
final String URL_ANSWER = "url" + Id + "url";
JsonArrayRequest request = new JsonArrayRequest(Request.Method.GET, URL_ANSWER, (String) null, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
mListblogs.clear();
mListblogs = parseJSONResponseQuestion(response);
mAdapterQuestion.setBloglist(mListblogs);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
System.out.println(error);
}
});
mRequestQueue.add(request);
}
private ArrayList<QuestionData> parseJSONResponseQuestion(JSONArray response) {
if (!response.equals("")) {
ArrayList<QuestionData> questionDataArrayList = new ArrayList<>();
try {
StringBuilder data = new StringBuilder();
for (int i = 0; i < response.length(); i++) {
JSONObject currentQuestions = response.getJSONObject(i);
String text = currentQuestions.getString("text");
String questionId = currentQuestions.getString("questionId");
String votes = currentQuestions.getString("votes");
System.out.println(votes+" VOTES");
int voteInt=Integer.parseInt(votes);
System.out.println(voteInt);
String Answerid = currentQuestions.getString("id");
String selectedId = currentQuestions.getString("selected");
System.out.println(response.length() + "length");
data.append(text + Answerid + "\n");
System.out.println(data);
QuestionData questionData = new QuestionData();
questionData.setMtext(text);
questionData.setVotes(votes);
questionData.setId(Answerid);
questionData.setSelected(selectedId);
mListblogs.add(questionData);
}
System.out.println(data.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
return mListblogs;
}
"I get all my data from a server so I am assuming I would need to make a new request."
-> Actually you don't need to re-request the data from your server again. You just need to update
private ArrayList<QuestionData> data =new ArrayList<>();
on your AdapterQuestion then call AdapterQuestion.notifyDataSetChanged(); after you get a success response from onUpVote or onDownVote
"Do I need to make a new adapter to? and JSON parseing method? How do I do this?!??!"
-> No need
To change a particular ItemView in your recyclerview use this below code.
notifyItemChanged(index);
If you want to change the particular Textview in onItemclick you have to get the item position.
#Override
public void onBindViewHolder(ViewQuestion holder, int position) {
holder.answerText.setText(currentObj.getMtext());
holder.answerId.setText(currentObj.getId());
holder.mVotes.setText(currentObj.getVotes());
holder.mVotes.setTag(currentObj);
holder.mLikeButton.setTag(holder);
}
In your like button click event change the code like the below
mLikeButton.setOnLikeListener(new OnLikeListener() {
#Override
public void liked(LikeButton likeButton) {
Voting vote = new Voting();
vote.onUpVote(answerId());
final ViewQuestion holder=(ViewQuestionholder)likeButton.getTag();
currentObj co=(currentObj)holder.mVotes.getTag();
holder.mVotes.setText("16");
System.out.print("Adapter Position"+getAdapterPosition());
}
#Override
public void unLiked(LikeButton likeButton) {
Voting onDown=new Voting();
onDown.onDownVote(answerId());
final ViewQuestion holder=(ViewQuestionholder)likeButton.getTag();
currentObj co=(currentObj)holder.mVotes.getTag();
holder.mVotes.setText("14");
}
});