getViewBinding() method does not override method from its superclass BaseActivity - android

getViewBinding() method does not override method from its superclass BaseActivity<T extends ViewBinding>
MentorChatActivity.java
package com.ocr.firebaseoc.ui.chat;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.firebase.ui.firestore.FirestoreRecyclerOptions;
import com.google.firebase.firestore.Query;
import com.ocr.firebaseoc.databinding.ActivityMentorChatBinding;
import com.ocr.firebaseoc.manager.ChatManager;
import com.ocr.firebaseoc.manager.UserManager;
import com.ocr.firebaseoc.model.Message;
import com.ocr.firebaseoc.ui.BaseActivity;
public class MentorChatActivity extends BaseActivity<ActivityMentorChatBinding> implements MentorChatAdapter.Listener {
private MentorChatAdapter mentorChatAdapter;
private String currentChatName;
private static final String CHAT_NAME_ANDROID = "android";
private static final String CHAT_NAME_BUG = "bug";
private static final String CHAT_NAME_FIREBASE = "firebase";
private UserManager userManager = UserManager.getInstance();
private ChatManager chatManager = ChatManager.getInstance();
#Override
protected ActivityMentorChatBinding getViewBinding() {
return ActivityMentorChatBinding.inflate(getLayoutInflater());
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
configureRecyclerView(CHAT_NAME_ANDROID);
setupListeners();
}
private void setupListeners(){
// Chat buttons
binding.androidChatButton.setOnClickListener(view -> { this.configureRecyclerView(CHAT_NAME_ANDROID); });
binding.firebaseChatButton.setOnClickListener(view -> { this.configureRecyclerView(CHAT_NAME_FIREBASE); });
binding.bugChatButton.setOnClickListener(view -> { this.configureRecyclerView(CHAT_NAME_BUG); });
}
// Configure RecyclerView
private void configureRecyclerView(String chatName){
//Track current chat name
this.currentChatName = chatName;
//Configure Adapter & RecyclerView
this.mentorChatAdapter = new MentorChatAdapter(
generateOptionsForAdapter(chatManager.getAllMessageForChat(this.currentChatName)),
Glide.with(this), this);
mentorChatAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
#Override
public void onItemRangeInserted(int positionStart, int itemCount) {
binding.chatRecyclerView.smoothScrollToPosition(mentorChatAdapter.getItemCount()); // Scroll to bottom on new messages
}
});
binding.chatRecyclerView.setLayoutManager(new LinearLayoutManager(this));
binding.chatRecyclerView.setAdapter(this.mentorChatAdapter);
}
// Create options for RecyclerView from a Query
private FirestoreRecyclerOptions<Message> generateOptionsForAdapter(Query query){
return new FirestoreRecyclerOptions.Builder<Message>()
.setQuery(query, Message.class)
.setLifecycleOwner(this)
.build();
}
public void onDataChanged() {
// Show TextView in case RecyclerView is empty
binding.emptyRecyclerView.setVisibility(this.mentorChatAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
}
}
BaseActivity.java
package com.ocr.firebaseoc.ui;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewbinding.ViewBinding;
import com.ocr.firebaseoc.databinding.ActivityMentorChatBinding;
/**
* Base Activity class that allow to manage all the common code for the activities
* #param <T> Should be the type of the viewBinding of your activity see more here
*/
public abstract class BaseActivity<T extends ViewBinding> extends AppCompatActivity {
abstract T getViewBinding();
protected T binding;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initBinding();
}
/**
* Initialise the binding object and the layout of the activity
*/
private void initBinding(){
binding = getViewBinding();
View view = binding.getRoot();
setContentView(view);
}
}
Error message:
Class 'MentorChatActivity' must either be declared abstract or implement abstract method 'getViewBinding()' in 'BaseActivity'
Method does not override method from its superclass
Can someone please explain what went wrong ?
here's my project's github link

abstract T getViewBinding() is a package private, you can't override in other package. MentorChatActivity is in other package that's why its throwing error.
Make your abstract method public,
abstract public T getViewBinding(), or move all classes to same package.

Related

How to make NEW Networking Calls in MVVM?

