I'm sure it's going to be a something very obvious that my stupid self couldn't find even after staring at the code for an hour.
I am trying to call the updateImages method in FragmentHome from HomeActivity. I have also created an instance of the class in onCreate but for reasons of my primitive coding knowledge, I am not able to call it. Any help would be greatly appreciated :)
Class that contains said method:
package com.example.youtubethumbnailapp;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.squareup.picasso.Picasso;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import static android.app.Activity.RESULT_OK;
public class FragmentHome extends Fragment {
private FragmentHomeListener listener;
public interface FragmentHomeListener{
void onInputHomeSent(ArrayList<Uri> input);
}
private ImageView video1;
private ImageView video2;
private ImageView video3;
private ImageView video4;
private ImageView video5;
private ImageView video6;
private ImageView video7;
private ImageView video8;
private ImageView video9;
private ImageView video10;
private ImageView addImageButton;
public Uri imageUri;
ArrayList<Uri> uriArrayList = new ArrayList<Uri>();
ArrayList<ImageView> imageViews = new ArrayList<ImageView>();
private int imagesSelected = 0;
#Nullable
#org.jetbrains.annotations.Nullable
#Override
public View onCreateView(#NonNull #org.jetbrains.annotations.NotNull LayoutInflater inflater, #Nullable #org.jetbrains.annotations.Nullable ViewGroup container, #Nullable #org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_home,container,false);
//initialize variables
video1 = v.findViewById(R.id.video1);
imageViews.add(video1);
video2 = v.findViewById(R.id.video2);
imageViews.add(video2);
video3 = v.findViewById(R.id.video3);
imageViews.add(video3);
video4 = v.findViewById(R.id.video4);
imageViews.add(video4);
video5 = v.findViewById(R.id.video5);
imageViews.add(video5);
video6 = v.findViewById(R.id.video6);
imageViews.add(video6);
video7 = v.findViewById(R.id.video7);
imageViews.add(video7);
video8 = v.findViewById(R.id.video8);
imageViews.add(video8);
video9 = v.findViewById(R.id.video9);
imageViews.add(video9);
video10 = v.findViewById(R.id.video10);
imageViews.add(video10);
addImageButton = v.findViewById(R.id.changeViewButton);
addImageButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
choosePicture();
}
});
return v;
}//end of onCreate
private void choosePicture() {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(intent, 1);
}
#Override
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode==1 && resultCode==RESULT_OK && null != data && data.getData()!=null){
imageUri = data.getData();
addPicture();
uriArrayList.add(imageUri);
imagesSelected++;
}
}
#Override
public void onAttach(#NonNull #NotNull Context context) {
super.onAttach(context);
if (context instanceof FragmentHomeListener){
listener = (FragmentHomeListener) context;
} else {
throw new RuntimeException(context.toString()
+ "must implement FragmentHomeListener");
}
}
#Override
public void onDetach() {
super.onDetach();
listener = null;
}
//this is the method I want to call
public void updateImages(ArrayList<Uri> imagesArrayList){
for (int i = 0; i < imagesArrayList.size(); i++){
Picasso.get()
.load(imagesArrayList.get(i))
.fit().centerCrop()
.into(imageViews.get(i));
}
}
private void addPicture(){
Picasso.get()
.load(imageUri)
.fit().centerCrop()
.into(imageViews.get(imagesSelected));
}
private void dataSent(){
listener.onInputHomeSent(uriArrayList);
}
}
Class where I want to call the method from:
package com.example.youtubethumbnailapp;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
public class HomeActivity extends AppCompatActivity implements FragmentHome.FragmentHomeListener, FragmentHistory.FragmentHistoryListener, FragmentSuggested.FragmentSuggestedListener {
private ImageView homeButton;
private ImageView historyButton;
private ImageView playButton;
private Fragment fragmentHome;
private Fragment fragmentHistory;
private Fragment fragmentSuggested;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
homeButton = findViewById(R.id.homeButton);
historyButton = findViewById(R.id.historyButton);
playButton = findViewById(R.id.playButton);
fragmentHome = new FragmentHome();
fragmentHistory = new FragmentHistory();
fragmentSuggested = new FragmentSuggested();
switchToFragmentHome();
homeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
switchToFragmentHome();
}
});
historyButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
switchToFragmentHistory();
}
});
playButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
switchToFragmentSuggested();
}
});
}//end of onCreate
public void switchToFragmentHome(){
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.flFragment, fragmentHome).commit();
}
public void switchToFragmentSuggested(){
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.flFragment, fragmentSuggested).commit();
}
public void switchToFragmentHistory(){
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.flFragment, fragmentHistory).commit();
}
#Override
public void onInputHistorySent(ArrayList<Uri> input) {
//I want to call it from here
}
#Override
public void onInputHomeSent(ArrayList<Uri> input) {
}
#Override
public void onInputSuggestedSent(ArrayList<Uri> input) {
}
}
Since I have instantiated the class, I tried fragmentHome.update but it doesn't show up.
you are creating new instance of fragment. Please check below code:
FragmentHome fragmentHome = new FragmentHome();
You should use it like this:
fragmentHome = new FragmentHome();
Currently, your updateImages method is part of an instance of the class FragmentHome. Since the method doesn't seem to depend on anything, e.g., state, you can make the method static as follows:
public static void updateImages(//args...){
// Your method here
}
Within HomeActivity, you can access this static inner method directly as:
FragmentHome.updateImages(//args...);
P.S.: At the moment, you are likely getting a Non-static method 'updateImages()' cannot be referenced from a static context error.
Note that creating and using updateImages() in this manner is not good practice. It is not "wrong", but it is not efficient in the long run and can cause bugs. (E.g., even if you just declared the method static, you'd likely get a NullPointerException because updateImages() contains a reference to imageViews, an object inside FragmentHome, which may not have been initialized when the method is called in HomeActivity.)
If possible, you should put the independent method updateImages() in a separate utilities class, such that your UI code is as separate from your logic code as possible. This is called "separation of concerns".
I see that you need to use Picasso to set a source image to an ImageView. To do this, you could pass in the ImageView as an argument into the method (disclaimer: if it makes sense for your use case; if it is not going to leak context; etc.), so that the updateImages() method doesn't contain a reference to the imageViews ArrayList that sits in your FragmentHome. Also note that imageViews is currently private, since you've not declared it public.
If you employ this method, your updateImages() or other methods can be reused with higher generality. But of course, there are cases where you just want a wrapper for a method you just can't make very generalized, and that's okay too.
Related
I have a pretty cool problem that I keep trying to figure out.
I have an Activity named Bill, it has a Textview and a RecyclerView. I plan to use textview to count the bills I have while recyclerView will show those bills.
But the problem is that in the adapter when I am processing the Viewholder data for the RecyclerView, it has a button to clear the Bill in case the customer returns or cancels the order.
And the problem is now I don't know how to setText for TextView, can anyone please answer this question for me? Thanks.
Here is the Bill activity i mention
package anhtuan.example.sample.feature;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.widget.TextView;
import java.util.ArrayList;
import anhtuan.example.sample.Bill.Bill_RecyclerView_Adapter;
import anhtuan.example.sample.DAO.DAO;
import anhtuan.example.sample.Model.BillModel;
import anhtuan.example.sample.R;
public class Bill extends AppCompatActivity {
TextView bill_total;
RecyclerView bill_RecyclerView;
ArrayList<BillModel>bills;
DAO dao;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bill);
setTitle("Bill");
bill_total = findViewById(R.id.bill_total);
bill_RecyclerView = findViewById(R.id.bill_recyclerView);
getSupportActionBar().hide();
bills=new ArrayList<>();
dao = new DAO(Bill.this);
bills= dao.getDSBill();
bill_total.setText("Bills: "+dao.CountBill());
Bill_RecyclerView_Adapter adapter = new Bill_RecyclerView_Adapter(bills,Bill.this,dao);
bill_RecyclerView.setLayoutManager(new LinearLayoutManager(Bill.this,RecyclerView.VERTICAL,false));
bill_RecyclerView.setAdapter(adapter);
}
}
bill_total is the textView i use to count the bill with the function in DAO class named CountBill()
public int CountBill(){
SQLiteDatabase database = sqLite.getReadableDatabase();
Cursor c = database.rawQuery("select * from bill ",new String[]{});
int sum = c.getCount();
c.close();
return sum;
}
And here is the RecyclerView Adapter
package anhtuan.example.sample.Bill;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import anhtuan.example.sample.DAO.DAO;
import anhtuan.example.sample.Model.BillModel;
import anhtuan.example.sample.R;
public class Bill_RecyclerView_Adapter extends RecyclerView.Adapter<Bill_RecyclerView_Viewholder> {
ArrayList<BillModel> bills;
Context context;
DAO dao;
public Bill_RecyclerView_Adapter(ArrayList<BillModel> bills, Context context, DAO dao) {
this.bills = bills;
this.context = context;
this.dao = dao;
}
#NonNull
#Override
public Bill_RecyclerView_Viewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.bill_viewholder,parent,false);
return new Bill_RecyclerView_Viewholder(view);
}
#Override
public void onBindViewHolder(#NonNull Bill_RecyclerView_Viewholder holder, int position) {
BillModel billModel;
billModel = bills.get(position);
holder.picture.setImageBitmap(billModel.BillBookPicture);
holder.name.setText(billModel.BillBookName);
holder.category.setText("Tag: "+billModel.BillBookCategory);
holder.date.setText("Date: "+billModel.BillDate);
holder.money.setText("Money: "+billModel.BillMoney);
holder.sale.setText("Sale: "+billModel.BillSale);
holder.totalSale.setText("Total: "+billModel.BillTotalSale);
holder.del.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dao.BillDel(billModel.id);
bills = dao.getDSBill();
notifyDataSetChanged();
}
});
}
#Override
public int getItemCount() {
return bills.size();
}
}
Thanks https://stackoverflow.com/users/20015640/urvish-shiroya recommend me about the interface callback, it kinda hard to understand clearly but i think i got a hand of it.
All i need to do here is to create an interface file named ViewUpdater then create a class interface in it:
public interface ViewUpdater {
void CallBack(TextView id);
}
Then create a void class to setText in Bill activity:
public void SetText(ViewUpdater view){
view.CallBack(bill_total);
}
Finally call it in the onBindViewHolder at the deleted button for it to automatic the Bill count after i delete a bill:
public void onBindViewHolder(#NonNull Bill_RecyclerView_Viewholder holder, int position) {
BillModel billModel;
billModel = bills.get(position);
holder.picture.setImageBitmap(billModel.BillBookPicture);
holder.name.setText(billModel.BillBookName);
holder.category.setText("Tag: "+billModel.BillBookCategory);
holder.date.setText("Date: "+billModel.BillDate);
holder.money.setText("Money: "+billModel.BillMoney);
holder.sale.setText("Sale: "+billModel.BillSale);
holder.totalSale.setText("Total: "+billModel.BillTotalSale);
holder.del.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dao.BillDel(billModel.id);
bills = dao.getDSBill();
((Bill)context).SetText(new ViewUpdater() {
#Override
public void CallBack(TextView id) {
id.setText("Bills: "+dao.CountBill()+"");
}
});
notifyDataSetChanged();
}
});
}
Hope this help with someone has the same problem
I try to create a Shopping/ToDoList application where the items are contained in SharedPreferences.
When I start the application, and I choose what I want to execute, Shopping list part or ToDoList part, then the java code fetches the existing data from the SharedPreferences and give to the RecycleView to create and show a list.
It seems works totally correct, but if I push the "add" button, then a new Activity is executed where I can specify the items, and when I click the save button, then the java code safe to the SharedPreferences and close the Activity and goes back to the "list" activity where the list should appears again with the new item. But when one data is inserted not in order in SharedPreferences but between two older data then the list create method get crazy and repeat always only the last data from SharedPreferences. But when I close the application, and restart, or goes back to the Main activity where I can choose again which list part I want then the list is totally OK again.
That is the list creating java code:
package com.example.recycleviewapp;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class ShoppingList extends AppCompatActivity implements MyRecyclerViewAdapter.ItemClickListener, View.OnClickListener {
public MyRecyclerViewAdapter adapter;
public Button btn;
public SharedPreferences sharedPreferences;
public SharedPreferences.Editor myEdit;
private List<String> items;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shoppinglist);
sharedPreferences = getSharedPreferences("ShoppingList", Context.MODE_PRIVATE);
myEdit = sharedPreferences.edit();
btn = findViewById(R.id.button);
items = new LinkedList<>();
StartDisplay();
RecyclerView recyclerView = findViewById(R.id.list);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new MyRecyclerViewAdapter(this,items);
adapter.setClickListener(this);
recyclerView.setAdapter(adapter);
btn.setOnClickListener(this);
}
#Override
public void onItemClick(View view, int position) {
//sharedPreferences = getSharedPreferences("ShoppingList", Context.MODE_PRIVATE);
String item_click =adapter.getItem(position);
String[] itemarray = item_click.split(" ",0);
//Toast.makeText(this, adapter.RemoveItem(position), Toast.LENGTH_SHORT).show();
//adapter.RemoveItem(position);
//myEdit = sharedPreferences.edit();
myEdit.remove(itemarray[0]);
myEdit.commit();
adapter.notifyItemRemoved(position);
items.remove(item_click);
}
#Override
public void onClick(View v) {
Intent NewSLItem = new Intent(ShoppingList.this, NewSLItem.class);
startActivity(NewSLItem);
}
#Override
public void onResume() {
super.onResume();
StartDisplay();
}
public void StartDisplay()
{
//sharedPreferences = getSharedPreferences("ShoppingList", Context.MODE_PRIVATE);
Map<String, ?> allEntries = sharedPreferences.getAll();
items.clear();
for (Map.Entry<String, ?> entry : allEntries.entrySet())
{
//Toast.makeText(this, entry.getKey(), Toast.LENGTH_SHORT).show();
String [] item_total = entry.getValue().toString().split(";");
items.add(entry.getKey() + " " + item_total[0] + " " + item_total[1]);
}
allEntries.clear();
}
}
Here is the code where I can specify the item:
package com.example.recycleviewapp;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class NewSLItem extends MainActivity {
private ArrayList<String> items;
private ArrayAdapter<String> itemsAdapter;
private ListView lvItems;
private Button btn;
public SharedPreferences sharedPreferences;
public SharedPreferences.Editor myEdit;
public List<String> list = new ArrayList<>();
public EditText etNewItem;
public String[] unit = {"liter", "kg", "pcs"};
public Spinner spinner;
public EditText amount;
public String itemName;
public TextView title;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shoppinglist_popup);
sharedPreferences = getSharedPreferences("ShoppingList", Context.MODE_PRIVATE);
myEdit = sharedPreferences.edit();
btn = (Button)findViewById(R.id.addbtn);
title = findViewById(R.id.title);
etNewItem = (EditText) findViewById(R.id.etNewItem);
amount = (EditText) findViewById(R.id.amount);
spinner = (Spinner) findViewById(R.id.spinner);
ArrayAdapter aa = new ArrayAdapter(this,android.R.layout.simple_spinner_item,unit);
aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(aa);
title.setText("Create a new item for ShoppingList");
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
onAddItem();
finish();
}
});
}
public void onAddItem()
{
//myEdit = sharedPreferences.edit();
itemName = etNewItem.getText().toString();
String itemValue = amount.getText().toString() + ";" + spinner.getSelectedItem().toString();
myEdit.putString(itemName,itemValue);
myEdit.commit();
etNewItem.setText("");
}
}
and here is the RecyclerView code:
package com.example.recycleviewapp;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {
private List<String> mData;
private LayoutInflater mInflater;
private ItemClickListener mClickListener;
MyRecyclerViewAdapter(Context context, List<String> data) {
this.mInflater = LayoutInflater.from(context);
this.mData = data;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.recyclerview_row, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
String meta_data = mData.get(position);
if (meta_data.contains("High")) holder.myTextView.setBackgroundColor(Color.parseColor("#FF003B"));
holder.myTextView.setText(meta_data);
}
#Override
public int getItemCount() {
return mData.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView myTextView;
ViewHolder(View itemView) {
super(itemView);
myTextView = itemView.findViewById(R.id.tvAnimalName);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view)
{
if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
}
}
String getItem(int id) {return mData.get(id);
}
void setClickListener(ItemClickListener itemClickListener) {
this.mClickListener = itemClickListener;
}
public interface ItemClickListener {
void onItemClick(View view, int position);
}
}
So the problem is in casef of only where the data is not in order in SharedPreferences and I go back from a new activity.
Please help me if you can, where should I fix my application?
Thanks in advance!!!
When you return to the list after adding an item, you reread all the items from the SharedPreferences in StartDisplay() (which is called from onResume(). This changes the data that the adapter is working with. However, you didn't tell the adapter that the data has changed. The adapter caches the Views and you must tell it when you modify the data, otherwise it doesn't know the data has changed. Add the following to StartDisplay() which will invalidate the adapter's cache and ensure that it rebuilds all the views:
adapter.notifyDataSetChanged()
Thank you for your help! It works.
But I noticed an other bug, what I would like to share.
The StartDisplay() function is earlier then where I define the adapter exactly so when I used the adapter.notifyDataSetChanged() then I got an exception as null object reference. So I put the function calling to the end of the initialization part and now everything is fine.
I'm trying to fetch data from an API and show the data into a recycler view. That API Contains an image URL and id. And I want to show the image from the URL and the id in the recycler view. But when I go to the Activity the recycler view is not showing the list. It is fetching the data from the API very well but it is not showing the data in the Recyclerview in a list format.
RecyclerviewAdapter.java
package com.madhulata.shriresume.shared;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.madhulata.shriresume.R;
import java.util.ArrayList;
public class RecyclerviewAdapter extends RecyclerView.Adapter<RecyclerviewAdapter.ViewHolder>{
private ArrayList<String> mImageNames;
private ArrayList<String> mId;
private Context mContext;
public RecyclerviewAdapter(ArrayList<String> mImageNames, ArrayList<String> mId, Context mContext) {
this.mImageNames = mImageNames;
this.mId = mId;
this.mContext = mContext;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.resume_format,parent,false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, final int position) {
Log.d("Recycler","on Bind Called");
Glide.with(mContext)
.asBitmap()
.load(mImageNames.get(position))
.into(holder.resumeImage);
holder.resumeId.setText(mId.get(position));
holder.constraintLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(mContext, mImageNames.get(position), Toast.LENGTH_SHORT).show();
}
});
}
#Override
public int getItemCount() {
return mImageNames.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
ImageView resumeImage;
TextView resumeId;
ConstraintLayout constraintLayout;
public ViewHolder(#NonNull View itemView) {
super(itemView);
resumeImage = itemView.findViewById(R.id.resumeLogo);
resumeId = itemView.findViewById(R.id.resumeId);
constraintLayout = itemView.findViewById(R.id.resumeTypeLayout);
}
}
}
***********************************SelectResume.java********************
package com.madhulata.shriresume.activity_dir;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.madhulata.shriresume.R;
import com.madhulata.shriresume.models.ResumeType;
import com.madhulata.shriresume.shared.RecyclerviewAdapter;
import com.madhulata.shriresume.shared.RetrofitClient;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class SelectResume extends AppCompatActivity {
RecyclerView selectResumeList;
private static final String TAG = "SignupActivity";
private ArrayList<String> mId;
private ArrayList<String> mUrls;
ProgressBar p;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_resume);
mId = new ArrayList<>();
mUrls = new ArrayList<>();
selectResumeList = findViewById(R.id.selectResumeList);
getResume();
}
private void initRecyclerView(){
Log.i("Value","init Recycler View");
RecyclerviewAdapter adapter = new RecyclerviewAdapter(mUrls,mId,this);
selectResumeList.setAdapter(adapter);
selectResumeList.setLayoutManager(new LinearLayoutManager(this));
}
private void getResume(){
Log.i("Value","Call method");
Call<List<ResumeType>> call = RetrofitClient.getInstance().getApi().getResume();
call.enqueue(new Callback<List<ResumeType>>() {
#Override
public void onResponse(Call<List<ResumeType>> call, Response<List<ResumeType>> response) {
if (!response.isSuccessful()){
Toast.makeText(SelectResume.this, response.code(), Toast.LENGTH_SHORT).show();
}else{
List<ResumeType> resume = response.body();
for (ResumeType r : resume){
mUrls.add(r.getUrl());
mId.add(r.getId());
Log.i("Value", mId.toString());
}
}
Log.i("Value","Call method 3");
}
#Override
public void onFailure(Call<List<ResumeType>> call, Throwable t) {
Toast.makeText(SelectResume.this, "Something went wrong!", Toast.LENGTH_SHORT).show();
}
});
initRecyclerView();
}
}
Why it is not showing?
Your initRecyclerView(); called before you update your data from the services. Retrofit callback works in a separate thread.
Try this instead of your method
private void getResume(){
Log.i("Value","Call method");
Call<List<ResumeType>> call = RetrofitClient.getInstance().getApi().getResume();
call.enqueue(new Callback<List<ResumeType>>() {
#Override
public void onResponse(Call<List<ResumeType>> call, Response<List<ResumeType>> response) {
if (!response.isSuccessful()){
Toast.makeText(SelectResume.this, response.code(), Toast.LENGTH_SHORT).show();
}else{
List<ResumeType> resume = response.body();
for (ResumeType r : resume){
mUrls.add(r.getUrl());
mId.add(r.getId());
Log.i("Value", mId.toString());
}
initRecyclerView();
}
Log.i("Value","Call method 3");
}
#Override
public void onFailure(Call<List<ResumeType>> call, Throwable t) {
Toast.makeText(SelectResume.this, "Something went wrong!", Toast.LENGTH_SHORT).show();
}
});
}
You can set adapter once at start in onCreate() even if your data is empty. You can add data later and call notifyDataSetChanged() on the adapter. The RecyclerView will be updated accordingly. This will save you from the overhead of setting adapter to RecyclerView each time you get some data.
public class SelectResume extends AppCompatActivity {
RecyclerView selectResumeList;
private static final String TAG = "SignupActivity";
private ArrayList<String> mId;
private ArrayList<String> mUrls;
ProgressBar p;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_resume);
mId = new ArrayList<>();
mUrls = new ArrayList<>();
selectResumeList = findViewById(R.id.selectResumeList);
initRecyclerView();
getResume();
}
private void initRecyclerView(){
Log.i("Value","init Recycler View");
RecyclerviewAdapter adapter = new RecyclerviewAdapter(mUrls, mId, this);
selectResumeList.setAdapter(adapter);
selectResumeList.setLayoutManager(new LinearLayoutManager(this));
}
private void getResume(){
Log.i("Value","Call method");
Call<List<ResumeType>> call = RetrofitClient.getInstance().getApi().getResume();
call.enqueue(new Callback<List<ResumeType>>() {
#Override
public void onResponse(Call<List<ResumeType>> call, Response<List<ResumeType>> response) {
if (!response.isSuccessful()) {
Toast.makeText(SelectResume.this, response.code(), Toast.LENGTH_SHORT).show();
} else {
List<ResumeType> resume = response.body();
for (ResumeType r : resume){
mUrls.add(r.getUrl());
mId.add(r.getId());
Log.i("Value", mId.toString());
}
adapter.notifyDataSetChanged();
}
Log.i("Value","Call method 3");
}
#Override
public void onFailure(Call<List<ResumeType>> call, Throwable t) {
Toast.makeText(SelectResume.this, "Something went wrong!", Toast.LENGTH_SHORT).show();
}
});
}
}
You receive the objects to show into RecyclerView from async network call. You need to update the adapter on the callback of your network call. Moreover I advice to initialize the adapter with empty list on the activity created, and after when you receive your data update the list with notifyDataSetChanged()
https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#notifyDataSetChanged()
Now I'm studying Threads and my task is to make a counter, which will add number from 0 to 9 to TextView with the help of Loader. Of course, I know that it isn't the best variant to use Loader for such tasks, but I'd like to understand how does it work.
So, I have the following code:
package asus.example.com.exercise4;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class LoaderActivity extends AppCompatActivity {
private TextView counter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_threads);
Button startButton = findViewById(R.id.start_button);
Button cancelButton = findViewById(R.id.cancel_button);
startButton.setOnClickListener(listener);
cancelButton.setOnClickListener(listener);
counter = findViewById(R.id.counter);
}
private View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.start_button:
getSupportLoaderManager().initLoader(0, null, new LoaderClass());
break;
case R.id.cancel_button:
break;
}
}
};
#SuppressLint("StaticFieldLeak")
class AsyncTaskLoaderClass extends AsyncTaskLoader<Void>{
AsyncTaskLoaderClass(#NonNull Context context) {
super(context);
}
#Nullable
#Override
public Void loadInBackground() {
for (int i = 0; i<10;i++){
counter.setText(i);
SystemClock.sleep(500);
}
return null;
}
}
private class LoaderClass implements LoaderManager.LoaderCallbacks<Void>{
#NonNull
#Override
public Loader<Void> onCreateLoader(int i, #Nullable Bundle bundle) {
return new LoaderActivity.AsyncTaskLoaderClass(LoaderActivity.this);
}
#SuppressLint("SetTextI18n")
#Override
public void onLoadFinished(#NonNull Loader<Void> loader, Void aVoid) {
counter.setText("Done!");
}
#Override
public void onLoaderReset(#NonNull Loader<Void> loader) {
}
}
}
When I run the project I have a runtime error:
java.lang.IllegalArgumentException: Object returned from onCreateLoader must not be a non-static inner member class: AsyncTaskLoaderClass{eed39bf id=0}
Yes, I understand, that it means that AsyncTaskLoaderClass should be in another file or static, but in such case I won't have an opportunity to add text to textview. So, how can I solve this problem?
UPD
I changed the code in clicking start button in such way:
case R.id.start_button:
Loader loader = getSupportLoaderManager().initLoader(0, null, LoaderActivity.this);
loader.forceLoad();
Log.i(TAG, "Button start clicked");
break;
And now each time in the loop I have the following error:
E/e.com.exercise: Invalid ID 0x00000009.
E/EventBus: Could not dispatch event: class asus.example.com.exercise4.LoaderActivity$MyAsyncTaskLoader$ProgressEvent to subscribing class class asus.example.com.exercise4.LoaderActivity
android.content.res.Resources$NotFoundException: String resource ID #0x9
UPD 2
Finally fixed the problem in the following way:
Was
counter.setText(i);
Now
counter.setText(""+i);
Probably I don't understrand why it works, but it works
Make the Activity implement LoaderCallbacks. Also a Loader retrieves one particular value in its onLoadFinished callback, and it should return the retrieved (loaded) item as a result.
To change what value is being loaded by a Loader, you're supposed to restart the loader with a new argument bundle, and pass in the parameters so that it knows what it is doing.
Then again, you are trying to create something like "publishProgress" in AsyncTask; Loaders cannot do that out of the box, and need some variant of "sending an event" (handler threads if you are adventurous, but most likely an event bus, see implementation 'org.greenrobot:eventbus:3.1.1').
TL;DR: use EventBus for this.
public class LoaderActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Void> {
private TextView counter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_threads);
Button startButton = findViewById(R.id.start_button);
Button cancelButton = findViewById(R.id.cancel_button);
counter = findViewById(R.id.counter);
startButton.setOnClickListener((view) -> {
getSupportLoaderManager().initLoader(0, null, LoaderActivity.this);
});
cancelButton.setOnClickListener((view) -> {
// do nothing, apparently
});
EventBus.getDefault().register(this);
}
#Override
protected void onDestroy() {
EventBus.getDefault().unregister(this);
super.onDestroy();
}
#Subscribe(threadMode = ThreadMode.MAIN)
public void onLoaderProgressEvent(MyAsyncTaskLoader.ProgressEvent event) {
counter.setText("" + event.getNumber());
}
#NonNull
#Override
public Loader<Void> onCreateLoader(int i, #Nullable Bundle bundle) {
return new MyAsyncTaskLoader(LoaderActivity.this);
}
#SuppressLint("SetTextI18n")
#Override
public void onLoadFinished(#NonNull Loader<Void> loader, Void aVoid) {
counter.setText("Done!");
}
#Override
public void onLoaderReset(#NonNull Loader<Void> loader) {
}
public static class MyAsyncTaskLoader extends AsyncTaskLoader<Void> {
public static class ProgressEvent {
private final int number;
public ProgressEvent(int number) {
this.number = number;
}
public int getNumber() { return number; }
}
public MyAsyncTaskLoader(#NonNull Context context) {
super(context);
}
#Nullable
#Override
public Void loadInBackground() {
for (int i = 0; i<10;i++){
EventBus.getDefault().post(new ProgressEvent(i));
SystemClock.sleep(500);
}
return null;
}
}
}
Your are using inner AsyncTaskLoaderClass in Activity class. Inner class holds the reference of Outer class. That means your AsyncTaskLoaderClass may hold Activity reference in some cases. Make your inner class static.
You have 2 solutions. Make AsyncTaskLoaderClass a separate class file or make AsyncTaskLoaderClass a static class.
make textview public static like this public static TextView counter;
I am trying to call another class using intent. But it is not working. I am using android studio to implement this project.
The app should show a screen with logos of popular brands like amazon, google, twitter, facebook, etc. When a logo is clicked, it shows another screen(activity), by calling AnotherActivity.java
Below is the class which seems to contain the problem:
package com.aquino.gridlayoutmanagerrecyclerview;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
public class ActivityMain extends AppCompatActivity {
RecyclerView rvMain;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rvMain = (RecyclerView) findViewById(R.id.rvMain);
Bitmap[] logos = new Bitmap[12];
logos[0] = BitmapFactory.decodeResource(getResources(),
R.drawable.medida2);
logos[1] = BitmapFactory.decodeResource(getResources(), R.drawable.logo_fb);
logos[2] = BitmapFactory.decodeResource(getResources(), R.drawable.logo_google);
logos[3] = BitmapFactory.decodeResource(getResources(), R.drawable.logo_insta);
logos[4] = BitmapFactory.decodeResource(getResources(), R.drawable.logo_linkedin);
logos[5] = BitmapFactory.decodeResource(getResources(), R.drawable.logo_microsoft);
logos[6] = BitmapFactory.decodeResource(getResources(), R.drawable.logo_myspace);
logos[7] = BitmapFactory.decodeResource(getResources(), R.drawable.logo_skype);
logos[8] = BitmapFactory.decodeResource(getResources(), R.drawable.logo_snapchat);
logos[9] = BitmapFactory.decodeResource(getResources(), R.drawable.logo_twitter);
logos[10] = BitmapFactory.decodeResource(getResources(), R.drawable.logo_viber);
logos[11] = BitmapFactory.decodeResource(getResources(), R.drawable.logo_whatsapp);
MyAdapter adapter = new MyAdapter(getResources().getStringArray(R.array.company_list), logos);
rvMain.setLayoutManager(new GridLayoutManager(ActivityMain.this, 2));
rvMain.setAdapter(adapter);
}//end of onCreate()
private class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
String[] companyList;
Bitmap[] logoList;
public MyAdapter(String[] companyList, Bitmap[] logoList) {
this.companyList = companyList;
this.logoList = logoList;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item, parent, false);
MyViewHolder viewHolder = new MyViewHolder(v);
return viewHolder;
}
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
holder.logo.setImageBitmap(logoList[position]);
holder.logo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(this, AnotherActivity.class);
startActivity(intent);
}
});
holder.name.setText(companyList[position]);
}
#Override
public int getItemCount() {
return companyList.length;
}
}//end of MyAdapter
private class MyViewHolder extends RecyclerView.ViewHolder{
public ImageView logo;
public TextView name;
public MyViewHolder(View itemView) {
super(itemView);
logo = (ImageView)itemView.findViewById(R.id.ivLogo);
name = (TextView)itemView.findViewById(R.id.tvCompany);
}
}//end of MyViewHolder
}
I cannot figure out why it is not working to add intent inside private class MyAdapter.
Any help is welcome
As per your code, all are fine. but in the private adapter, you will not get the context of the class directly by "this". so just replace code.
Intent intent = new Intent(ActivityMain.this, AnotherActivity.class);
startActivity(intent);
Im not sure what error you are getting.
good way to implement onclick in recyclerview is to create an interface.
implement the interface in the activity, create intent in the implemented method of interface in activity and call it in recyclerview
or use this :
Defining a RecyclerView's onCLickListener in an Activity