I'm using Youtube API in my app, i'm trying to get a list of videos from Youtube, it's work fine, but it's limit to 48 videos in one list for some reason, when I'm trying to get more than 48 videos in one list, i'm getting 400 ERROR CODE, Here's my code:
public void Load(final Context context, int start, int end, int category, LoaderVideoListener listener) {
try {
mVideosNames.clear();
mVideos.clear();
mCategory = category;
mStart = start;
mEnd = end;
mListener = listener;
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference dataRef = database.getReference();
String child = "Category";
if (mCategory == 1) {
child = "category1";
} else if (mCategory == 2) {
child = "category2";
} else {
child += category;
}
dataRef.child(child).orderByChild("index").startAt(start).endAt(end).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
try {
StringBuilder videoIds = new StringBuilder();
for (DataSnapshot data : dataSnapshot.getChildren()) {
videoIds.append(data.child("YTId").getValue()).append(",");
}
Network net = new Network();
net.Request(context, URL_1 + videoIds + URL_2, new RequestJsonListiner() {
#Override
public void OnResponse(String json, boolean isError, String errorDetails) {
if (!isError) {
try {
ParseJsonToVideoYT(json);
} catch (JSONException e1) {
handleCallBack.obtainMessage(1, e1.getMessage()).sendToTarget();
}
} else
handleCallBack.obtainMessage(1, errorDetails).sendToTarget();
}
});
} catch (Exception e) {
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
handleCallBack.obtainMessage(1, databaseError.getMessage()).sendToTarget();
}
});
} catch (Exception e) {
}
}
400 error means bad request so there's something wrong with your field parameters. Also, note that maxResults in Youtube API list has a maximum value of 50.
Related
I have two RecyclerViews inside a LinearLayout in which I'm trying to display Firebase Storage data on one and some Products data queried from Real-Time Database on the other. While I am able to retrieve the data successfully, I have trouble showing it on the RecyclerView(s).
There are 1 of 3 things that happen spontaneously when I try to display the data:
Case 1: Data does not show on both RecyclerViews OR
Case 2: Data is shown for the first RecyclerView(displays storage
data) OR
Case 3: Data shows for both (but can sometimes take a verrryy long
time to load even though I have only one data each for both).
For the second RecyclerView, I have written the code to query in-app products data from Google Play Console using the billingclient library and I use the data queried from Real-Time DB to see if there is a match in the product IDs. If there is, I display the matching data on the RecyclerView.
While fetching the data is fine, at various times my code gets stuck on setAdapter() and I don't understand why and I don't know how to get it to work properly?
Here's a reference to my current code:
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
FirebaseStorage storage = FirebaseStorage.getInstance();
FirebaseDatabase database = FirebaseDatabase.getInstance();
storageRef = storage.getReference();
dataRef = database.getReference().child("products");
view = inflater.inflate(R.layout.course_fragment, parent, false);
mainLayout = view.findViewById(R.id.mainLayout);
filesRv = view.findViewById(R.id.file_recycler_view);
productRv = view.findViewById(R.id.product_recycler_view);
//list storage folder/files
listFilesFolders();
//check for premium data on real-time database and see if productID matches with productID on Google Play Console (display data on recycler view if it matches)
checkForPremium();
return view;
}
private void checkForPremium() {
setBillingClient(getContext());
connectToGooglePlay();
}
private void listFilesFolders() {
fileStorageRef.listAll()
.addOnSuccessListener(listResult -> {
for (StorageReference folder : listResult.getPrefixes()) {
parentFolder = folder.getName();
contentList.add(fileStorageRef.child(parentFolder));
}
for (StorageReference file : listResult.getItems()) {
fileName = file.getName();
contentList.add(fileStorageRef.child(fileName));
}
setFilesRecyclerView();
})
.addOnFailureListener(e -> {
// Some code here
})
.addOnCompleteListener(task -> {
// Some code here
});
}
private void setFilesRecyclerView() {
if(pageTitle.equals(rootFolder) || contentList.isEmpty()) {
displayFolders();
}
else {
displayFiles();
}
}
private void displayFolders() {
int columnCount = 2;
DisplayMetrics displayMetrics = view.getResources().getDisplayMetrics();
int width = displayMetrics.widthPixels; //get screen width
//if screen width is large, increase grid columns
if(width > 800 && width < 1500){
columnCount = 3;}
else if(width >= 1500 && width < 1800){
columnCount = 4; }
else if(width >= 1800){
columnCount = 5;
}
GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), columnCount);
SubFolderAdapter subFolderAdapter = new SubFolderAdapter(getActivity(), contentList);
filesRv.setLayoutManager(gridLayoutManager);
filesRv.setAdapter(subFolderAdapter);
}
private void displayFiles() {
LinearLayoutManager llm1 = new LinearLayoutManager(getActivity());
fileAdapter = new FileAdapter(getActivity(), contentList);
filesRv.setLayoutManager(llm1);
filesRv.setAdapter(fileAdapter);
}
private void displayPremiumData() {
LinearLayoutManager llm2 = new LinearLayoutManager(getActivity());
productsAdapter = new ProductsAdapter3(getActivity(), billingClient, prodDetailsList, path);
productRv.setLayoutManager(llm2);
productRv.setAdapter(productsAdapter);
}
public void setBillingClient(Context context) {
System.out.println("Set billing client");
billingClient = BillingClient.newBuilder(context) //creates instance of billing client
.enablePendingPurchases()
.setListener(this)
.build();
}
public void connectToGooglePlay() {
//Establish a connection to Google Play
billingClient.startConnection(new BillingClientStateListener() {
#Override
public void onBillingSetupFinished(#NonNull BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
// The BillingClient is ready. You can query purchases here.
System.out.println("Billing client ready");
listPremium();
} else System.out.println("Billing client NOT ready");
}
#Override
public void onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
System.out.println("Billing service disconnected");
}
});
}
private void listPremium() {
premiumDBRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
cProductsList.clear();
for (DataSnapshot snap: snapshot.getChildren()) {
Products products = snap.getValue(Products.class);
String sku;
String name;
String url;
if (products != null) {
sku = products.getProductId();
name = products.getName();
url = products.getUrl();
if(sku != null) {
skuList.add(sku);
}
} else {
System.out.println("Product does not exist!");
}
}
for(String sku : skuList) {
productList.add(
QueryProductDetailsParams.Product.newBuilder()
.setProductId(sku)
.setProductType(BillingClient.ProductType.INAPP)
.build()
);
}
if (!productList.isEmpty()) {
querySkuDetails(productList);
} else {
System.out.println("No products available");
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
public void querySkuDetails(List<QueryProductDetailsParams.Product> productList) {
QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder()
.setProductList(productList)
.build();
billingClient.queryProductDetailsAsync(
params,
(billingResult, productDetailsList) -> {
// check billingResult
// process returned productDetailsList
if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) {
System.out.printf(Locale.ENGLISH, "Unable to query sku details: %d - %s%n", billingResult.getResponseCode(), billingResult.getDebugMessage());
} else {
for (ProductDetails details: productDetailsList) {
prodDetailsList.add(details);
}
displayPremiumData();
}
});
}
Note: When I run the code, there are no errors. The issue is that the RecyclerView is not working consistently as intended.
I have been trying to get this to work but I have been stuck for days now and I would really appreciate some help please!
I'm using GraphView library. My code below gets data from Firebase real-time database and updates the graph with values from database, but it isn't sorted. I need it to be sorted in ascending order in X axis. The data in X axis is Long type, then it's converted to date.
I've tried adding dp[index] to array list and using different sorting methods, but nothing seems to work.
#Override
public void onStart() {
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
FirebaseAuth auth;
auth = FirebaseAuth.getInstance();
FirebaseUser user = auth.getCurrentUser();
String id = user.getUid();
DataPoint[] dp = new DataPoint[(int) snapshot.child(id).getChildrenCount()];
int index = 0;
for(DataSnapshot myDataSnapshot : snapshot.child(id).getChildren()){
PointValue pointValue = myDataSnapshot.getValue(PointValue.class);
dp[index] = new DataPoint(pointValue.getxValue(), pointValue.getyValue());
index ++;
}
lineGraphSeries.resetData(dp);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
super.onStart();
}
AlertDialog, where data is being written to the database:
builder.setPositiveButton("ADD",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
if(TextUtils.isEmpty(weightEditText.getText().toString()) || TextUtils
.isEmpty(dateEditText.getText().toString())) {
Toast.makeText(getActivity(),"Please provide weight and date",
Toast.LENGTH_SHORT).show();
} else{
linearLayout.addView(createNewTextView(weightEditText.getText().toString(),
dateEditText.getText().toString()));
String id = user.getUid();
String randomId = reference.push().getKey();
try {
Date date = sdf.parse(dateEditText.getText().toString());
long x = date.getTime();
int y = Integer.parseInt(weightEditText.getText().toString());
PointValue pointValue = new PointValue(x,y);
reference.child(id).child(randomId).setValue(pointValue);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
});
builder.setView(view);
builder.show();
PointValue class:
public class PointValue {
long xValue;
int yValue;
public PointValue() {
}
public PointValue(long xValue, int yValue) {
this.xValue = xValue;
this.yValue = yValue;
}
public long getxValue() {
return xValue;
}
public int getyValue() {
return yValue;
}
}
#EDIT
Thanks to #Frank van Puffelen, I've managed to sort my data from Firebase Database using orderByChild()
https://firebase.google.com/docs/database/android/lists-of-data#sort_data
below working solution:
#Override
public void onStart() {
FirebaseAuth auth;
auth = FirebaseAuth.getInstance();
FirebaseUser user = auth.getCurrentUser();
String id = user.getUid();
Query dateAscendingOrder = database.getReference("users")
.child(id).orderByChild("xValue");
dateAscendingOrder.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
DataPoint[] dp = new DataPoint[(int) snapshot.getChildrenCount()];
int index = 0;
for (DataSnapshot myDataSnapshot : snapshot.getChildren()){
PointValue pointValue = myDataSnapshot.getValue(PointValue.class);
dp[index] = new DataPoint(pointValue.getxValue(), pointValue.getyValue());
index++;
}
lineGraphSeries.resetData(dp);
}
I am trying to implement a ViewModel architecture for a RecyclerView in AndroidX, following the example as stated in enter link description here and enter link description here. Items in the recyclerView get selected on position clicked, but for some reason, the selected item de-select and revert to default after the device is rotated and configuration changed. I know there have been answers for questions like this in the past, but all I have seen are either not directly applicable in my case or are simply for deprecated cases.
CAN SOMEONE PLEASE TELL ME WHAT I AM DOING WRONG!
Below are snippets from my Code:
Dependencies added
dependencies {
def lifecycle_version = "2.2.0"
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
// Saved state module for ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
// Annotation processor
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha02'
}
Repository Class:
public class TopicRepository {
private Application application;
private SharedPreferences sharedPreferences;
private ArrayList<RootTopic> topicGroupList;
private MutableLiveData<ArrayList<RootTopic>>topicGroupMLD;
public TopicRepository(Application application) {
this.application = application;
}
public LiveData<ArrayList<RootTopic>> getRootTopicLD(String subject){
if (topicGroupMLD == null){
topicGroupMLD = new MutableLiveData<ArrayList<RootTopic>>();
generateTopicGroup(subject);
}
return topicGroupMLD;
}
private void generateTopicGroup(final String subject){
Log.d(TAG, "generateTopicGroup: CALLED");
isRequestingMLD.postValue(true);
final String subjectTopicGroupList = subject + "TopicGroupList";
sharedPreferences = application.getSharedPreferences(AppConstant.Constants.PACKAGE_NAME, Context.MODE_PRIVATE);
String serializedTopicGroup = sharedPreferences.getString(subjectTopicGroupList, null);
if (serializedTopicGroup != null){
Gson gson = new Gson();
Type type = new TypeToken<ArrayList<RootTopic>>(){}.getType();
topicGroupList = gson.fromJson(serializedTopicGroup, type);
topicGroupMLD.postValue(topicGroupList);
}else {// - Not saved in SP
Log.d(TAG, "getTopicGroup: NOT IN SP");
new ActiveConnectionCheck(new ActiveConnectionCheck.Consumer() {
#Override
public void accept(Boolean internet) {
Log.d(TAG, "accept: CHECKED INTERNET");
if (internet){
Log.d(TAG, "accept: INTERNET CONNECTION = TRUE");
internetCheckMLD.postValue(AppConstant.Constants.IS_INTERNET_REQUEST_SUCCESS);
FirebaseFirestore fbFStore = FirebaseFirestore.getInstance();
CollectionReference lectureRef = fbFStore.collection(subject);
lectureRef.orderBy(AppConstant.Constants.POSITION, Query.Direction.ASCENDING)
.get().addOnSuccessListener(
new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
ArrayList<Topic>topicList = new ArrayList<>();
ArrayList<String> rootTitleList = new ArrayList<>();
for (QueryDocumentSnapshot snapshot : queryDocumentSnapshots){
Topic topic = snapshot.toObject(Topic.class);
topicList.add(topic);
}
Log.d(TAG, "onSuccess: TopicListSize = " + topicList.size());
for (Topic topic : topicList){
String rootTopicString = topic.getRootTopic();
if (!rootTitleList.contains(rootTopicString)){
rootTitleList.add(rootTopicString);
}
}
Log.d(TAG, "onSuccess: RootTitleListSize = " + rootTitleList.size());
for (int x = 0; x < rootTitleList.size(); x ++){
RootTopic rootTopic = new RootTopic(rootTitleList.get(x), new ArrayList<Topic>());
topicGroupList = new ArrayList<>();
topicGroupList.add(rootTopic);
}
for (int e = 0; e < topicList.size(); e++){
addTopicToGroup(topicGroupList, topicList.get(e));
}
topicGroupMLD.postValue(topicGroupList);
Gson gson = new Gson();
String serializedTopicGroup = gson.toJson(topicGroupList);
sharedPreferences.edit().putString(subjectTopicGroupList, serializedTopicGroup).apply();
Log.d(TAG, "onSuccess: TOPICGROUPSIZE = " + topicGroupList.size());
Log.d(TAG, "onSuccess: SERIALIZED GROUP = " + serializedTopicGroup);
isRequestingMLD.postValue(false);
}
}
).addOnFailureListener(
new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
isRequestingMLD.postValue(false);
Log.d(TAG, "onFailure: FAILED TO GET TOPICLIST e = " + e.toString());
}
}
);
}else {
internetCheckMLD.postValue(AppConstant.Constants.IS_INTERNET_REQUEST_FAIL);
Log.d(TAG, "accept: InternetCONECTION = " + false);
}
}
});
}
}
private void addTopicToGroup(ArrayList<RootTopic>rootGroup, Topic topic){
for (int x = 0; x < rootGroup.size(); x++){
RootTopic rootTopic = rootGroup.get(x);
if (rootTopic.getRootTopicName().equals(topic.getRootTopic())){
rootTopic.getTopicGroup().add(topic);
}
}
}
}
My ViewModel class
public class LectureViewModel extends AndroidViewModel {
public static final String TAG = AppConstant.Constants.GEN_TAG + ":LectureVM";
private Application application;
private TopicRepository topicRepository;
private ArrayList<RootTopic> topicGroupList;
public LectureViewModel(#NonNull Application application) {
super(application);
this.application = application;
topicRepository = new TopicRepository(application);
}
public LiveData<ArrayList<RootTopic>> getRootTopicListLD(String subject){
return topicRepository.getRootTopicLD(subject);
}
}
Activity Implementing ViewModel
public class LectureRoomActivity extends AppCompatActivity {
public static final String TAG = AppConstant.Constants.GEN_TAG + " LecRoom";
private LectureViewModel lectureRoomVM;
private String subject;
private RecyclerView mainRecyclerView;
private RootTopicAdapter rootTopicAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lecture_room);
Intent intent = getIntent();
subject = intent.getStringExtra(AppConstant.Constants.SUBJECT);
mainRecyclerView = findViewById(R.id.recyclerView);
downloadVM = new ViewModelProvider(this).get(DownloadLectureViewModel.class);
lectureRoomVM = new ViewModelProvider(this).get(LectureViewModel.class);
lectureRoomVM.getRootTopicListLD(subject).observe(
this,
new Observer<ArrayList<RootTopic>>() {
#Override
public void onChanged(ArrayList<RootTopic> rootTopics) {
if (rootTopics != null){
currentTopic = lectureRoomVM.getCursorTopic(subject, rootTopics);
setUpRec(rootTopics, currentTopic);
}
}
});
}
private void setUpRec( ArrayList<RootTopic>topicGroup, CursorTopic currentTopic){
rootTopicAdapter = new RootTopicAdapter(topicGroup,
new ArrayList<String>(), currentTopic.getParentPosition(),
currentTopic.getCursorPosition());
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(
this, RecyclerView.VERTICAL,false);
mainRecyclerView.setHasFixedSize(true);
mainRecyclerView.setLayoutManager(linearLayoutManager);
mainRecyclerView.setAdapter(rootTopicAdapter);
Log.d(TAG, "setUpRec: SETTING REC");
}
}
For saving and restoring UI related data you better use savedInstanceState Bundle to survive the last state. To achive this you simply override two methods in you UI activity. See the sample code snippet below.
In your RootTopicAdapter
// Add this where you detect the item click, probably in your adaptor class
private int lastRecyclerViewIndex; // define the variable to hold the last index
...
#Override
public void onClick(View v) {
lastRecyclerViewIndex = getLayoutPosition();
}
public int getLastIndex() {
return lastRecyclerViewIndex;
}
In your view model class
public class LectureViewModel extends AndroidViewModel {
public static final String TAG = AppConstant.Constants.GEN_TAG + ":LectureVM";
private Application application;
private TopicRepository topicRepository;
private ArrayList<RootTopic> topicGroupList;
public boolean mustRestore; // Is there any data to restore
public int lasIndexSelected;
public LectureViewModel(#NonNull Application application) {
super(application);
this.application = application;
topicRepository = new TopicRepository(application);
}
public LiveData<ArrayList<RootTopic>> getRootTopicListLD(String subject){
return topicRepository.getRootTopicLD(subject);
}
}
In you UI activity which uses the RecyclerView
public class LectureRoomActivity extends AppCompatActivity {
...
private LectureViewModel lectureRoomVM;
...
private RecyclerView mainRecyclerView;
private RootTopicAdapter rootTopicAdapter;
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lecture_room);
Intent intent = getIntent();
subject = intent.getStringExtra(AppConstant.Constants.SUBJECT);
mainRecyclerView = findViewById(R.id.recyclerView);
downloadVM = new ViewModelProvider(this).get(DownloadLectureViewModel.class);
lectureRoomVM = new ViewModelProvider(this).get(LectureViewModel.class);
lectureRoomVM.getRootTopicListLD(subject).observe(
this,
new Observer<ArrayList<RootTopic>>() {
#Override
public void onChanged(ArrayList<RootTopic> rootTopics) {
if (rootTopics != null){
currentTopic = lectureRoomVM.getCursorTopic(subject, rootTopics);
setUpRec(rootTopics, currentTopic);
// Exactly here, after setting up the data get your index for example
if(lectureRoomVM.mustRestore){
// Check the item count in the adaptor to avoid crashes
if(mainRecyclerView.getAdapter().getItemCount >= lastRecyclerViewIndex){
mainRecyclerView.findViewHolderForAdapterPosition(lastRecyclerViewIndex).itemView.performClick();
}
// After the restoration set the mustRestore to false
lectureRoomVM.mustRestore = false;
}
}
}
});
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.d(E, "onDestroy");
/*
* Here just set the mustRestore to true in order to be able to restore in onCreate method.
* If the application itself is not destroyed your data will still be live in the
* memory thanks to the ViewModel's life cycle awarness.
*/
lectureRoomVM.mustRestore = true;
}
}
There you go. Try this logic carefully without bugs. Then I think you will achive what you want to get.
I am new in Android and working on an Android app which can retrieve data from firebase. There is a weird problem. I already successfully implemented the retrieving function for one data model of my program, and I used same codes just changed the variables but it doesn't work for another data model. I did many tests and I think the problem is in FirebaseHelper cuz there is no any data returned from the data snapshot. The error is
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ListView.setAdapter(android.widget.ListAdapter)' on a null object reference
The codes are shown below:
The Activity that shows the retrieved data in a listview.
public class TimeTableActivity extends AppCompatActivity {
DatabaseReference db;
FirebaseHelper firebasehelper;
TimeTableAdapter adapter;
ListView lv_CourseList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_time_table);
//GET INTENT
Intent intent = this.getIntent();
String majorID = intent.getStringExtra("MAJOR_ID");
lv_CourseList = (ListView) findViewById(R.id.lv_CourseList);
//INITIALIZE FIREBASE DB
db= FirebaseDatabase.getInstance().getReference();
firebasehelper=new FirebaseHelper(db);
//ADAPTER
adapter = new TimeTableAdapter(getApplicationContext(),firebasehelper.retrieveCourse(majorID, new CourseCallbacks() {
#Override
public void onCourseCallback(ArrayList<CourseInfo> courseInfos) {
lv_CourseList.setAdapter(adapter);
}
}));
lv_CourseList.setAdapter(adapter);
}
}
FirebaseHelper:
public class FirebaseHelper{
private DatabaseReference db;
private ArrayList<Major> majors = new ArrayList<>();
private ArrayList<CourseInfo> courseInfos = new ArrayList<>();
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
//Save the Major info. into db
public Boolean saveMajor(Major major)
{
Boolean saved = null;
if(major==null)
{
saved =false;
}else
{
try
{
db.child("Major").push().setValue(major);
saved =true;
}catch (DatabaseException e)
{
e.printStackTrace();
saved =false;
}
}
return saved;
}
//Save the Course info. into db
public Boolean saveCourse(CourseInfo courseInfo)
{
Boolean saved = null;
if(courseInfo==null)
{
saved =false;
}else
{
try
{
db.child("CourseInfo").push().setValue(courseInfo);
saved =true;
}catch (DatabaseException e)
{
e.printStackTrace();
saved =false;
}
}
return saved;
}
public ArrayList<Major> retrieveMajor(final MajorCallbacks majorCallbacks){
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
Major major = ds.getValue(Major.class);
if (major != null && major.getMajor_id() != null) {
majors.add(major);
}
}
majorCallbacks.onMajorCallback(majors);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
Major major = ds.getValue(Major.class);
if (major != null && major.getMajor_id() != null) {
majors.add(major);
}
}
majorCallbacks.onMajorCallback(majors);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
db.addChildEventListener(childEventListener);
if (!majors.isEmpty()){
db.removeEventListener(childEventListener);
}
return majors;
}
public ArrayList<CourseInfo> retrieveCourse(String majorID, final CourseCallbacks courseCallbacks){
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
CourseInfo courseInfo = ds.getValue(CourseInfo.class);
if (courseInfo != null && courseInfo.getCourse_id() != null) {
courseInfos.add(courseInfo);
}
}
courseCallbacks.onCourseCallback(courseInfos);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String prevChildKey) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
CourseInfo courseInfo = ds.getValue(CourseInfo.class);
if (courseInfo != null && courseInfo.getCourse_id() != null) {
courseInfos.add(courseInfo);
}
}
courseCallbacks.onCourseCallback(courseInfos);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String prevChildKey) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
db.child("CourseInfo").orderByChild("major_id").equalTo(majorID).addChildEventListener(childEventListener);
return courseInfos;
}
}
The retrieveMajor method works well even though it returns many null data and repetitive data, and I used the codes of retrieveMajor in retrieveCourse. It doesn't work, the courseInfos is always null. Even though I changed db.child("CourseInfo").orderByChild("major_id").equalTo(majorID).addChildEventListener(childEventListener);
to
db.addChildEventListener(childEventListener);
,still nothing is retrieved which means the problem is not the query (Probably the query is also wrong).
Adapter:
public class TimeTableAdapter extends BaseAdapter {
Context context;
ArrayList<CourseInfo> courseInfos;
public TimeTableAdapter(Context context, ArrayList<CourseInfo> courseInfos) {
this.context = context;
this.courseInfos = courseInfos;
}
#Override
public int getCount() {
return courseInfos.size();
}
#Override
public Object getItem(int pos) {
return courseInfos.get(pos);
}
#Override
public long getItemId(int pos) {
return pos;
}
#Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
LayoutInflater inflater = LayoutInflater.from(context);
if(convertView == null)
{
convertView= LayoutInflater.from(context).inflate(R.layout.model_timetable,viewGroup,false);
}
TextView tv_courseid= (TextView) convertView.findViewById(R.id.tv_courseid);
TextView tv_coursename= (TextView) convertView.findViewById(R.id.tv_coursename);
TextView tv_courseinstructor= (TextView) convertView.findViewById(R.id.tv_courseinstructor);
TextView tv_courseavailable= (TextView) convertView.findViewById(R.id.tv_courseavailable);
final CourseInfo courseInfo= (CourseInfo) this.getItem(position);
tv_courseid.setText(courseInfo.getCourse_id());
tv_coursename.setText(courseInfo.getCourse_name());
tv_courseinstructor.setText(courseInfo.getCourse_instructor());
tv_courseavailable.setText(courseInfo.getCourse_available());
return convertView;
}
}
Data model:
#IgnoreExtraProperties
public class CourseInfo {
public String course_id;
public String course_name;
public int course_section;
public String course_type;
public double course_crdhrs;
public String course_days;
public String course_times;
public String course_location;
public int course_max;
public int course_cur;
public int course_available;
public int course_wl;
public double course_per;
public String course_instructor;
public String course_description;
public String course_prerequire;
public String major_id;
public CourseInfo() {
}
public CourseInfo(String course_id, String course_name, int course_section, String course_type, double course_crdhrs, String course_days, String course_times, String course_location, int course_max, int course_cur, int course_available, int course_wl, double course_per, String course_instructor, String course_description, String course_prerequire, String major_id) {
this.course_id = course_id;
this.course_name = course_name;
this.course_section = course_section;
this.course_type = course_type;
this.course_crdhrs = course_crdhrs;
this.course_days = course_days;
this.course_times = course_times;
this.course_location = course_location;
this.course_max = course_max;
this.course_cur = course_cur;
this.course_available = course_available;
this.course_wl = course_wl;
this.course_per = course_per;
this.course_instructor = course_instructor;
this.course_description = course_description;
this.course_prerequire = course_prerequire;
this.major_id = major_id;
}
public String getCourse_id() {
return course_id;
}
public String getCourse_name() {
return course_name;
}
public int getCourse_section() {
return course_section;
}
public String getCourse_type() {
return course_type;
}
public double getCourse_crdhrs() {
return course_crdhrs;
}
public String getCourse_days() {
return course_days;
}
public String getCourse_times() {
return course_times;
}
public String getCourse_location() {
return course_location;
}
public int getCourse_max() {
return course_max;
}
public int getCourse_cur() {
return course_cur;
}
public int getCourse_available() {
return course_available;
}
public int getCourse_wl() {
return course_wl;
}
public double getCourse_per() {
return course_per;
}
public String getCourse_instructor() {
return course_instructor;
}
public String getCourse_description() {
return course_description;
}
public String getCourse_prerequire() {
return course_prerequire;
}
public String getMajor_id() {
return major_id;
}
}
If you need more codes or information, please comment and let me know. I will really appreciate if you can also help me solve the null data and repetitive data problem cuz it makes the listview show many blank and repetitive items.
You cannot return something now that hasn't been loaded yet. With other words, you cannot just simply create a method that as a return type, an ArrayList<Major> and in the same time return that object. This is happening because those methods, onChildAdded(), onChildChanged() and so on, have an asynchronous behaviour, which means that are called even before you are getting/updating the data from/in the database. To solve this, you can move the declaration of that ArrayList inside one method and do what you need to do with it or dive into asynchronous world and use the last part of my answer from this post. You can take also a look at this video for a better understanding.
Rather than describing from zero to all, I would like to illustrate the thing I wanted with an example.
Let's take an example of Playstore, when we search for any application, we get a long list of search results. Only those results are downloaded first which we can see first depends upon screen size not all results are downloaded at once. How to make that kind of request-response cycle in my application.
I use PHP for back-end to get results in JSON format. So, how to get JSON response in modular form.
Use the concept of PAGINATION on your backend and send your response and use the concept of LAZY LOADING on your RecyclerView
Here i have added code for setting lazy loading in recyclerview
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (mLayoutManager.findLastCompletelyVisibleItemPosition() ==
mObjectList.size() - 1 && !mIsLoading && !mIsEnded) {
mIsLoading = true;
getList();
}
}
});
private void getList() {
addProgressItem();
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET,
mUrl, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
mRefreshLayout.setRefreshing(false);
removeProgressItem();
setLoading(); // isLoading = false
handleListResponse(response);
isEmptyList();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
mRefreshLayout.setRefreshing(false);
removeProgressItem();
setLoading();
VolleyErrorHandler.handle(MainActivity.this, error);
isEmptyList();
}
});
AppController.getInstance().addToRequestQueue(jsonObjectRequest, "list");
}
private void handleListResponse(JSONObject response) {
clearList();
try {
mCount = response.getInt("count");
mNextUrl = response.getString("next_url");
//process JSON here
mAdapter.notifyDataSetChanged();
if (mNextUrl == null || TextUtils.isEmpty(mNextUrl) || mNextUrl.equals("null")) {
isEnded();//set list ended
}
} catch (JSONException e) {
e.printStackTrace();
}
}
private void addProgressItem() {
if (mCount != 0) {
mObjectList.add(null);
mAdapter.notifyItemInserted(mObjectList.size() - 1);
}
}
private void removeProgressItem() {
if (mCount != 0) {
mObjectList.remove(mObjectList.size() - 1);
mAdapter.notifyItemRemoved(mObjectList.size());
}
}
private void setLoading() {
mIsLoading = false;
}
private void isEnded() {
mIsEnded = true;
}
private void isEmptyList() {
if (mObjectList.size() == 1) {
mObjectList.add(1, -1);
mAdapter.notifyItemInserted(1);
} else if (mObjectList.get(1) instanceof Integer) {
mObjectList.remove(1);
mAdapter.notifyItemRemoved(1);
}
}