When the method(Bill) is called the widgets that I initialized with Butterknife is returning null(noPrev and recyclerList).
In other classes like activities, I used the same method(Binding the widget with BUtterknife) and It is working well but when I tried binding my widgets inside the fragment, it always returning null.
........................................................................
public class Home extends Fragment implements BridgeInterface.BillsResponse{
#BindView(R.id.rvBillList)
RecyclerView recyclerList;
#BindView(R.id.tvNoPreviousBill)
TextView noPrev;
public List<Bill> list_of_bill = new ArrayList<>();
private BillRecyclerAdapter adapter;
private Handler h;
private Runnable r;
private View v;
public Home() {
// Required empty public constructor
}
public static Home getInstance() {
Home home = new Home();
return home;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v = inflater.inflate(R.layout.fragment_home, container, false);
ButterKnife.bind(Home.this,v);
if(list_of_bill.size()==0){
noPrev.setVisibility(View.VISIBLE);
recyclerList.setVisibility(View.GONE);
} else{
noPrev.setVisibility(View.GONE);
recyclerList.setVisibility(View.VISIBLE);
}
return v;
}
#Override
public void onResume() {
super.onResume();
h = new Handler();
r = () -> {
BridgeInterface.GetBIlls getBIlls =
new BillsRequest(getContext());
getBIlls.request();
h.postDelayed(r,5000);
};
r.run();
}
#Override
public void Bill(List<Bill> bills) {
list_of_bill = bills;
initRecycler();
}
public void initRecycler() {
noPrev.setVisibility(View.GONE);
recyclerList.setVisibility(View.VISIBLE);
adapter = new BillRecyclerAdapter(list_of_bill);
recyclerList.setAdapter(adapter);
recyclerList.setLayoutManager(new LinearLayoutManager(getContext()));
}
}
Here's the Interface Class
public interface BridgeInterface {
interface BillsResponse{
void Bill(List<Bill> bills);
}
interface GetBIlls{
void request();
}
}
BillRequest Class;:::
public class BillsRequest implements BridgeInterface.GetBIlls {
private Context context;
private final String url = "http://"+
AppSingleton.getInstance().getIP_ADDRESS()
+"/waterdistrict/bills.php";
private Gson gson;
public BillsRequest(Context context ) {
this.context = context;
}
#Override
public void request() {
StringRequest request = new StringRequest(Request.Method.GET, url,
response -> {
gson = new GsonBuilder().create();
List<BillResponse> bill_response =
Arrays.asList(gson.fromJson(response,
BillResponse.class));
Log.d("Check", "Levl 2");
Home.getInstance().Bill(bill_response.get(0).getBills());
}, error -> {
Log.d("Error", error.toString());
});
RequestQueue queue = Volley.newRequestQueue(context);
queue.add(request);
}
}
Related
I want to create savedInstanceState that will save/keep data when display is rotating landscape or portrait, but it keep crashing when i try to rotate the display, and showing error "on a null object reference,
Here is some code for my Adapter :
public class ListMovieAdapter extends RecyclerView.Adapter<ListMovieAdapter.CardViewViewHolder> {
Context context;
ArrayList<Movie.ResultsBean> listMovie;
ProgressDialog progressBar;
public ListMovieAdapter(Context context, ArrayList<Movie.ResultsBean> listMovie) {
this.listMovie = listMovie;
this.context = context;
progressBar = new ProgressDialog(this.context);
}
public ArrayList<Movie.ResultsBean> getListMovie() {
return listMovie;
}
public void setListMovie(ArrayList<Movie.ResultsBean> movieList) {
this.listMovie = movieList;
notifyDataSetChanged();
}
and here is some of my Fragment code :
public class MovieFragment extends Fragment {
View v;
private RecyclerView myrecyclerview;
private Parcelable mRecyclerState;
private ListMovieAdapter listMovieAdapter;
private ArrayList<Movie> listMovie = new ArrayList<>();
private MutableLiveData<ArrayList<Movie.ResultsBean>> dataMovies = new MutableLiveData<>();
private ProgressDialog progressBar;
public static String BASE_URL = "https://api.themoviedb.org";
public static String CATEGORY = "upcoming";
public static int PAGE = 1;
public static String API_KEY = "ce7feeb6af94d9372180d04db1bc755d";
public static String LANGUAGE = "en-US";
private static final String SAVEINSTANCE_RECYCLERSTATE = "RecyclerState";
private static final String SAVEINSTANCE_LIST = "movielist";
public MovieFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, #Nullable Bundle savedInstanceState) {
v = inflater.inflate(R.layout.fragment_movie, viewGroup, false);
myrecyclerview = v.findViewById(R.id.rv_fragmovie);
myrecyclerview.setLayoutManager(new LinearLayoutManager(getActivity()));
progressBar = new ProgressDialog(getContext());
if (savedInstanceState == null) {
fetchJSON();
}else{
mRecyclerState = savedInstanceState.getParcelable(SAVEINSTANCE_RECYCLERSTATE);
listMovieAdapter.setListMovie((ArrayList)savedInstanceState.getParcelableArrayList(SAVEINSTANCE_LIST));
myrecyclerview.getLayoutManager().onRestoreInstanceState(mRecyclerState);
}
return v;
}
private void fetchJSON() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiInterface apiInterface = retrofit.create(ApiInterface.class);
Call<Movie> call = apiInterface.listOfMovie(CATEGORY, API_KEY, LANGUAGE, PAGE);
call.enqueue(new Callback<Movie>() {
#Override
public void onResponse(Call<Movie> call, Response<Movie> response) {
Movie results = response.body();
List<Movie.ResultsBean> listMovie = results.getResults();
ListMovieAdapter listMovieAdapter = new ListMovieAdapter(getContext(),
(ArrayList<Movie.ResultsBean>) listMovie);
myrecyclerview.setAdapter(listMovieAdapter);
}
#Override
public void onFailure(Call<Movie> call, Throwable t) {
showDialogLoad(false);
showDialogFail(true);
}
});
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
listMovie = new ArrayList<>();
}
#Override
public void onSaveInstanceState(Bundle outState) {
mRecyclerState = myrecyclerview.getLayoutManager().onSaveInstanceState();
outState.putParcelable(SAVEINSTANCE_RECYCLERSTATE,mRecyclerState);
outState.putParcelableArrayList(SAVEINSTANCE_LIST,(ArrayList<? extends Parcelable>) listMovieAdapter.getListMovie());
super.onSaveInstanceState(outState);
}
and then some error log :
java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.ArrayList com.ilham.mymoviecatalogue.adapter.ListMovieAdapter.getListMovie()' on a null object reference
at com.ilham.mymoviecatalogue.fragment.MovieFragment.onSaveInstanceState(MovieFragment.java:106)
Create a global variables
private static final String SCROLL_POSITION = "SCROLL_POSITION";
private RecyclerView movieGrid;
private GridLayoutManager layoutManager;
For onSaveInstanceState
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(SCROLL_POSITION, ((LinearLayoutManager)movieGrid.getLayoutManager()).findFirstVisibleItemPosition());
}
Then below that add:
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
final int position = savedInstanceState.getInt(SCROLL_POSITION);
movieGrid.postDelayed(new Runnable() {
public void run() {
movieGrid.scrollToPosition(position);
}
}, 300);
}
Note, the last number 300 should be adjusted accordingly, to test if it is returning to the position you were last in instead of resetting your position to the top upon rotation.
In my application I get some data from server and show into RecyslerView.
I can get data and fill adapter and show into RecyclerView, but I want write Test for this with Mockito Test and fill adapter for show into RecyclerView.
I use this link for json : https://api.learn2crack.com/android/jsonandroid/
I write below codes but I don't know how can I write Test for this.
My Activity class :
public class MainActivity extends AppCompatActivity {
private RecyclerView list;
private Context context;
private ApiServices apiServices;
private List<Android> model = new ArrayList<>();
private RecyclerAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
apiServices = ApiClient.getClient().create(ApiServices.class);
list = findViewById(R.id.list);
list.setLayoutManager(new LinearLayoutManager(context));
list.setHasFixedSize(true);
adapter = new RecyclerAdapter(model);
list.setAdapter(adapter);
Call<AndroidResponse> call = apiServices.getAndroid();
call.enqueue(new Callback<AndroidResponse>() {
#Override
public void onResponse(Call<AndroidResponse> call, Response<AndroidResponse> response) {
if (response.isSuccessful()) {
if (response.body() != null) {
model.clear();
model.addAll(response.body().getAndroid());
adapter.notifyDataSetChanged();
}
}
}
#Override
public void onFailure(Call<AndroidResponse> call, Throwable t) {
}
});
}
}
My Adapter class :
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
private List<Android> model;
public RecyclerAdapter(List<Android> model) {
this.model = model;
}
#NonNull
#Override
public RecyclerAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_list, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RecyclerAdapter.ViewHolder holder, int position) {
holder.name.setText(model.get(position).getName());
holder.version.setText(model.get(position).getVer());
holder.api.setText(model.get(position).getApi());
}
#Override
public int getItemCount() {
return model.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView name, version, api;
public ViewHolder(View itemView) {
super(itemView);
name = itemView.findViewById(R.id.rowName);
version = itemView.findViewById(R.id.rowVersion);
api = itemView.findViewById(R.id.rowApi);
}
}
}
My Test class :
#LargeTest
#RunWith(AndroidJUnit4.class)
public class MainActivityTest extends InstrumentationTestCase {
#Rule
public ActivityTestRule<MainActivity> mainActivityTestRule = new ActivityTestRule<>(MainActivity.class, true, false);
private MockWebServer mockWebServer;
#Before
public void setUp() throws Exception {
super.setUp();
mockWebServer = new MockWebServer();
mockWebServer.start();
injectInstrumentation(InstrumentationRegistry.getInstrumentation());
AppConstants.BASE_URL = mockWebServer.url("/").toString();
}
#Test
public void setupAndroidListAdapterTest() throws Exception {
String fileName = "android_list_response.json";
mockWebServer.enqueue(new MockResponse()
.setResponseCode(200)
.setBody(fileName));
Intent intent = new Intent();
mainActivityTestRule.launchActivity(intent);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#After
public void tearDown() throws Exception {
mockWebServer.shutdown();
}
}
I saved above json into asset folder.
I write above codes and when run test show me 1 test pass but not show me any data into recyclerView and adapter!
How can I do it?
Android add Paging Library as part of Architecture Component for using the pagination of the resource. I use this example for do it. I write these codes but in my DataSource.Factory I can't return my received DataSource from network. let's see my codes:
PostDataSource:
public class PostDataSource extends PageKeyedDataSource {
private final APIUtils api = RetrofitHelper.getInstance().create(APIUtils.class);
private final String TOKEN = TokenUtil.getCachedAuthToken();
private int page = 1;
private GeneralWebResult<ArrayList<Post>> postList;
#Override
public void loadInitial(#NonNull LoadInitialParams params, #NonNull LoadInitialCallback callback) {
api.getMainPosts("all",10,"new",page,TOKEN).enqueue(new Callback<GeneralWebResult<ArrayList<Post>>>() {
#Override
public void onResponse(Call<GeneralWebResult<ArrayList<Post>>> call, Response<GeneralWebResult<ArrayList<Post>>> response) {
postList = response.body();
callback.onResult(/*return ArrayList<Post> */postList.getResult(),null, ++ page);
Log.e("RESULT",response.code()+" ");
}
#Override
public void onFailure(Call<GeneralWebResult<ArrayList<Post>>> call, Throwable t) {
Log.e("ERROR",t.getLocalizedMessage());
}
});
}
#Override
public void loadBefore(#NonNull LoadParams params, #NonNull LoadCallback callback) {
}
#Override
public void loadAfter(#NonNull LoadParams params, #NonNull LoadCallback callback) {
ArrayList<Post> postList = new ArrayList<>();
api.getMainPosts("all",10,"new",page,TOKEN).enqueue(new Callback<GeneralWebResult<ArrayList<Post>>>() {
#Override
public void onResponse(Call<GeneralWebResult<ArrayList<Post>>> call, Response<GeneralWebResult<ArrayList<Post>>> response) {
postList.addAll(response.body().getResult());
callback.onResult(postList,null);
Log.e("RESULT",response.code()+" ");
}
#Override
public void onFailure(Call<GeneralWebResult<ArrayList<Post>>> call, Throwable t) {
Log.e("ERROR",t.getLocalizedMessage());
}
});
}
}
PostDataSourceFactory:
public class PostDataSourceFactory extends DataSource.Factory {
private PostDataSource dataSource;
#Override
public DataSource create() {
return new PostDataSource();
}
}
PostViewModel:
public class PostViewModel extends ViewModel {
public LiveData<PagedList<Post>> liveDataSource;
public PostViewModel() {
Executor executor = Executors.newFixedThreadPool(5);
PostDataSourceFactory factory = new PostDataSourceFactory(executor);
PagedList.Config config = new PagedList.Config.Builder().setEnablePlaceholders(false)
.setInitialLoadSizeHint(10).setPageSize(10).setPrefetchDistance(4).build();
liveDataSource = (new LivePagedListBuilder(factory,config)).setFetchExecutor(executor).build();
//Log.e("LIVE DATA SOURCE", liveDataSource.getValue().get(0).getContent());
}
}
PostAdapter:
public class PostAdapter extends PagedListAdapter<Post, PostAdapter.Holder> {
private PagedList<Post> items;
public void setItems(PagedList<Post> items) {
this.items = items;
}
public class Holder extends RecyclerView.ViewHolder{
TextView content;
Holder(View itemView) {
super(itemView);
content = itemView.findViewById(R.id.item_post_test_content);
}
void bindTo(Post post){
content.setText(post.getContent());
}
}
PostAdapter() {
super(Post.DiffCAllback);
}
#NonNull
#Override
public PostAdapter.Holder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new Holder(LayoutInflater.from(parent.getContext()).inflate(R.layout.post_test_item,parent,false));
}
#Override
public void onBindViewHolder(#NonNull PostAdapter.Holder holder, int position) {
holder.bindTo(getItem(position));
}
}
MainActivity:
list = findViewById(R.id.home_list);
list.setLayoutManager(new LinearLayoutManager(this));
PostViewModel viewModel = ViewModelProviders.of(this).get(PostViewModel.class);
PostAdapter adapter = new PostAdapter();
viewModel.liveDataSource.observe(this,items ->{
Log.e("ITEMS SIZE",items.size()+" ");
adapter.setItems(items);
} );
list.setAdapter(adapter);
Where is my mistake? why PostDataSourceFactory return null on create()?
Use a MutableLiveData object to wrap your data source
MutableLiveData is used for notifying your UI when observing any data
When using LivePagedListBuilder it is advisable to use a MutableLiveData as a wrapper for data source
See PagingWithNetworkSample
You also need to update your data source PagedKeyDataSource
public class PostDataSourceFactory extends DataSource.Factory<Integer, Post> {
public MutableLiveData<PostDataSource> datasourceLiveData = new MutableLiveData<>();
public PostDataSourceFactory(
}
#Override
public DataSource<Integer, Post> create() {
PostDataSource dataSource = new PostDataSource();
datasourceLiveData.postValue(dataSource);
return dataSource;
}
}
I am trying to set the data for recycler view to display from an AsyncTask. I am calling the method setdataEntries from the postExecute of inner class AsyncTask. But the android studio is showing me error could not find the method.
Adapter class
public class EntryAdapter extends RecyclerView.Adapter<EntryAdapter.ViewHolder> {
List<UserTuple> entries;
final private itemClickListener mOnClickListener;
public interface itemClickListener{
void onItemClick(UserTuple utuple);
}
public EntryAdapter(itemClickListener clickhandler) {
mOnClickListener = clickhandler;
}
public void setdataEntries(List<UserTuple> Data) {
entries = Data;
notifyDataSetChanged();
}
#Override
public EntryAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.singleusertuple,parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(EntryAdapter.ViewHolder holder, int position) {
holder.Username.setText(entries.get(position).getUsername());
holder.Password.setText(entries.get(position).getPassword());
}
#Override
public int getItemCount() {
return entries.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView Username;
private TextView Password;
private CardView card;
public ViewHolder(View itemView) {
super(itemView);
Username = itemView.findViewById(R.id.susername);
Password=itemView.findViewById(R.id.pass);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
int adapterPosition = getAdapterPosition();
UserTuple ut=new UserTuple(entries.get(adapterPosition).getUsername(),entries.get(adapterPosition).getPassword());
mOnClickListener.onItemClick(ut);
}
}
}
Calling Activity
public class Usertuple extends AppCompatActivity implements EntryAdapter.itemClickListener {
private RecyclerView recyclerView ;
private RecyclerView.Adapter adapater;
private SnapHelper snapHelper;
private List<UserTuple> entries;
private ProgressBar mLoadingIndicator;
private Bundle extras;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_logins);
extras = getIntent().getExtras();
//String site= extras.getString("sitename");
mLoadingIndicator = (ProgressBar) findViewById(R.id.pb_loading_indicator);
Log.i("Logins","Size of returned list "+entries.size());
recyclerView = findViewById(R.id.recycleview);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
adapater = new EntryAdapter(this);
recyclerView.setAdapter(adapater);
snapHelper= new LinearSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
dataView();
}
public void dataView() {
String site= extras.getString("sitename");
recyclerView.setVisibility(View.VISIBLE);
new FetchDataTask().execute(site);
}
#Override
public void onItemClick(UserTuple utuple) {
}
private String key(){
SharedPreferences sharedPref = getSharedPreferences(
"User", this.MODE_PRIVATE);
final String passphrase = sharedPref.getString("userid", "none");
return passphrase;
}
public void showerror(){
recyclerView.setVisibility(View.GONE);
Toast.makeText(this,"Error in retrieving",Toast.LENGTH_SHORT).show();
}
public setdata(List<UserTuple> data){
adapater.setdataEntries(data);
}
public class FetchDataTask extends AsyncTask<String, Void, List<UserTuple>> {
#Override
protected void onPreExecute() {
super.onPreExecute();
mLoadingIndicator.setVisibility(View.VISIBLE);
}
#Override
protected List<UserTuple> doInBackground(String... params) {
/* If there's no zip code, there's nothing to look up. */
if (params.length == 0) {
return null;
}
String site = params[0];
try {
AppDatabase db = Room.databaseBuilder(getApplicationContext(),AppDatabase.class, "production")
.build();
entries =db.entryDao().getSpecific(site);
for(UserTuple ut : entries){
Log.i("password",ut.getPassword());
String st = new Decryption().decrypt(ut.getPassword(),key());
Log.i("After decryption",st);
ut.setPassword(st);
}
return entries;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(List<UserTuple> Data) {
mLoadingIndicator.setVisibility(View.INVISIBLE);
if (Data != null) {
adapater.setdataEntries(Data);
} else {
showerror();
}
}
}
}
I want the database calls to be a background task. I don't want the activity to freeze waiting for database calls. Any ideas? Thanks
Declare adapter like
private EntryAdapter adapter;
instead of
private RecyclerView.Adapter adapater;
because RecyclerView.Adapter class does not have any method named setdataEntries but only EntryAdapter class has this method so only the object of type EntryAdapter can call setdataEntries method.
Or you can use down-casting as
((EntryAdapter)adapater).setdataEntries(data);
I have some trouwble with my custom class to get Data. I've created one custom class for get data from my web service, the issue comes when I try to use my singleton class, If I use DataReader.getInstance(getContext(), this) my listview is populated only the first time when app starts. But if I use a new instance of my DataReader work fine in anytime..
Here my DataReader Class:
public class DataReader {
private static DataReader singleton;
private Context context;
private Data_Listener data_listener;
public DataReader(Context context, Data_Listener data_listener) {
this.context = context;
this.data_listener = data_listener;
}
public static synchronized DataReader getInstance(Context context, Data_Listener data_listener) {
if (singleton == null) {
singleton = new DataReader(context, data_listener);
}
return singleton;
}
public void Categorias_fill(){
final ArrayList<Object> objects = new ArrayList<>();
API.getInstance(context).unAuthenticateArrayRequest(Request.Method.GET, context.getString(R.string.endpoint_categorias), null, new API_Listener() {
#Override
public void OnSuccess(JSONObject response) {
}
#Override
public void OnSuccess(JSONArray response) throws JSONException {
Gson gson = new Gson();
Categoria categoria;
for(int i = 0;i < response.length(); i++) {
categoria = gson.fromJson(response.getJSONObject(i).toString(), Categoria.class);
objects.add(categoria);
}
data_listener.onBindData(objects);
}
#Override
public void OnError(String error) {
data_listener.onBindData(objects);
}
});
}
and here how I used DataReader:
public class CategoriasFragment extends Fragment implements Data_Listener{
private Categorias_Adapter adapter;
private ArrayList<Categoria> list = new ArrayList<>();
private ExpandableListView listView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_categorias, container, false);
listView = (ExpandableListView) view.findViewById(R.id.exp_list);
listView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
#Override
public boolean onChildClick(ExpandableListView parent, View v,int groupPosition, int childPosition, long id) {
if(list.size()>0){
if(list.get(groupPosition).getSubCategorias().size()>0){
SubCategoria subCategoria = list.get(groupPosition).getSubCategorias().get(childPosition);
Log.d(General.appname, subCategoria.getNombre());
}
}
return true;
}
});
//This work only the first time
//DataReader.getInstance(getContext(), this).Categorias_fill();
//This work everytime
DataReader dataReader = new DataReader(getContext(), this);
dataReader.Categorias_fill();
return view;
}
#Override
public void onBindData(ArrayList<Object> objects) {
list = (ArrayList) objects;
adapter = new Categorias_Adapter(getContext(), list);
listView.setAdapter(adapter);
}
In subsequent calls to getInstance() your context and Data_Listener are not getting set. They'll still point to whatever they pointed to with the first call.
I suggest trying this: explicitly set DataReader.context and DataReader.data_listener inside your getInstance() method.