This is the 15th day of my participation in the First Challenge 2022

Album Photo show

In ListView, the asynchronous batch image loading service uses the mechanism of round-the-clock task queue to complete the service

Modify interface to pass a parameter type, query general information, modify UrlFactory

public class UrlFactory {
    /** * url **@param keyword
     * @return json
     */
    public static String getNewMusicListUrl(String keyword) {
        String url = "Https://v2.alapi.cn/api/music/search?token= registered users center view token&keyword =" + keyword+"&type=1018";
        returnurl; }}Copy the code

View the returned JSON dataSince the return structure has changed, the corresponding entity class

public class MusicDataModel {
    public MusicSongModel song;
}

public class MusicSongModel {
    public List<MusicItem> songs;
}

public class MusicItem {
    public String id;
    public String name;
    public String albumName;
    public String albumPic;
    public AlbumModel al;
}

public class AlbumModel {
    public String name;
    public String picUrl;
}
Copy the code

Modify JsonParser

public class JsonParser {
    /** * Parses the XML content through the input stream using XMLPULL parsing **@param is
     * @return List<Music>
     */
    public static List<MusicItem> parseMusicList(InputStream is) throws IOException, JSONException {

        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
        String line = "";
        while((line = reader.readLine()) ! =null) {
            sb.append(line);
        }
        String json = sb.toString();
        JSONObject obj = new JSONObject(json);
        JSONObject data = obj.getJSONObject("data");
        JSONObject song = data.getJSONObject("song");
        JSONArray songs = song.getJSONArray("songs");

        List<MusicItem> list = new ArrayList<>();
        for (int i = 0; i < songs.length(); i++) {
            JSONObject s = songs.getJSONObject(i);
            String id = s.getString("id");
            String name = s.getString("name");
            MusicItem musicItem = new MusicItem();
            musicItem.id = id;
            musicItem.name = name;
            musicItem.albumName = s.getJSONObject("al").getString("name");
            musicItem.albumPic = s.getJSONObject("al").getString("picUrl");
            list.add(musicItem);
        }
        returnlist; }}Copy the code

Modify MusicAdapter

