我使用Retrofit从web api加载数据并将数据显示到recyclerview。这是我的布局:
回收者视图项目:
<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>
模型由http://www.jsonschema2pojo.org/从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;
}
}
和api http://demo.museum.vebrary.vn/api/Exhibit/GetImages?id=4按ID返回一个图像字符串
以前,我曾经将属性String Image添加到Model,因为之前的api返回数据和图像。我可以轻松加载回收者视图。但它需要很多时间加载。 然后,我有2 api获取数据并获得图像独立。 我想在之前显示数据,并且UI主要不要通过将图像加载到图像视图来阻止,我想在图像视图加载时滚动回收器视图(就像facebook app) 这是主要活动类:
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();
}
适配器:
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();
}
}
这是我的代码的结果。 result
但图像显示错综复杂 那么,你能帮帮我吗? 啊,它通常有错误&#34; android应用程序在其主线程上做了太多工作&#34; 你能帮我解决一下吗?非常感谢!!
答案 0 :(得分:1)
一旦得到图像的响应或网址,请通过这种方式使用图书馆,它将自动处理所有场景。
如果您在下面一行的回复中获得了图片的网址:
showImage(response.body(),holder);
如果response.body()包含图像的网址
替换
Bitmap bmp = Util.StringToBitMap(imageString);
ImageView imv = holder.imvExhibit;
imv.setImageBitmap(bmp);
通过
Picasso.with(context).load(your image url).into(imageView);
如果您的回复是base64编码的。其中urlRes是您编码的响应,如: -
String urlRes = "XFLSVJpiqqVA3yQVy74obNAMCrajG1a5mvtgZBcXFK";
String data = new FileDecryption().decrypt(urlRes);
Log.e("MEssage decoded", data);
在项目中添加两个类。
Base64.java
public class Base64 {
/**
* encode
*
* coverts a byte array to a string populated with
* base64 digits. It steps through the byte array
* calling a helper method for each block of three
* input bytes
*
* @param raw The byte array to encode
* @return A string in base64 encoding
*/
public static String encode(byte[] raw) {
StringBuffer encoded = new StringBuffer();
for (int i = 0; i < raw.length; i += 3) {
encoded.append(encodeBlock(raw, i));
}
return encoded.toString();
}
/*
* encodeBlock
*
* creates 4 base64 digits from three bytes of input data.
* we use an integer, block, to hold the 24 bits of input data.
*
* @return An array of 4 characters
*/
protected static char[] encodeBlock(byte[] raw, int offset) {
int block = 0;
// how much space left in input byte array
int slack = raw.length - offset - 1;
// if there are fewer than 3 bytes in this block, calculate end
int end = (slack >= 2) ? 2 : slack;
// convert signed quantities into unsigned
for (int i = 0; i <= end; i++) {
byte b = raw[offset + i];
int neuter = (b < 0) ? b + 256 : b;
block += neuter << (8 * (2 - i));
}
// extract the base64 digits, which are six bit quantities.
char[] base64 = new char[4];
for (int i = 0; i < 4; i++) {
int sixbit = (block >>> (6 * (3 - i))) & 0x3f;
base64[i] = getChar(sixbit);
}
// pad return block if needed
if (slack < 1)
base64[2] = '=';
if (slack < 2)
base64[3] = '=';
// always returns an array of 4 characters
return base64;
}
/*
* getChar
*
* encapsulates the translation from six bit quantity
* to base64 digit
*/
protected static char getChar(int sixBit) {
if (sixBit >= 0 && sixBit <= 25)
return (char) ('A' + sixBit);
if (sixBit >= 26 && sixBit <= 51)
return (char) ('a' + (sixBit - 26));
if (sixBit >= 52 && sixBit <= 61)
return (char) ('0' + (sixBit - 52));
if (sixBit == 62)
return '+';
if (sixBit == 63)
return '/';
return '?';
}
/**
* decode
*
* convert a base64 string into an array of bytes.
*
* @param base64 A String of base64 digits to decode.
* @return A byte array containing the decoded value of
* the base64 input string
*/
public static byte[] decode(String base64) {
// how many padding digits?
int pad = 0;
for (int i = base64.length() - 1; base64.charAt(i) == '='; i--)
pad++;
// we know know the length of the target byte array.
int length = base64.length() * 6 / 8 - pad;
byte[] raw = new byte[length];
int rawIndex = 0;
// loop through the base64 value. A correctly formed
// base64 string always has a multiple of 4 characters.
for (int i = 0; i < base64.length(); i += 4) {
int block = (getValue(base64.charAt(i)) << 18)
+ (getValue(base64.charAt(i + 1)) << 12)
+ (getValue(base64.charAt(i + 2)) << 6)
+ (getValue(base64.charAt(i + 3)));
// based on the block, the byte array is filled with the
// appropriate 8 bit values
for (int j = 0; j < 3 && rawIndex + j < raw.length; j++)
raw[rawIndex + j] = (byte) ((block >> (8 * (2 - j))) & 0xff);
rawIndex += 3;
}
return raw;
}
/*
* getValue
*
* translates from base64 digits to their 6 bit value
*/
protected static int getValue(char c) {
if (c >= 'A' && c <= 'Z')
return c - 'A';
if (c >= 'a' && c <= 'z')
return c - 'a' + 26;
if (c >= '0' && c <= '9')
return c - '0' + 52;
if (c == '+')
return 62;
if (c == '/')
return 63;
if (c == '=')
return 0;
return -1;
}
}
,第二个是FileDecryption.java
public class FileDecryption {
private static final String ALGO = "AES";
private static final byte[] keyValue =
new byte[] { 'S', 'n', 'd', 'A', 'p', 'p','s','S', 'e', 'c', 'r','e', 't', 'K', 'e', 'y' };
public String decrypt(String encryptedData) {
//encryptedData="PDvLeKmmKUcUQd/zKZ5b2JPRCXHJwu4dVZhaZJCrRK4JRvBP3IhRpizk6qCLcaUmhoDGR+QUeS1fjHdWujZTGQ==";
String decryptedValue=null;
//int flags= Base64.NO_WRAP | Base64.URL_SAFE;
if("ON".equals("ON")){
try{
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.DECRYPT_MODE, key);
// byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
byte[] decordedValue = Base64.decode(encryptedData);
byte[] decValue = c.doFinal(decordedValue);
decryptedValue = new String(decValue);}
catch(Exception e){
e.printStackTrace();
}
}else{
decryptedValue=encryptedData;
}
//Log.d("decrypted : ", decryptedValue);
return decryptedValue;
}
private static Key generateKey() throws Exception {
Key key = new SecretKeySpec(keyValue, ALGO);
return key;
}
}
答案 1 :(得分:0)
如果我理解正确,您正在使用改造来从网络加载图像。除了自己动手之外,还有一些流行的库旨在处理,加载和显示应用程序中的图像,为用户提供免费的UI线程和体验。 这些库让您专注于您的主要逻辑,而不是每个开发人员需要的技术。此外,因为它们非常受欢迎,所以它们比我们自己可能写的更少,并随着时间的推移不断更新。 这些图书馆包括毕加索,格莱德和弗雷斯科等。
祝你好运!