I'm trying to implement pull to refresh with MVVM (and a recyclerview) yet I don't understand how I'm supposed to fetch new data. Inital load up of the app is fine as I'm just observing the livedata from the view model when it's created, but how do I query for more data?
MainActivity.java
package com.example.simplenews;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.example.simplenews.adapters.NewsArticleAdapter;
import com.example.simplenews.adapters.RecyclerItemClickListener;
import com.example.simplenews.models.Article;
import com.example.simplenews.models.NewsResponse;
import com.example.simplenews.repositories.NewsAPI;
import com.example.simplenews.repositories.NewsRepository;
import com.example.simplenews.viewmodels.NewsViewModel;
import com.victor.loading.rotate.RotateLoading;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import timber.log.Timber;
public class MainActivity extends AppCompatActivity {
private RecyclerView newsRecyclerView;
private NewsArticleAdapter newsAdapter;
private NewsAPI NewsAPI;
private ArrayList<Article> newsArticles = new ArrayList<>();
private RotateLoading rotateLoadingIndicator;
private SwipeRefreshLayout swipeRefreshLayout;
private NewsViewModel newsViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Planting timber debug tree here because this joint refuses to work when planted in the application class
Timber.plant(new Timber.DebugTree());
swipeRefreshLayout = findViewById(R.id.swipe_refresh_layout);
newsRecyclerView = findViewById(R.id.newsRecyclerView);
rotateLoadingIndicator = findViewById(R.id.rotate_loading_indicator);
// Getting and setting up the viewmodel
newsViewModel = new ViewModelProvider(this).get(NewsViewModel.class);
newsViewModel.initNewsViewModel();
// Setting up the observer
newsViewModel.getNewsRepositoryQuery().observe(this, newsResponse -> {
ArrayList<Article> freshNewsArticles = (ArrayList<Article>) newsResponse.getArticles();
newsArticles.addAll(freshNewsArticles);
newsAdapter.notifyDataSetChanged();
});
initReyclerView();
// This is not the way to do recyclerview click listeners but this will suffice for now
newsRecyclerView.addOnItemTouchListener(
new RecyclerItemClickListener(this, newsRecyclerView, new RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
Article article = newsArticles.get(position);
Uri uri = Uri.parse(article.getUrl());
Intent webIntent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(webIntent);
}
#Override
public void onLongItemClick(View view, int position) {
}
})
);
// Configure the refreshing colors
swipeRefreshLayout.setColorSchemeColors(getResources().getColor(R.color.colorPrimary));
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
newsViewModel.getNewHeadlines().observe(MainActivity.this, new Observer<NewsResponse>() {
#Override
public void onChanged(NewsResponse newsResponse) {
if (newsResponse.getArticles() != null) {
refreshNewsRecyclerView(newsResponse.getArticles());
swipeRefreshLayout.setRefreshing(false);
}
swipeRefreshLayout.setRefreshing(false);
Timber.d("the articles in the refresh callback were null");
}
});
}
});
}
/*
* Helper method that refreshes topHeadlinesRecyclerView with new articles
* #param: list of new article objects from a network request
* */
private void refreshNewsRecyclerView(List<Article> freshArticles) {
newsRecyclerView.setVisibility(View.INVISIBLE);
showLoadingIndicator();
newsAdapter.clearNewsArticles();
newsAdapter.addAll(freshArticles);
newsRecyclerView.setVisibility(View.VISIBLE);
hideLoadingIndicator();
newsAdapter.notifyDataSetChanged();
}
/*
* Helper method to show the loading indicator
* */
private void showLoadingIndicator() {
rotateLoadingIndicator.setVisibility(View.VISIBLE);
rotateLoadingIndicator.start();
}
/*
* Helper method to hide loading indicator
* */
private void hideLoadingIndicator() {
rotateLoadingIndicator.stop();
rotateLoadingIndicator.setVisibility(View.GONE);
}
/*
* Helper method to setup the recyclerView
* */
private void initReyclerView() {
if (newsAdapter == null) {
showLoadingIndicator();
newsAdapter = new NewsArticleAdapter(newsArticles, this);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
newsRecyclerView.setLayoutManager(layoutManager);
newsRecyclerView.setAdapter(newsAdapter);
hideLoadingIndicator();
} else {
newsAdapter.notifyDataSetChanged();
}
}
}
NewsViewModel
public class NewsViewModel extends ViewModel {
private MutableLiveData<NewsResponse> mutableLiveData;
private NewsRepository newsRepository;
// When a viewmodel object is created fetch the data needed for the activitiy
public void initNewsViewModel() {
if (mutableLiveData != null) {
return;
}
newsRepository = NewsRepository.getInstance();
mutableLiveData = newsRepository.getTopHeadlines();
}
public MutableLiveData<NewsResponse> getNewsRepositoryQuery() {
return mutableLiveData;
}
public MutableLiveData<NewsResponse> getNewHeadlines() {
MutableLiveData<NewsResponse> response = newsRepository.getTopHeadlines();
return response;
}
}
News Repository
public class NewsRepository {
private static NewsRepository newsRepository;
private NewsAPI newsAPI;
private List<Article> freshArticles;
public static NewsRepository getInstance() {
if (newsRepository == null) {
newsRepository = new NewsRepository();
}
return newsRepository;
}
/*
* Private constructor because nobody should be creating this object direcly
* */
private NewsRepository() {
newsAPI = RetrofitClient.getRetrofitInstance().create(NewsAPI.class);
}
public MutableLiveData<NewsResponse> getTopHeadlines() {
MutableLiveData<NewsResponse> topHeadlines = new MutableLiveData<>();
newsAPI.getRootJSONObject().enqueue(new Callback<NewsResponse>() {
#Override
public void onResponse(Call<NewsResponse> call, Response<NewsResponse> response) {
if (response.isSuccessful()) {
topHeadlines.setValue(response.body());
Timber.d("Network call was succesful here is the response code " + response.code());
} else {
Timber.d("Network call was unsuccesful " + response.code());
}
}
#Override
public void onFailure(Call<NewsResponse> call, Throwable t) {
Timber.d("Network call completely failed lol");
topHeadlines.setValue(null);
}
});
return topHeadlines;
}
}
You can simply make a function which reset value of MutableLiveData
For example on swipe call viewmodel.resetNewsHeadlines() and in resetNewsHeadlines() method simple set value to null and recall mutableLiveData = newsRepository.getTopHeadlines(); again