public class MusicAdapter extends BaseAdapter {
    private Context context;
    private List<MusicItem> musics;
    private LayoutInflater inflater;
    private List<ImageLoaderTask> tasks = new ArrayList<ImageLoaderTask>();
    private Thread workThread;
    private boolean isLoop = true;
    private ListView listView;
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case HANDLER_IMAGE_LOAD_SUCCESS:
                    // Set the bitmap for the corresponding Imageview
                    ImageLoaderTask task = (ImageLoaderTask) msg.obj;
                    Bitmap bitmap = task.bitmap;
                    ImageView imageView = (ImageView) listView.findViewWithTag(task.path);
                    if(imageView ! =null) {
                        if(bitmap ! =null) {
                            imageView.setImageBitmap(bitmap);
                        } else{ imageView.setImageResource(R.mipmap.ic_launcher); }}break; }}};public static final int HANDLER_IMAGE_LOAD_SUCCESS = 1;

    public MusicAdapter(Context context, List<MusicItem> musics, ListView listView) {
        super(context, musics);
        this.context = context;
        this.musics = musics;
        this.inflater = LayoutInflater.from(context);
        this.listView = listView;
        // Start the worker thread to cycle through the task set
        workThread = new Thread() {
            @Override
            public void run(a) {
                while (isLoop) {
                    if(! tasks.isEmpty()) {// Not an empty set
                        ImageLoaderTask task = tasks.remove(0);//remove returns the data at the same time
                        String url = task.path;
                        // Send an HTTP request to download the image
                        Bitmap bitmap = loadBitmap(url);
                        task.bitmap = bitmap;
                        // Update the interface and send a message to Handler
                        Message message = new Message();
                        message.what = HANDLER_IMAGE_LOAD_SUCCESS;
                        message.obj = task;
                        handler.sendMessage(message);

                    } else {// Empty set wait
                        try {
                            / / lock
                            synchronized(workThread) { workThread.wait(); }}catch(InterruptedException e) { e.printStackTrace(); }}}}}; workThread.start(); }/** ** Send an HTTP request to the url **@param url
     * @return* /
    private Bitmap loadBitmap(String url) {
        try {
            InputStream is = HttpUtils.getInputStream(url);
            Bitmap bitmap = BitmapFactory.decodeStream(is);
            return bitmap;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public int getCount(a) {
        return musics.size();
    }

    @Override
    public MusicItem getItem(int i) {
        return musics.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder holder = null;
        if (view == null) {
            view = inflater.inflate(R.layout.item_lv_music, null);
            holder = new ViewHolder();
            holder.imgPic = view.findViewById(R.id.img_Pic);
            holder.tvName = view.findViewById(R.id.tv_name);
            holder.tvAlbum = view.findViewById(R.id.tv_album);
            view.setTag(holder);
        }

        holder = (ViewHolder) view.getTag();
        // Assign a value to the control
        MusicItem music = getItem(i);
        holder.tvName.setText(music.name);
        holder.tvAlbum.setText(music.albumName);
        // The image is on the server. It should be displayed from the thread, but this is adapter.getView()
        // The phone will explode if I start the thread every time a picture is displayed.
        // Set the image to holder.imgpic
        // Download the task to an image in the task collection
        holder.imgPic.setTag(music.albumPic);
        ImageLoaderTask task = new ImageLoaderTask();
        task.path = music.albumPic;
        tasks.add(task);
        // Wake up the worker thread
        synchronized (workThread) {
            workThread.notify();
        }
        return view;
    }

    class ViewHolder {
        ImageView imgPic;
        TextView tvName;
        TextView tvAlbum;
    }

    class ImageLoaderTask {
        String path;// Save the image download path
        Bitmap bitmap;// Download the image successfully}}Copy the code

NewMusicListFrament is modified as follows

public void setAdapter(List<MusicItem> musics) {
        adapter = new MusicAdapter(getActivity(), musics, listView);
        listView.setAdapter(adapter);
    }
Copy the code

To run the program

Image compression

Common image formats: JPG: the most commonly used compression format with a high compression ratio, but does not support transparent colors. PNG: Supports transparent colors. GIF: supports dynamic images

Provides a utility class for compressing bitmap BitmapUtils

public class BitmapUtils {

    /** * Compress the image to get the corresponding size of the image **@paramIs Input stream *@paramWidth Target width *@paramHeight Target height *@return* /
    public static Bitmap loadBitmap(InputStream is, int width, int height) throws IOException {
        // parse is to read data into byte[]
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        // Read data from the input stream into bos
        byte[] buffer = new byte[1024 * 8];
        int length = 0;
        while((length = is.read(buffer)) ! = -1) {
            bos.write(buffer, 0, length);
            bos.flush();
        }
        // This byte array describes the complete information of an image
        byte[] bytes = bos.toByteArray();
        // Get the original size of the image
        BitmapFactory.Options options = new BitmapFactory.Options();
        // Only boundary attributes are loaded
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
        // Calculate the compression ratio according to the original size and width and height
        int w = options.outWidth / width;
        int h = options.outHeight / height;
        int scale = w > h ? w : h;
        // Perform compression
        options.inJustDecodeBounds = false;
        options.inSampleSize = scale;// Set the zoom scale
        Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
        returnbitmap; }}Copy the code

use

Bitmap bitmap = BitmapUtils.loadBitmap(is,5.5);
Copy the code

Apply to the previous project and modify the MusicAdapter loadBitmap method

private Bitmap loadBitmap(String url) {
        try {
            InputStream is = HttpUtils.getInputStream(url);
            Bitmap bitmap = BitmapUtils.loadBitmap(is,100.100);
            //Bitmap bitmap = BitmapFactory.decodeStream(is);
            return bitmap;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

Copy the code