I am creating fragments inside Android Studio where one of my fragments calls an API and displays the listview with a custom listadapter. However, I have read many similar examples but none can determine why my listview is not appearing.
This is my News Fragment:
package com.example.firebasetestapplication;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.TextView;
import com.example.firebasetestapplication.databinding.FragmentNewsBinding;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
/**
* A simple {#link Fragment} subclass.
* Use the {#link NewsFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class NewsFragment 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";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private Handler mHandler = new Handler(Looper.getMainLooper());
ArrayList<News> newsArrayList = new ArrayList<>();
// FragmentNewsBinding binding;
// Context thiscontext;
public NewsFragment() {
// 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 NewsFragment.
*/
// TODO: Rename and change types and number of parameters
public static NewsFragment newInstance(String param1, String param2) {
NewsFragment fragment = new NewsFragment();
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) {
View v = inflater.inflate(R.layout.fragment_news,container,false);
TextView textview = v.findViewById(R.id.textview);
ListView listview = v.findViewById(R.id.listview);
// thiscontext = container.getContext();
textview.setText("");
// textView.setText("Trying for the first time");
// Inflate the layout for this fragment
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://api.jsonbin.io/v3/b/636b51910e6a79321e444107")
.get()
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(#NonNull Call call, #NonNull IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(#NonNull Call call, #NonNull Response response) throws IOException {
if(response.isSuccessful()) {
String myResponse = response.body().string();
try {
JSONObject jsonObject = new JSONObject(myResponse);
JSONObject record = jsonObject.getJSONObject("record");
JSONArray club_news = record.getJSONArray("Club_News");
Gson gson = new Gson();
Type listType = new TypeToken<ArrayList<News>>(){}.getType();
List<News> total_News = gson.fromJson(club_news.toString(),listType);
for(News news : total_News) {
textview.append("Club: " + news.club + " " + news.description + "\n");
newsArrayList.add(news);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
});
ListAdapter listAdapter = new ListAdapter(getActivity(),newsArrayList);
listview.setAdapter(listAdapter); // line that breaks program
// mHandler.post(new Runnable() {
// #Override
// public void run() {
// ListAdapter listAdapter = new ListAdapter(getActivity(),newsArrayList);
// listview.setAdapter(listAdapter); // line that breaks program
// }
// });
// getActivity().runOnUiThread(new Runnable() {
// #Override
// public void run() {
// ListAdapter listAdapter = new ListAdapter(getActivity(),newsArrayList);
// listview.setAdapter(listAdapter); // line that breaks program
// }
// });
return v;
}
}
The OkHttpRequest successfully gets all the data and organized with Gson. This is my ListAdapter:
package com.example.firebasetestapplication;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.ArrayList;
public class ListAdapter extends ArrayAdapter<News> {
public ListAdapter(#NonNull Context context, ArrayList<News> newsArrayList) {
super(context,R.layout.custom_news_item,newsArrayList);
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View listItemView = convertView;
News news = getItem(position);
if(listItemView == null) {
listItemView = LayoutInflater.from(getContext()).inflate(R.layout.custom_news_item,parent,false);
}
ImageView club_logo = listItemView.findViewById(R.id.club_logo);
TextView club = listItemView.findViewById(R.id.club);
TextView club_description = listItemView.findViewById(R.id.club_description);
TextView title = listItemView.findViewById(R.id.title);
TextView description = listItemView.findViewById(R.id.description);
TextView time = listItemView.findViewById(R.id.time);
club_logo.setImageResource(R.drawable.frats_color); // Temporary
club.setText(news.getClub());
club_description.setText(news.getClub_description());
title.setText(news.getTitle());
description.setText(news.getDescription());
time.setText(news.getTime());
return listItemView;
}
}
And my News class Model:
package com.example.firebasetestapplication;
public class News {
String club;
String club_description;
String title;
String description;
String time;
public News(String club, String club_description, String title, String description, String time) {
this.club = club;
this.club_description = club_description;
this.title = title;
this.description = description;
this.time = time;
}
public String getClub() {return club;}
public String getClub_description() {return club_description;}
public String getTitle() {return title;}
public String getDescription() {return description;}
public String getTime() {return time;}
public void setClub(String club) {this.club = club;}
public void setClub_description(String club_description) {this.club_description = club_description;}
public void setTitle(String title) {this.title = title;}
public void setDescription(String description) {this.description = description;}
public void setTime(String time) {this.time = time;}
}
Finally, here is my custom_news item xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp">
<LinearLayout
android:id="#+id/first_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="3dp">
<ImageView
android:id="#+id/club_logo"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="#drawable/frats_color"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:orientation="vertical">
<TextView
android:id="#+id/club"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:textSize="20sp"
android:textColor="#color/black"
android:textStyle="bold"
android:text="Frater Sodalis" />
<TextView
android:id="#+id/club_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Social Club at Abilene Christian University"
android:textStyle="italic"/>
</LinearLayout>
</LinearLayout>
<TextView
android:id="#+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:padding="15dp"
android:text="8:15pm" />
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/first_layout"
android:layout_marginTop="0dp"
android:layout_marginStart="10dp"
android:textSize="15sp"
android:textColor="#color/black"
android:textStyle="bold"
android:text="Haunted Forrest is now open! 6869 E North " />
<TextView
android:id="#+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/title"
android:layout_marginTop="10dp"
android:layout_marginStart="10dp"
android:layout_marginBottom="10dp"
android:textSize="15sp"
android:text="#string/HF_Example"/>
</RelativeLayout>
</LinearLayout>
and my fragment_news xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".NewsFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:id="#+id/textview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textStyle="bold"
android:text="News Fragment" />
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/listview"
tools:listitem="#layout/custom_news_item" />
</FrameLayout>
I know if looks like a lot, but I am pretty sure that the error lies around the ListAdapter or the News Fragment. I was looking into whether the getActivity() was passing the correct context for the Fragment or whether my listview.setAdapter(listAdapter); needs a RunOnUiThread somehow in a fragment.
I would very much appreciate it if someone could give me a hint on what's missing for my listview. I know I am pretty close. Thank you so much!
Just in case you are wondering, the Main Activity looks like this:
package com.example.firebasetestapplication;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.text.format.DateFormat;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.example.firebasetestapplication.databinding.ActivityMainBinding;
import com.firebase.ui.database.FirebaseListAdapter;
import com.firebase.ui.database.FirebaseListOptions;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
public class MainActivity extends AppCompatActivity {
private TextView greetings;
private Button logout;
//Firebase
FirebaseAuth mAuth = FirebaseAuth.getInstance();
private FirebaseListAdapter<ChatMessage> adapter;
private FirebaseUser user;
private FirebaseUser currentUser;
private DatabaseReference reference;
// Binding
ActivityMainBinding binding;
//Assets
private FloatingActionButton fab;
private String userID;
#SuppressLint("MissingInflatedId")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
replaceFragment(new HomeFragment());
//
binding.bottomNavigationView.setOnItemSelectedListener(item -> {
switch (item.getItemId()) {
case R.id.home:
replaceFragment(new HomeFragment());
case R.id.profile:
break;
case R.id.settings:
break;
case R.id.news:
// startActivity(new Intent(MainActivity.this, NewsActivity.class));
replaceFragment(new NewsFragment());
}
return true;
});
logout = findViewById(R.id.signOut);
// greetings = findViewById(R.id.greeting);
currentUser = mAuth.getCurrentUser();
// fab = findViewById(R.id.fab);
//
// fab.setOnClickListener(new View.OnClickListener() {
// #Override
// public void onClick(View view) {
// EditText input = findViewById(R.id.input);
// FirebaseDatabase.getInstance()
// .getReference()
// .push()
// .setValue(new ChatMessage(input.getText().toString(),
// FirebaseAuth.getInstance()
// .getCurrentUser()
// .getDisplayName())
// );
//
// // Clear the input
// input.setText("");
// }
// });
logout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FirebaseAuth.getInstance().signOut();
startActivity(new Intent(MainActivity.this, LoginActivity.class));
}
});
if (currentUser == null)
{
Intent intent
= new Intent(MainActivity.this,
LoginActivity.class);
startActivity(intent);
}
else
{
// displayChatMessages();
user = FirebaseAuth.getInstance().getCurrentUser();
reference = FirebaseDatabase.getInstance().getReference("Users");
userID = user.getUid();
reference.child(userID).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
User userChat = snapshot.getValue(User.class);
if(userChat != null) {
String fullname = userChat.fullName;
String email = userChat.email;
String age = userChat.age;
// greetings.setText("Welcome, " + fullname + "!");
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Toast.makeText(MainActivity.this, "Something did not go right!", Toast.LENGTH_SHORT).show();
}
});
}
}
private void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, fragment);
fragmentTransaction.commit();
}
}
Related
please help me to find out where is the trouble in my code, i tried to set onclick listener to delete the item from the database, howerver i does nothing, i checked the code again and again but i didn't find out where in the code that cause the problem.
please help me
thanks
The layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
android:padding="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_toLeftOf="#id/btn_delete">
<TextView
android:id="#+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Title"
android:textColor="#color/white"
android:textSize="20sp"
android:gravity="center"
android:padding="8dp"
/>
<TextView
android:id="#+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Content"
android:textSize="20sp"
android:gravity="start"
android:padding="10dp"
android:textColor="#color/white" />
</LinearLayout>
<Button
android:id="#+id/btn_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="delete"
android:backgroundTint="#color/transparent"
android:textColor="#color/white"
android:layout_alignParentEnd="true"
android:layout_marginEnd="40dp"
android:layout_alignParentRight="true"/>
</RelativeLayout>
the adapter
package com.haki.mysimplehakidiarynotes.adapters;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.haki.mysimplehakidiarynotes.InterfaceDeleteListener;
import com.haki.mysimplehakidiarynotes.objects.ItemsObject;
import com.haki.mysimplehakidiarynotes.R;
import java.util.ArrayList;
public class ItemsAdapter extends RecyclerView.Adapter<ItemsAdapter.ItemViewHolder>{
private Context mContext;
private ArrayList<ItemsObject> arrayList;
private InterfaceDeleteListener deleteListener;
public ItemsAdapter(Context mContext, InterfaceDeleteListener deleteListener) {
this.mContext = mContext;
this.deleteListener = deleteListener;
}
public void setData(ArrayList<ItemsObject> arrayList){
this.arrayList = arrayList;
notifyDataSetChanged();
}
#NonNull
#Override
public ItemViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).
inflate(R.layout.layout_items, parent, false);
return new ItemViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ItemViewHolder holder, int position) {
ItemsObject object =arrayList.get(position);
if (object==null){
return;
}
holder.txtTitle.setText(object.getTitle());
holder.txtContent.setText(object.getContent());
holder.btn_delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
deleteListener.onClickDeleteListen(object);
}
});
}
#Override
public int getItemCount() {
if (arrayList!=null){
return arrayList.size();
}
return 0;
}
public class ItemViewHolder extends RecyclerView.ViewHolder {
private TextView txtTitle;
private TextView txtContent;
private Button btn_delete;
public ItemViewHolder(#NonNull View itemView) {
super(itemView);
txtTitle =itemView.findViewById(R.id.tv_title);
txtContent =itemView.findViewById(R.id.tv_content);
btn_delete = itemView.findViewById(R.id.btn_delete);
}
}
}
the main
package com.haki.mysimplehakidiarynotes.fragments.diary_tabs;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.haki.mysimplehakidiarynotes.InterfaceDeleteListener;
import com.haki.mysimplehakidiarynotes.adapters.ItemsAdapter;
import com.haki.mysimplehakidiarynotes.databases.DiaryDatabase;
import com.haki.mysimplehakidiarynotes.objects.ItemsObject;
import com.haki.mysimplehakidiarynotes.R;
import java.util.ArrayList;
public class DiaryLogFragment extends Fragment implements InterfaceDeleteListener {
private RecyclerView recyclerView;
private ArrayList<ItemsObject> arrayList = new ArrayList<>();
private ItemsAdapter adapter;
public DiaryLogFragment() {
}
public static DiaryLogFragment newInstance() {
DiaryLogFragment fragment = new DiaryLogFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_diary_log, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
recyclerView = view.findViewById(R.id.rcv_items);
//arrayList.add(new ItemsObject("thử nghiệm","nội dung thử nghiệm"));
arrayList = (ArrayList<ItemsObject>) DiaryDatabase.getInstance(getActivity()).userDAO().getAllData();
adapter = new ItemsAdapter(getActivity(), this::onClickDeleteListen);
adapter.setData(arrayList);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity()
,LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(adapter);
}
#Override
public void onResume() {
super.onResume();
arrayList = (ArrayList<ItemsObject>) DiaryDatabase.getInstance(getActivity()).userDAO().getAllData();
adapter.setData(arrayList);
}
#Override
public void onClickDeleteListen(ItemsObject object) {
DiaryDatabase.getInstance(getActivity()).userDAO().delete(object);
arrayList = (ArrayList<ItemsObject>) DiaryDatabase.getInstance(getActivity()).userDAO().getAllData();
adapter.setData(arrayList);
}
}
the interface
package com.haki.mysimplehakidiarynotes;
import com.haki.mysimplehakidiarynotes.objects.ItemsObject;
public interface InterfaceDeleteListener {
void onClickDeleteListen(ItemsObject object);
}
the Dao
package com.haki.mysimplehakidiarynotes.databases;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import com.haki.mysimplehakidiarynotes.objects.ItemsObject;
import java.util.List;
#Dao
public interface DiaryDAO {
//Bước 1. Tạo insert vào cơ sở dữ liệu
#Insert
void insert(ItemsObject itemsObject);
#Query("SELECT * FROM user order by id DESC")
List<ItemsObject> getAllData();
#Delete
void delete(ItemsObject object);
}
i checked the code many times, however i didn't findout where is the cause that doen'st delete the item from the database
Im trying to use a searchview to create a search bar in a simple map application, however i get the next error:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.SearchView.setOnQueryTextListener(android.widget.SearchView$OnQueryTextListener)' on a null object reference
This is my code:
MapsActivity:
package com.example.actividad13mapactivity;
import androidx.fragment.app.FragmentActivity;
import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import android.widget.SearchView;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.example.actividad13mapactivity.databinding.ActivityMapsBinding;
import java.io.IOException;
import java.util.List;
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private GoogleMap mMap;
private ActivityMapsBinding binding;
SupportMapFragment mapFragment;
SearchView searchView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
searchView = findViewById(R.id.sv_location);
mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
String location = searchView.getQuery().toString();
List <Address> adressList = null;
if (location != null || !location.equals("")){
Geocoder geocoder = new Geocoder(MapsActivity.this);
try {
adressList = geocoder.getFromLocationName(location,1);
}catch (IOException e){
e.printStackTrace();
}
Address address = adressList.get(0);
LatLng latLng = new LatLng(address.getLatitude(),address.getLongitude());
mMap.addMarker(new MarkerOptions().position(latLng).title(location));
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng,10));
}
return false;
}
#Override
public boolean onQueryTextChange(String query) {
return false;
}
});
binding = ActivityMapsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// Add a marker in Sydney and move the camera
LatLng sydney = new LatLng(-34, 151);
mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
}
}
Layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MapsActivity">
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<SearchView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/sv_location"
android:queryHint="Search..."
android:iconifiedByDefault="false"
android:layout_margin="100dp"
android:elevation="5dp"
android:background="#drawable/bg_round"/>
</RelativeLayout>
Hi I'm working on a small application which sets a countdown. Now I want this countdown to be seen in front of a background inside a recyclerview. So in the end a user will have set multiple countdown timers and these will be displayed with backgrounds inside a recyclerview.
What I have made right now is far from perfect, but it's in the right direction of what I want it to be. The only problem I have right now is, because I'm working with a recyclerview, the view (including the text with the countdown) will be recycled. So if I scroll down, the countdown will be reset. I think that's the problem I'm having but I have no clue how to solve it. This is the most important code:
The activity the recyclerview is in:
package anotherChallenge.example.criminalactivity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.widget.DatePicker;
import com.example.criminalactivity.R;
import java.text.DateFormat;
import java.util.Calendar;
public class Overview extends AppCompatActivity {
private int[] allImages = {
R.drawable.festive1_pictures,
R.drawable.festive2_pictures,
R.drawable.festive3_pictures,
R.drawable.festive4_pictures,
R.drawable.festive5_pictures,
R.drawable.ferrari_materialistic_pictures,
R.drawable.house_materialistic_pictures,
R.drawable.boat_materialistic_pictures,
R.drawable.rolex_materialistic_pictures,
R.drawable.private_jet_materialistic_pictures,
R.drawable.holiday1_pictures,
R.drawable.holiday2_pictures,
R.drawable.holiday3_pictures,
R.drawable.holiday4_pictures,
R.drawable.holiday5_pictures,
R.drawable.meet1_pictures,
R.drawable.meet2_pictures,
R.drawable.meet3_pictures,
R.drawable.meet4_pictures,
R.drawable.meet5_pictures,
R.drawable.other1_pictures,
R.drawable.other2_pictures,
R.drawable.other3_pictures,
R.drawable.other4_pictures,
R.drawable.other5_pictures,
};
private RecyclerView recyclerView2;
private DatePicker datePicker;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_overview);
// textClock.setFormat12Hour(null);
// textClock.setFormat24Hour("EEE/MMM d/yyyy hh:mm:ss");
recyclerView2 = findViewById(R.id.recyclerview2);
datePicker = findViewById(R.id.datepicker);
Calendar calendar = Calendar.getInstance();
String currentDate = DateFormat.getDateInstance(DateFormat.FULL).format(calendar.getTime());
System.out.println(currentDate);
// String filledInDate = datePicker.getDayOfMonth() + "/" + datePicker.getMonth() + "/"+
// datePicker.getYear();
adapterForOverview adapter = new adapterForOverview(this, allImages);
recyclerView2.setAdapter(adapter);
recyclerView2.setLayoutManager(new LinearLayoutManager(this));
}
}
Adapter for the recyclerview:
package anotherChallenge.example.criminalactivity;
import android.content.Context;
import android.os.CountDownTimer;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.RecyclerView;
import com.example.criminalactivity.R;
public class adapterForOverview extends RecyclerView.Adapter<adapterForOverview.MyViewHolder> {
AddItem addItem;
int[] images;
Context context;
CustomAdapterCardView customAdapterCardView;
public adapterForOverview(Context context, int[] images) {
this.context=context;
this.images=images;
addItem = new AddItem();
// customAdapterCardView = new CustomAdapterCardView(context,
customAdapterCardView.getArrayList());
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
// holder.cardView.setCardBackgroundColor(Color.parseColor("#696969"));
new CountDownTimer(30000,1000) {
#Override
public void onTick(long millisUntilFinished) {
holder.myTextview.setText("The title will be here \n" + millisUntilFinished/1000);
}
#Override
public void onFinish() {
holder.myTextview.setText("Achieved!");
}
}.start();
holder.myImage.setImageResource(images[position]);
// holder.myImage.setImageDrawable(addItem.getDrawable());
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(context);
View view = layoutInflater.inflate(R.layout.itemsinoverview,parent,false);
return new MyViewHolder(view);
}
#Override
public int getItemCount() {
return images.length;
}
public class MyViewHolder extends RecyclerView.ViewHolder{
CardView cardView;
ImageView myImage;
TextView myTextview;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
cardView = itemView.findViewById(R.id.cardview2);
myImage = itemView.findViewById(R.id.imageView);
myTextview = itemView.findViewById(R.id.textviewOfCountdown);
}
}
}
XML Code of the item inside the recyclerview:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
<androidx.cardview.widget.CardView
android:id="#+id/cardview2"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginHorizontal="8dp"
android:layout_marginVertical="4dp"
>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/constraintlayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/imageView"
android:scaleType="fitXY"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="#+id/textviewOfCountdown"
android:layout_width="match_parent"
android:layout_height="100dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="25sp"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
Explanation:
As you know android's recyclerView recycles its views and reuses its viewHolders by calling onBind each time to update the item's data. I noticed that in onBindViewHolder
you create a CountDownTimer every time any data is bound, so you end up with multiple timers updating the same ViewHolder.
Bad solution:
One solution would be to make the adapter's items non-recyclable, but that wouldn't be optimal and negates the recycling ability of the recyclerview.
Good Solution:
The solution is to keep a reference to your timer inside your viewHolder called MyViewHolder. Then in onBindViewHolder check if the timer has already been instantiated. If yes, then cancel the previous timer and afterwards create again a new timer. If not, then there's no need to cancel anything you just proceed to the creation of a new timer object for the first time.
public void onBindViewHolder(#NonNull MyViewHolder holder, final int position) {
if (holder.timer != null) {
holder.timer.cancel();
}
holder.timer = new CountDownTimer(30000, 1000) {
...
}.start();
}
public static class MyViewHolder extends RecyclerView.ViewHolder {
...
CountDownTimer timer;
...
}
The problem is that you're creating a new timer every time a new view is bound. You want to keep the data the adapterr is going to display separate from the view that will display it. In this case, you could manage the countdown timer in an object that represents each item in the list. For example (pseudocode):
class MyItem {
val imageResource: Int
val timer: CountDownTimer
}
In the adapter, you hold a list of MyItem and instead of creating a brand new timer, you just set the current value of the existing timer (pseudocode):
public class adapterForOverview extends RecyclerView.Adapter<adapterForOverview.MyViewHolder> {
MyItem[] items;
Context context;
public adapterForOverview(Context context, MyItem[] items) {
this.context=context;
this.items=items;
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
timer = items[position].timer
if (timer.isFinished()) {
holder.myTextview.setText("The title will be here \n" + millisUntilFinished/1000);
} else {
holder.myTextview.setText("Achieved!");
}
}
#Override
public int getItemCount() {
return items.length;
}
Finally you would create the timer wherever you're currently initializing the images now. Instead of updating any views, the on tick and finished method just tell the adapter to refresh that specific item in the list, which will then rebind the current timer values (pseudocode):
for (int i = 0; i < allImages.length; i++) {
items[i] = new MyItem()
items[i].image = allImages[i]
items[i].timer = new CountDownTimer(30000,1000) {
#Override
public void onTick(long millisUntilFinished) {
adapter.notifyItemChanged(i)
}
#Override
public void onFinish() {
adapter.notifyItemChanged(i)
}
}.start();
}
Again, this is all pseudo code and won't compiler, but should give you an idea of how to structure your code to solve your problem.
I am using youtube API top import youtube channel in android app. I have created MainActivity, Adapter, Video Datails Class and another activity named youtubePlay activity. the xml for main activity consists of list view and another custom layout with text and image for list view items display obtained from json parsing (title, description, thumbnail). I have added youtube player view in the activity_play_youtube. but on clicking the video from list, the video is not displayed on the youtube player view.
the coding is as shown;
MainActivity.java
package com.currentmedia.channel;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ListView;
import android.widget.Toast;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import com.currentmedia.channel.Adapter.MyCustomAdapter;
import com.currentmedia.channel.Model.VideoDetails;
import static android.widget.Toast.*;
public class MainActivity extends AppCompatActivity {
//private static final String TAG = "Channel Activity";
String API_Key = "[]";
ListView listView;
ArrayList<VideoDetails> videoDetailsArrayList;
MyCustomAdapter myCustomAdapter;
String url="https://www.googleapis.com/youtube/v3/search?part=snippet&channelId=UCVMWWQ985A_-SESZUy_SsVQ&maxResults=50&key=[]";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
videoDetailsArrayList = new ArrayList<>();
myCustomAdapter = new MyCustomAdapter(MainActivity.this, videoDetailsArrayList);
displayVideos();
}
private void displayVideos ()
{
RequestQueue requestQueue= Volley.newRequestQueue(getApplicationContext());
StringRequest stringRequest=new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jsonObject = new JSONObject(response);
JSONArray jsonArray = jsonObject.getJSONArray("items");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject1 = jsonArray.getJSONObject(i);
if (jsonObject1.has("id")){
JSONObject jsonVideoId=jsonObject1.getJSONObject("id");
if (jsonVideoId.has("kind")){
if(jsonVideoId.getString("kind").equals("youtube#video")){
JSONObject jsonObjectSnippet = jsonObject1.getJSONObject("snippet");
JSONObject jsonObjectDefault=jsonObjectSnippet.getJSONObject("thumbnails").getJSONObject("medium");
String video_id=jsonVideoId.getString("videoId");
VideoDetails vd=new VideoDetails();
vd.setVideoId(video_id);
vd.setTitle(jsonObjectSnippet.getString("title"));
vd.setDescription(jsonObjectSnippet.getString("description"));
vd.setUrl(jsonObjectDefault.getString("url"));
videoDetailsArrayList.add(vd);
}
listView.setAdapter(myCustomAdapter);
myCustomAdapter.notifyDataSetChanged();
}
}
}
}catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getApplicationContext(),error.getMessage(), LENGTH_LONG).show();
}
});
requestQueue.add(stringRequest);
}
}
the adapter class named myCustomAdapter is following
package com.currentmedia.channel.Adapter;
import android.app.Activity;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.currentmedia.channel.R;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
import com.currentmedia.channel.Model.VideoDetails;
public class MyCustomAdapter extends BaseAdapter {
Activity activity;
ArrayList<VideoDetails> videoDetailsArrayList;
LayoutInflater inflater;
public MyCustomAdapter(Activity activity, ArrayList<VideoDetails> videoDetailsArrayList)
{
this.activity=activity;
this.videoDetailsArrayList=videoDetailsArrayList;
}
#Override
public Object getItem(int position) {
return this.videoDetailsArrayList.get(position);
}
#Override
public long getItemId(int position) {
return (long) position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(inflater==null)
{inflater=this.activity.getLayoutInflater();}
if(convertView == null)
{convertView=inflater.inflate(R.layout.custom_layout,null);}
ImageView imageView=(ImageView) convertView.findViewById(R.id.imageView);
TextView textView=(TextView) convertView.findViewById(R.id.mytitle);
LinearLayout linearLayout=(LinearLayout)convertView.findViewById(R.id.root);
final VideoDetails videoDetails=(VideoDetails) this.videoDetailsArrayList.get(position);
linearLayout.setOnClickListener (new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i=new Intent(activity, com.currentmedia.channel.VideoPlayActivity.class);
i.putExtra("videoId", videoDetails.getVideoId());
activity.startActivity(i);}
});
Picasso.get().load(videoDetails.getUrl()).into(imageView);
textView.setText(videoDetails.getTitle());
return convertView;
}
#Override
public int getCount() {
return this.videoDetailsArrayList.size();
}
}
videoPlayActivity.java
package com.currentmedia.channel;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import com.google.android.youtube.player.YouTubeBaseActivity;
import com.google.android.youtube.player.YouTubePlayerView;
public class VideoPlayActivity extends YouTubeBaseActivity {
YouTubePlayerView youTubePlayerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_play);
youTubePlayerView= (YouTubePlayerView) findViewById(R.id.youtube_player) ;
}
}
and the xml files are :
activity_video_play
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".VideoPlayActivity">
<com.google.android.youtube.player.YouTubePlayerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/youtube_player"></com.google.android.youtube.player.YouTubePlayerView>
</RelativeLayout>
while activity_main and custom_layout is as follows
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/listView"></ListView>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:orientation="horizontal"
android:id="#+id/root">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageView"
android:src="#mipmap/ic_launcher"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:id="#+id/mytitle"
android:text="welcome to my video"
android:textSize="16sp"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
can anybody explain where am I doing wrong?
In your videoPlayActivity.java
YouTubePlayerView youTubePlayerView;
YouTubePlayer.OnInitializedListener onInitializedListener;
String url = getIntent().getStringExtra("videoId");
youTubePlayerView = findViewById(R.id.youtube_player);
onInitializedListener = new YouTubePlayer.OnInitializedListener() {
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean b) {
youTubePlayer.loadVideo(url);
}
#Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {
}
};
youTubePlayerView.initialize("Api key", onInitializedListener);
To generate Api key https://developers.google.com/youtube/android/player/register
I have 2 spinners in my application.one(spinner 1) for selecting qualification and another(spinner2) is to show courses according to selected qualification in spinner 1.
how can I add items in spinner2 on the basis of item selected in spinner 1.
Try This Code:
Java Class
package com.example.spinnerexam;
import java.util.ArrayList;
import java.util.List;
import android.annotation.TargetApi;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class SpinnerExample extends Activity implements OnItemSelectedListener{
private Spinner qualificationSpinner, coursesSpinner;
ArrayAdapter<String> courseAdapter;
List<ArrayList<String>> allCoursesList;
CustomOnItemSelectedListener pCustomOnItemSelectedListener;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
qualificationSpinner = (Spinner) findViewById(R.id.spinner1);
coursesSpinner = (Spinner) findViewById(R.id.spinner2);
List<String> qualificationList = new ArrayList<String>();
qualificationList.add("B.tech");
qualificationList.add("M.tech");
qualificationList.add("MCA");
ArrayList<String> cources_Btech = new ArrayList<String>();
cources_Btech.add("Btechcourse1");
cources_Btech.add("Btechcourse2");
cources_Btech.add("Btechcourse3");
ArrayList<String> cources_Mtech = new ArrayList<String>();
cources_Mtech.add("Mtechcourse1");
cources_Mtech.add("Mtechcourse2");
cources_Mtech.add("Mtechcourse3");
ArrayList<String> cources_MCA = new ArrayList<String>();
cources_MCA.add("MCAcourse1");
cources_MCA.add("MCAcourse2");
cources_MCA.add("MCAcourse3");
allCoursesList = new ArrayList<ArrayList<String>>();
allCoursesList.add(cources_Btech);
allCoursesList.add(cources_Mtech);
allCoursesList.add(cources_MCA);
ArrayAdapter<String> qualificationAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, qualificationList);
qualificationAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
qualificationSpinner.setAdapter(qualificationAdapter);
courseAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
courseAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
coursesSpinner.setAdapter(courseAdapter);
addListenerOnSpinnerItemSelection();
}
// Add spinner data
public void addListenerOnSpinnerItemSelection(){
qualificationSpinner.setOnItemSelectedListener(this);
coursesSpinner.setOnItemSelectedListener(this);
}
#Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
courseAdapter.clear();
courseAdapter.addAll(allCoursesList.get(pos));
courseAdapter.notifyDataSetChanged();
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
}
}
XML layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Spinner
android:id="#+id/spinner1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:prompt="#string/spinner_prompt" />
<Spinner
android:id="#+id/spinner2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:prompt="#string/spinner_prompt" />
</LinearLayout>