How to use a ViewModel outside of onCreate()?

I have an Activity with a RecyclerView which display Livedata from a room database.
My aim is to start a new Activity with more data from the room database when the user is clicking on the corresponding item in the RecyclerView.
For that I overwrote the onClick() method in the adapter of the RecylcerView. Each object of the RecyclerView has a Id, I need that Id to get the corresponding data from the database. So I passed the Id from the Adapter to the Activity.
To search an element by Id in the database that I need the ViewModel object in the MainAcitivty. It is initialized in the onCreate() of the Activity. The method I called in the Adapter is outside the onCreate() and I get a null object reference exception when I try to use it.
How can I use the ViewModel outside of the onCreate() method of the Activity? Or is there another way to search for the element in the database?
Thank you!
The Adapter class:
In the onClick() method is the relevant part.
package com.example.fillmyplate.activities;
import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.fillmyplate.R;
import com.example.fillmyplate.entitys.Recipe;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
class RecipeAdapter extends RecyclerView.Adapter<RecipeAdapter.RecipeViewHolder> {
private static final String TAG = "RecipeAdapter";
private List<Recipe> mRecipes = new ArrayList<>();
private LayoutInflater mInflater;
private Context mContext;
private MainActivity mainActivity = new MainActivity();
private static int backGroundIndex = 0;
class RecipeViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public final TextView recipeTitleItemView;
ImageView imageView;
public RecipeViewHolder(View itemView) {
super(itemView);
recipeTitleItemView = itemView.findViewById(R.id.name);
imageView = itemView.findViewById(R.id.card_image_view);
Log.d(TAG, "RecipeViewHolder: index " + backGroundIndex);
if (backGroundIndex == 0) {
imageView.setImageResource(R.drawable.background_green);
backGroundIndex++;
} else if (backGroundIndex == 1 ) {
imageView.setImageResource(R.drawable.background_red);
backGroundIndex++;
} else if (backGroundIndex == 2 ) {
imageView.setImageResource(R.drawable.background_blue);
backGroundIndex = 0;
}
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
int position = getAdapterPosition();
// This should be the mistake.
mainActivity.startKnownRecipeActivity(position);
}
}
public RecipeAdapter(Context context) {
mInflater = LayoutInflater.from(context);
this.mContext = context;
}
#NonNull
#Override
public RecipeAdapter.RecipeViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
// Inflate an item view
View mRecipeTitleView = mInflater.inflate(
R.layout.recipe_list_row, parent, false);
return new RecipeViewHolder(mRecipeTitleView);
}
// Get data into the corrsponding views
#Override
public void onBindViewHolder(RecipeAdapter.RecipeViewHolder holder, int position) {
Log.d(TAG, "onBindViewHolder: " + position);
Recipe currentRecipe = mRecipes.get(position);
Log.d(TAG, "onBindViewHolder: setText " + currentRecipe);
holder.recipeTitleItemView.setText(currentRecipe.getTitle());
}
#Override
public int getItemCount() {
return mRecipes.size();
}
public void setRecipes(List<Recipe> recipes) {
this.mRecipes = recipes;
Log.d(TAG, "setRecipes: notifydataChanged" );
notifyDataSetChanged();
}
}
MainActivity:
package com.example.fillmyplate.activities;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.media.Image;
import android.os.Build;
import android.os.Bundle;
import com.example.fillmyplate.R;
import com.example.fillmyplate.entitys.Recipe;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.cardview.widget.CardView;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
public static final String TAG = "MainAcitivity";
private static final int NEW_RECIPE_ACTIVITY_REQUEST_CODE = 1;
private RecyclerView mRecyclerView;
private RecipeViewModel mRecipeViewmodel;
private RecyclerView.LayoutManager layoutManager;
//private final List<String> mTitleList = new LinkedList<>();
//NEU for adapter
private List<String> recipeDataList = new ArrayList<>();
RecipeRoomDatabase db;
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// RECYCLER VIEW STUFF
mRecyclerView = findViewById(R.id.recycler_view1);
mRecyclerView.setHasFixedSize(true);
// user linerar layout manager
layoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(layoutManager);
// specify an adapter
final RecipeAdapter recipeAdapter = new RecipeAdapter(this);
//mAdapter = new RecipeAdapter(this, mTitleList);
mRecyclerView.setAdapter(recipeAdapter);
mRecipeViewmodel = ViewModelProviders.of(this).get(RecipeViewModel.class);
mRecipeViewmodel.getAllRecipes().observe(this, new Observer<List<Recipe>>() {
#Override
public void onChanged(List<Recipe> recipes) {
Log.d(TAG, "onChanged: " + recipes.toString());
for (Recipe rec : recipes) {
Log.d(TAG, "onChanged: " + rec.getTitle());
Log.d(TAG, "onChanged: recipe id " + rec.getUid());
}
recipeAdapter.setRecipes(recipes);
}
});
// DB
db = Room.databaseBuilder(getApplicationContext(), RecipeRoomDatabase.class, "appdb").build();
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, AddRecipeActivity.class);
startActivityForResult(intent, NEW_RECIPE_ACTIVITY_REQUEST_CODE);
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "onActivityResult: ");
if (requestCode == NEW_RECIPE_ACTIVITY_REQUEST_CODE && resultCode == RESULT_OK) {
Log.d(TAG, "onActivityResult: " + data.getStringExtra(AddRecipeActivity.EXTRA_REPLY));
// mTitleList.add(data.getStringExtra(AddRecipeActivity.EXTRA_REPLY));
Recipe rec = new Recipe(data.getStringExtra(AddRecipeActivity.EXTRA_REPLY));
mRecipeViewmodel.insert(rec);
} else {
Toast.makeText(
getApplicationContext(),
"saved",
Toast.LENGTH_LONG).show();
}
}
public void startKnownRecipeActivity(int position) {
Log.d(TAG, "startKnownRecipeActivity: Position " + position);
LiveData<List<Recipe>> recipe = mRecipeViewmodel.findById(position);
if (recipe.getValue().size() > 1) {
Log.d(TAG, "startKnownRecipeActivity: Error database found more than one recipe.");
} else {
Log.d(TAG, "startKnownRecipeActivity: Start activity with recipe " + recipe.getValue().get(0).getTitle());
}
}
}
The thing you need to do is to use a call back to send position back to activity.
To make sure that view position is correct you need to override 3 functions in RecyclerView Adapter:
#Override
public int getItemCount() {
return filteredUsers.size();
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
For the Callback just create an Interface:
public interface AdapterListener {
void onClick(int id);
void onClick(ViewModel object);
}
Make a method in your Recycler Adapter:
private AdapterListener adapterListener;
public void setAdapterListener(AdapterListener mCallback) {
this.adapterListener = mCallback;
}
Implement this Interface on your Activity then you will get both methods of the interface.
public class MainActivity extends AppCompatActivity implements AdapterListener{
Register the listener by calling the setAdapterListener method in your activity after the initialization of the RecyclerView
adapterObject.setAdapterListener(MainActivity.this);
Then the last thing you need to do is call interface method in your item onClickListener, where u can either pass the complete model or just the id of the model
adapterListener.onClick(modelObject.getId());
OR
adapterListener.onClick(modelObject);

How to fix "java.util.ArrayList cannot be cast to"

I have a problem with transfering data from retrofit to room. I downloaded data from the API but when i try getting data in room database I receive the error :
" Caused by: java.lang.ClassCastException: java.util.ArrayList cannot
be cast to".
Debug shows me on error in
newsDao.insert((News) news);
AND
.subscribe(new Consumer<List<News>>()
Here is my code.
import android.arch.persistence.room.Room;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import java.util.List;
import burtsev.a.k.news.Model.News;
import burtsev.a.k.news.Retrofit.NewsAPI;
import burtsev.a.k.news.Retrofit.RetrofitClient;
import burtsev.a.k.news.Room.NewsDao;
import burtsev.a.k.news.Room.NewsDatabase;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import retrofit2.Retrofit;
public class Splash extends AppCompatActivity {
public static Splash instance;
public NewsDatabase newsDatabase;
NewsAPI newsAPI;
CompositeDisposable compositeDisposable = new CompositeDisposable();
NewsDao newsDao;
public static Splash getInstance() {
return instance;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
newsDatabase = Room.databaseBuilder(getApplicationContext(),
NewsDatabase.class, "database")
.allowMainThreadQueries()
.build();
newsDao = newsDatabase.newsDao();
Retrofit retrofit = RetrofitClient.getInstance();
newsAPI = retrofit.create(NewsAPI.class);
fetchData();
}
private void fetchData() {
compositeDisposable.add(newsAPI.getNews().subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<News>>() {
#Override
public void accept(List<News> news) throws Exception {
Intent intent = new Intent(Splash.this, NewsListFragment.class);
// intent.putExtra("news", (Serializable) news);
newsDao.insert((News) news);
startActivity(intent);
}
}));
}
#Override
protected void onStop() {
compositeDisposable.clear();
super.onStop();
}
public NewsDatabase getNewsDatabase() {
return newsDatabase;
}
}
you are trying to insert list but, you are trying to cast it to an object.
so news is not a News model. it is a List<News>. If you want to insert all your news objects. you can try foreach or you can create a new function inside your DAO which will insert all list at once.
foreach;
for(News anews: news){
newsDao.insert(anews);
}
to insert at once. new function inside your DAO class should be;
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insertAllNews(List<News> news);
in your subscibe you need to use;
newsDao.insertAllNews(news);

Can anyone explain me the meaning of this part of the code "((MainActivity)getActivity()).someMethod()"?

I created a ListDialog extending a DialogFragment class and I have a problem with understanding of this code in the DijalogX class
((MainActivity)getActivity()).setTextField(selectedItem);
I understand that with this code above I put selected String variable to the setTextField method as an argument and after that this variable is showed in TextView on MainActivity class.
My questions:
Why I need a cast from getActivity() to the MainActivity and how I get access from DijalogX(fragment) to the method setTextField in MainActivity? Please explain a little about this process.
I also tried instead of ((MainActivity)getActivity()).setTextField(selectedItem)
use an Interface and everything works nice and I got the same resoult but I am wondering what is better solution here Interface or ((MainActivity)getActivity()).setTextField(selectedItem)?
MainActivity
package com.example.dezox.dijaloglist;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity{
private Button btnStartDialog;
private TextView tvSelectedOption;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initWidgets();
setupListener();
}
private void initWidgets() {
btnStartDialog = findViewById(R.id.btnDialog);
tvSelectedOption = findViewById(R.id.tvselectedOption);
}
private void setupListener() {
btnStartDialog.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DijalogX dijalogX = new DijalogX();
dijalogX.show(getSupportFragmentManager(), "dx");
tvSelectedOption.setText("");
}
});
}
public void setTextField(String odabrano){
tvSelectedOption.setText(odabrano);
}
public String getTextField(){
return tvSelectedOption.getText().toString();
}
}
DijalogX
package com.example.dezox.dijaloglist;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
public class DijalogX extends DialogFragment {
private String[] languageList;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initListResource();
}
private void initListResource() {
languageList = getResources().getStringArray(R.array.language_list);
}
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(),
android.R.style.Theme_Material_Dialog_Alert)
.setTitle("Select Language: ")
.setItems(languageList, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
String selectedItem = languageList[which];
//THIS PART OF THE CODE I DONT UNDERSTAND:
((MainActivity)getActivity()).setTextField(selectedItem);
}
});
return builder.create();
}
}
You have declared a method in MainActivity called setTextField. If you called
Activity a = getActivity();
you would not be able to call your custom method (it is on your derived class, not the base Activity class).
a.setTextField(selectedIte); // WON'T WORK - NO SUCH METHOD
If instead you call
MainActivity ma = (MainActivity)getActivity();
it is now cast as your derived class and you can then call
ma.setTextField(selectedItem);
Doing it in two lines like this is the same as calling the one-liner in your code
((MainActivity)getActivity()).setTextField(selectedItem);
As far as casting vs. an interface, an interface is a bit more flexible of an approach. If you tried to use this fragment in a different activity (not MainActivity) the casting approach would fail. If you are only ever going to use the fragment in this Activity then either would work.

