Android Retrofit如何加载数据并独立加载图像到回收站视图

时间:2018-06-07 13:13:33

标签: android image android-recyclerview retrofit

我使用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; 你能帮我解决一下吗?非常感谢!!

2 个答案:

答案 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线程和体验。 这些库让您专注于您的主要逻辑,而不是每个开发人员需要的技术。此外,因为它们非常受欢迎,所以它们比我们自己可能写的更少,并随着时间的推移不断更新。 这些图书馆包括毕加索,格莱德和弗雷斯科等。

祝你好运!