I'm using Retrofit to load data from web api and display data to recyclerview. Here are my layout:
Item of recycler view:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="100"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
android:layout_weight="30"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:cardview="http://schemas.android.com/apk/res-auto"
cardview:cardCornerRadius="@dimen/cardview_corner_radius"
>
<ImageView
android:id="@+id/imgExhibit"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@drawable/img_no_image" />
</android.support.v7.widget.CardView>
<ProgressBar
android:id="@+id/viewProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminateDrawable="@drawable/my_progress"
android:visibility="gone"/>
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="70"
android:orientation="vertical"
android:weightSum="100">
<TextView
android:id="@+id/tvExhibitName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="10"
android:text="TRỐNG NHẠC"
android:textAppearance="@style/ExhibitNameMainscreen" />
<TextView
android:id="@+id/tvExhibitDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/ExhibitDescriptionMainscreen"
android:layout_weight="30"
android:ellipsize="end"
android:maxLines="2"
android:text="Trống nhạc là hiện vật do Toà thánh Ngọc Sắc trao tặng"
/>
</LinearLayout>
</LinearLayout>
Model is auto parse by http://www.jsonschema2pojo.org/ from api: http://demo.museum.vebrary.vn/api/Exhibit/GetPaging?pageindex=1&pagesize=10
public class ExhibitMainScreenModel {
@SerializedName("EXHID")
@Expose
private Integer eXHID;
@SerializedName("EXHIBITNAME")
@Expose
private String eXHIBITNAME;
@SerializedName("DESCRIPTION")
@Expose
private String dESCRIPTION;
public Integer getEXHID() {
return eXHID;
}
public void setEXHID(Integer eXHID) {
this.eXHID = eXHID;
}
public String getEXHIBITNAME() {
return eXHIBITNAME;
}
public void setEXHIBITNAME(String eXHIBITNAME) {
this.eXHIBITNAME = eXHIBITNAME;
}
public String getDESCRIPTION() {
return dESCRIPTION;
}
public void setDESCRIPTION(String dESCRIPTION) {
this.dESCRIPTION = dESCRIPTION;
}
}
and api http://demo.museum.vebrary.vn/api/Exhibit/GetImages?id=4 return one String of image by id
Previously, I used to add attribute String Image to Model because the previous api return both data and image. And I can load it easy to recycler view. But it toke many time loading. And then, I have 2 api get data and get image independent. I want to display data before, and UI main don't block by loading image to image view, I want to can scroll the recycler view while the image view loading (be like facebook app) Here are Main activity class:
public class MainActivityNew extends AppCompatActivity implements View.OnClickListener {
Toolbar toolbar;
RecyclerView recyclerView;
NavigationView navigationView;
DrawerLayout drawerLayout;
TextView tvTitleToolbar, txtTitleCategory;
//RecyclerView api
private ExhibitMainscreenRecyclerViewAdapter mAdapter;
private ApiService mService;
//ProgressDialog
private ProgressBar viewProgressBar;
private CustomProgressDialogTwo customProgressDialogTwo;
private LoadMoreProgressDialog loadMoreProgressDialog;
//load more
private int indexPage=1;
private int size=10;
private EndlessRecyclerViewScrollListener scrollListener;
//
int id;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_new);
//set transparent stt bar
//StatusBarUtil.setTransparent(this);
addControl();
actionBar();
showDataToRecyclerView();
showProgressDialog();
loadAnswers(indexPage,size);
showIntroMenu();
setPositionTextViewTittleCategogy();
addEvent();
}
public void showErrorMessage() {
Toast.makeText(MainActivityNew.this, "Error loading posts", Toast.LENGTH_SHORT).show();
}
private void showProgressDialog() {
viewProgressBar.setVisibility(View.GONE);
customProgressDialogTwo.show();
}
private void showLoadMoreProgressDialog(){
viewProgressBar.setVisibility(View.GONE);
loadMoreProgressDialog.show();
}
private void loadAnswers(int indexPage,int size) {
new Thread(new Runnable() {
@Override
public void run() {
mService.getExhibitByPage(indexPage,size).enqueue(new Callback<AllExhibitJsonResponse>() {
@Override
public void onResponse(Call<AllExhibitJsonResponse> call, Response<AllExhibitJsonResponse> response) {
if(response.isSuccessful()) {
customProgressDialogTwo.dismiss();
mAdapter.updateAnswers(response.body().getExhibitModels());
Log.d("AnswersPresenter", "posts loaded from API");
}else {
int statusCode = response.code();
Toast.makeText(MainActivityNew.this, "Error"+statusCode+response.message(), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<AllExhibitJsonResponse> call, Throwable t) {
showErrorMessage();
Log.d("AnswersPresenter", "error loading from API");
}
});
}
}).start();
}
private void showDataToRecyclerView() {
mAdapter = new ExhibitMainscreenRecyclerViewAdapter(this, new ArrayList<ExhibitMainScreenModel>(0), new ExhibitMainscreenRecyclerViewAdapter.PostItemListener() {
@Override
public void onPostClick(long id) {
startDetailActivity((int)id);
}
});
/*RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);*/
GridLayoutManager layoutManager = new GridLayoutManager(this, 2);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(mAdapter);
recyclerView.setHasFixedSize(true);
EndlessRecyclerViewScrollListener scrollListener = new EndlessRecyclerViewScrollListener(layoutManager) {
@Override
public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
showLoadMoreProgressDialog();
loadMoreAnswers(page,size);
}
};
recyclerView.addOnScrollListener(scrollListener);
}
private void loadMoreAnswers(int i, int size) {
new Thread(new Runnable() {
@Override
public void run() {
mService.getExhibitByPage(i+1,size).enqueue(new Callback<AllExhibitJsonResponse>() {
@Override
public void onResponse(Call<AllExhibitJsonResponse> call, Response<AllExhibitJsonResponse> response) {
if(response.isSuccessful()) {
loadMoreProgressDialog.dismiss();
mAdapter.updateMoreAnswers(response.body().getExhibitModels());
Log.d("AnswersPresenter", "posts loaded from API");
}else {
int statusCode = response.code();
Toast.makeText(MainActivityNew.this, "Error"+statusCode+response.message(), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<AllExhibitJsonResponse> call, Throwable t) {
showErrorMessage();
Log.d("AnswersPresenter", "error loading from API");
}
});
}
}).start();
}
And the adapter:
public class ExhibitMainscreenRecyclerViewAdapter extends RecyclerView.Adapter<ExhibitMainscreenRecyclerViewAdapter.ViewHolder> {
private List<ExhibitMainScreenModel> ExhibitList;
private Context mContext;
private PostItemListener mItemListener;
private int id;
//web api
private ApiService mService;
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
public TextView tvName,tvDescription;
public ImageView imvExhibit;
PostItemListener mItemListener;
public ViewHolder(View itemView, PostItemListener postItemListener) {
super(itemView);
tvName = itemView.findViewById(R.id.tvExhibitName);
tvDescription = itemView.findViewById(R.id.tvExhibitDescription);
imvExhibit=itemView.findViewById(R.id.imgExhibit);
this.mItemListener = postItemListener;
itemView.setOnClickListener(this);
}
@Override
public void onClick(View view) {
ExhibitMainScreenModel item = getItem(getAdapterPosition());
this.mItemListener.onPostClick(item.getEXHID());
notifyDataSetChanged();
}
}
public ExhibitMainscreenRecyclerViewAdapter(Context context, List<ExhibitMainScreenModel> posts, PostItemListener itemListener) {
ExhibitList = posts;
mContext = context;
mItemListener = itemListener;
}
@Override
public ExhibitMainscreenRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View postView = inflater.inflate(R.layout.item_recyclerview_mainscreen, parent, false);
ViewHolder viewHolder = new ViewHolder(postView, this.mItemListener);
//web api
mService = ApiUtils.getSOService();
return viewHolder;
}
@Override
public void onBindViewHolder(ExhibitMainscreenRecyclerViewAdapter.ViewHolder holder, int position) {
ExhibitMainScreenModel item = ExhibitList.get(position);
TextView tvName = holder.tvName;
tvName.setText(item.getEXHIBITNAME());
TextView tvDesc = holder.tvDescription;
tvDesc.setText(item.getDESCRIPTION());
//
id = item.getEXHID();
loadImage(id,holder);
}
private void loadImage(int id, ViewHolder holder) {
new Thread(new Runnable() {
@Override
public void run() {
//get image default
mService.getExhibitImageById(id, true).enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
if (response.isSuccessful()) {
try{
showImage(response.body(),holder);
Log.d("AnswersPresenter", "Image loaded!!!!");
}
catch (Exception e)
{
e.printStackTrace();
}
} else {
int statusCode = response.code();
Toast.makeText(mContext, "Error" + statusCode + response.message(), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<String> call, Throwable t) {
showErrorMessage();
Log.d("AnswersPresenter", "error loading image!!!");
}
});
}
}).run();
}
@Override
public int getItemCount() {
return ExhibitList.size();
}
public void updateAnswers(List<ExhibitMainScreenModel> items) {
ExhibitList = items;
notifyDataSetChanged();
}
public void updateMoreAnswers(List<ExhibitMainScreenModel> items) {
ExhibitList.addAll(items);
notifyDataSetChanged();
}
private ExhibitMainScreenModel getItem(int adapterPosition) {
return ExhibitList.get(adapterPosition);
}
public interface PostItemListener {
void onPostClick(long id);
}
private void showImage(String imageString, ViewHolder holder) {
Bitmap bmp = Util.StringToBitMap(imageString);
ImageView imv = holder.imvExhibit;
imv.setImageBitmap(bmp);
}
public void showErrorMessage() {
Toast.makeText(mContext, "Error loading posts", Toast.LENGTH_SHORT).show();
}
}
And here is result with my code. result
but the image is display intricate So, can you help me? Ah, It usually have error "android application doing too much work on its main thread" Can you help me solve it? Thank you very much!!