Android Retrofit, как загружать данные и загружать изображения независимо от вида переработчика - PullRequest
0 голосов
/ 07 июня 2018

Я использую Retrofit для загрузки данных из веб-API и отображения данных в программе просмотра.Вот мой макет:

Элемент представления переработчика:

 <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 в модель, поскольку предыдущий API возвращает данные и изображение.И я могу загрузить его легко для просмотра переработчика.Но это много времени загрузки.И затем, у меня есть 2 API получить данные и получить изображение независимо.Я хочу отображать данные раньше, и основной пользовательский интерфейс не блокируется при загрузке изображения в представление изображения. Я хочу прокручивать представление рециркулятора во время загрузки представления изображения (аналогично приложению facebook). Вот основные действия класса:

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();
}

}

А вот и результат с моим кодом. результат

но изображение отображается запутанно Итак, вы можете мне помочь?Ах, у него обычно есть ошибка "Android-приложение выполняет слишком много работы в своей основной ветке" Можете ли вы помочь мне решить ее?Большое спасибо !!

Ответы [ 2 ]

0 голосов
/ 07 июня 2018

Если я вас правильно понял, вы используете модификацию для загрузки изображения из сети.Вместо того, чтобы делать это самостоятельно, есть несколько популярных библиотек, предназначенных для обработки, загрузки и отображения изображений в приложении, предоставляя пользователю бесплатный поток пользовательского интерфейса и опыт.Эти библиотеки позволяют вам сосредоточиться на своей основной логике, а не на технических вещах, которые нужны каждому разработчику.Кроме того, поскольку они очень популярны, они менее глючные, чем то, что мы все могли бы написать сами, и с течением времени будут обновляться.Эти библиотеки включают, среди прочего, Пикассо, Глайд и Фреско.

Удачи!

0 голосов
/ 07 июня 2018

Как только вы получите ответ или URL-адрес изображения, любезно используйте библиотеку таким образом, чтобы он автоматически обрабатывал все сценарии.

, если вы получаете URL-адрес изображения в ответе в строке ниже:

showImage(response.body(),holder);

здесь, если response.body () содержит URL-адрес изображения

Заменить

 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;
}

}
...