LiveData fails to notify it's observer of changes in PagedList object

I have written this simple example to test paging library and observe changes to PagedList using LiveData but it notifies the observer only once, when the LiveData<PagedList<Integer>> object is created. I load more data using a button in my activity and pagedList object is loaded correctly but changes are not observed. here's the code for my activity:
import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.arch.paging.PagedList;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final MainViewModel mainViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
Button b = findViewById(R.id.button);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
PagedList<Integer> s = mainViewModel.getIntegers().getValue();
s.loadAround(s.size());
}
});
mainViewModel.setUpPaging(1);
mainViewModel.getIntegers().observe(this, new Observer<PagedList<Integer>>() {
#Override
public void onChanged(#Nullable PagedList<Integer> integers) {
//logging some text
Log.i("MyLog","new list Observed");
}
});
}
}
here's my ViewModel class:
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.ViewModel;
import android.arch.paging.LivePagedListBuilder;
import android.arch.paging.PagedList;
public class MainViewModel extends ViewModel {
LiveData<PagedList<Integer>> integers;
public LiveData<PagedList<Integer>> getIntegers() {
return integers;
}
public void setUpPaging(Integer startFrom){
integers = new LivePagedListBuilder<Integer,Integer>(IntegersDataSource.randomNumbersStartingFrom(startFrom),
new PagedList.Config.Builder()
.setPageSize(5)
.setEnablePlaceholders(false)
.build()).build();
}
}
and here's my DataSource which for simplicity only generate random integers :
import android.arch.paging.DataSource;
import android.arch.paging.PageKeyedDataSource;
import android.support.annotation.NonNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class IntegersDataSource extends PageKeyedDataSource<Integer,Integer> {
private Integer initialInt;
private final Integer BOUND = 300;
public IntegersDataSource(Integer initialInt) {
this.initialInt = initialInt;
}
#Override
public void loadInitial(#NonNull LoadInitialParams<Integer> params, #NonNull LoadInitialCallback<Integer, Integer> callback) {
Random r = new Random();
Integer i = r.nextInt(BOUND - 1) + 1;
List<Integer> l = new ArrayList<>();
l.add(i);
callback.onResult(l,initialInt-1, initialInt+1);
}
#Override
public void loadBefore(#NonNull LoadParams<Integer> params, #NonNull LoadCallback<Integer, Integer> callback) {
Random r = new Random();
Integer i = r.nextInt(BOUND - 1) + 1;
List<Integer> l = new ArrayList<>();
l.add(i);
callback.onResult(l, params.key-1);
}
#Override
public void loadAfter(#NonNull LoadParams<Integer> params, #NonNull LoadCallback<Integer, Integer> callback) {
Random r = new Random();
Integer i = r.nextInt(BOUND - 1) + 1;
List<Integer> l = new ArrayList<>();
l.add(i);
callback.onResult(l, params.key+1);
}
private static class RandomsFactory extends DataSource.Factory{
Integer srartFrom;
public RandomsFactory(Integer startFrom) {
this.srartFrom = startFrom;
}
#Override
public DataSource create() {
return new IntegersDataSource(srartFrom);
}
}
public static DataSource.Factory<Integer, Integer> randomNumbersStartingFrom(Integer startFrom) {
return new RandomsFactory(startFrom);
}
}
and this is in my build gradle :
implementation "android.arch.paging:runtime:1.0.0-rc1"
I keep pushing the button multiple times but only one time it is observed(for creation time).
PagedListAdapter doesn’t reflect changed item itself. To put it another way, PagedList is immutable. you should call invalidate() on the current DataSource when an update occurs. A new PagedList / DataSource pair will be created via LivePagedListBuilder and It will be passed through LiveData to observers when the current DataSource is invalidated.
Try this code.
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
PagedList<Integer> s = mainViewModel.getIntegers().getValue();
s.getDataSource().invalidate();
}
});
Please check out this demo app.
https://github.com/jungilhan/cheese-aac-paging-sample/tree/item_based_paging

Categories

Resources