Zhihu daily client -- look at the section every day

Keywords: Fragment JSON OkHttp Android

After reading this article, you should learn how to show the photo wall and save the pictures to the local place. design sketch:


The last one is about: The realization of Zhihu daily

Knowledge points of this article include: Okhttp, Picasso, CardView, dynamic request permission, create file, folder, save picture.

Layout first:


Material design, use CardView, use CardView remember to add

com.android.support:cardview-v7:27.0.2 dependency

Main code:

public class MeiriFragment extends Fragment {
    private final String TAG = "MeiriFragment";
    private RecyclerView mRecyclerView;
    private int cur = 1;
    private MeiriAdapter mMeiriAdapter;
    private boolean isFirstEnter = true;  //Whether the sign enters for the first time
    boolean isGettingPre = false;  //Identify whether the previous picture is being acquired
    boolean isEnd = false;  //Whether the logo is in the bottom picture
    private List<String> imgUrls;
    //  private ThumbnailDownloader<MeiriAdapter.MeiriHolder> mThumbnailDownloader;

    public static Fragment newInstance() {
        return new MeiriFragment();
    }

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == 0x123) {
                Log.d("MeiriFragment", "Handler Message received");
                String url = (String) msg.obj;
                Log.d("message===>", url);
            }
        }
    };

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mMeiriAdapter = new MeiriAdapter();
        AsyncTask<Object, Integer, List<String>> task = new AsyncTask<Object, Integer, List<String>>() {
            @Override
            protected List<String> doInBackground(Object... objects) {
                return Connect.getMeiriImgUrls(getActivity(), String.valueOf(cur));
            }

            @Override
            protected void onPostExecute(List<String> imgs) {
                super.onPostExecute(imgs);
                imgUrls = imgs;
                mRecyclerView.setAdapter(mMeiriAdapter);
            }
        };
        task.execute();
       /* Handler responseHandler = new Handler();
        mThumbnailDownloader = new ThumbnailDownloader<>(responseHandler);
        mThumbnailDownloader.setTThumbnailDownloadListener(new ThumbnailDownloader.ThumbnailDownloadListener<MeiriAdapter.MeiriHolder>() {
            @Override
            public void onThumbnailDownloaded(MeiriAdapter.MeiriHolder target, Bitmap thumbnail) {
             // target.mImageView.setImageBitmap(thumbnail);
            }
        });
        mThumbnailDownloader.start();
        mThumbnailDownloader.getLooper();
        Log.i(TAG,"background thread started");*/
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.wangyifragmennt, container, false);
        mRecyclerView = v.findViewById(R.id.recyler_view);
        final LinearLayoutManager manager = new LinearLayoutManager(getActivity());
        mRecyclerView.setLayoutManager(manager);
        BitmapFactory.Options options = new BitmapFactory.Options();
        //mBitmap = CalculateInSampleSize.decodeSampleBitmapFromRes(getResources(),R.drawable.wangyiimg,600,600);
        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                Log.i(TAG, "itemCount==> " + manager.getItemCount() + "\n current item position==> " + manager.findLastVisibleItemPosition());
                //  Log.i(TAG,"isEnd==> "+isEnd);

                if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset()
                        >= recyclerView.computeVerticalScrollRange() && isEnd) {
                    Toast.makeText(getActivity(), "No more pictures", Toast.LENGTH_SHORT).show();
                }


                if (isGettingPre) {
                    return;
                }
                if (manager.getItemCount() - manager.findLastVisibleItemPosition() < 3) {
                    final int preLength = imgUrls.size();
                    isGettingPre = true;
                    AsyncTask task = new AsyncTask() {
                        @Override
                        protected Object doInBackground(Object[] objects) {
                            return Connect.getPreMeiriUrls(String.valueOf(++cur));
                        }

                        @Override
                        protected void onPostExecute(Object o) {
                            super.onPostExecute(o);
                            imgUrls = (List<String>) o;
                            if (preLength == imgUrls.size()) {
                                isEnd = true;
                                return;
                            }
                            mMeiriAdapter.notifyDataSetChanged();
                            isGettingPre = false;
                        }
                    };
                    task.execute();
                }
            }
        });
        return v;
    }

    private class MeiriAdapter extends RecyclerView.Adapter {

        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View v = LayoutInflater.from(getActivity()).inflate(R.layout.meiri_layout, parent, false);
            return new MeiriHolder(v);
        }

        @Override
        public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
            //((MeiriHolder)holder).mImageView.setImageBitmap(mBitmap);
//            Message msg = mHandler.obtainMessage(0x123,imgUrls.get(position));
//            mHandler.sendMessage(msg);
            //  mThumbnailDownloader.queueThumbnail((MeiriHolder) holder,imgUrls.get(position));
            // Picasso.with(getActivity()).setIndicatorsEnabled(true); / / used to display where pictures are loaded [network, memory, disk]
            Picasso.with(getActivity()).load(Uri.parse(imgUrls.get(position))).fit().centerCrop().into(((MeiriHolder) holder).mImageView);
            /*
             * Why add fit() and centerCrop() here
             *
            */
            ((MeiriHolder) holder).mImageView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // Toast.makeText(getActivity(), "click photos", Toast.LENGTH_SHORT).show();
                    View view = LayoutInflater.from(getActivity()).inflate(R.layout.bigimg, null);
                    ImageView imageView = view.findViewById(R.id.img_container);
                    Log.i(TAG, "Got it URI yes==>: " + imgUrls.get(position));
                    Picasso.with(getActivity()).load(Uri.parse(imgUrls.get(position))).into(imageView);
                    AlertDialog dialog = new AlertDialog.Builder(getActivity(), R.style.Dialog_Fullscreen).setView(view)
                            .setPositiveButton("Preservation", null)
                            .setNegativeButton("Return", null).create();

                    //If. fit() and centerCrop() are added here, the image will not be displayed
                    imageView.setOnTouchListener(new OnDoubleClickListener(new OnDoubleClickListener.DoubleClickCallback() {
                        @Override
                        public void onDoubleClcik() {
                            saveImg(position);
                        }
                    }));

                    imageView.setOnLongClickListener(new View.OnLongClickListener() {
                        @Override
                        public boolean onLongClick(View v) {
                            Log.i(TAG, "url is ==> " + imgUrls.get(position));
                            saveImg(position);
                            return true;
                        }
                    });

                    dialog.show();
                    dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            //Toast.makeText(getActivity(), "save", Toast.LENGTH_SHORT).show();
                            saveImg(position);
                        }
                    });
                    if (isFirstEnter) {
                        Toast.makeText(getActivity(), "Long press pictures to save", Toast.LENGTH_SHORT).show();
                        isFirstEnter = false;
                    }

                }
            });
        }

        @Override
        public int getItemCount() {
            return imgUrls.size();
        }

        public class MeiriHolder extends RecyclerView.ViewHolder {
            public ImageView mImageView;

            public MeiriHolder(View itemView) {
                super(itemView);
                mImageView = itemView.findViewById(R.id.iv_meiri);
            }
        }

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // mThumbnailDownloader.clearQueue();
    }

    public void saveImg(final int position) {
        if (SaveImg.hasPermission(getActivity())) {
            Picasso.with(getActivity()).load(imgUrls.get(position)).into(new Target() {
                @Override
                public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                    Log.i(TAG, "load from==>" + from);
                    boolean hasSaved = SaveImg.saveImg(bitmap, "Take a look every day-" + String.valueOf(position) + ".jpeg", getActivity());
                    if (hasSaved) {
                        Toast.makeText(getActivity(), "Saved to album^.^", Toast.LENGTH_SHORT).show();
                    }
                }

                @Override
                public void onBitmapFailed(Drawable errorDrawable) {

                }

                @Override
                public void onPrepareLoad(Drawable placeHolderDrawable) {

                }
            });
        } else {
            Log.i(TAG,"No permission");
            requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
        }

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case 0: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(getActivity(), "Permission obtained,Pictures can be saved", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(getActivity(), "You have denied permission to write files. Unable to save the picture", Toast.LENGTH_SHORT).show();
                }
                return;
            }
        }
    }
}

Let's talk about the logic:

When creating a fragment, it will return the layout containing the CardView. In onCreate, first load the data online with AsyncTask. These data are returned in json format. At this time, I use JsonObject to parse, get the url of each image in json, and then put the url into a list collection, return, and set adapter,

The bindView in the adapter will display each sub item, and then use Picasso framework to obtain the image corresponding to the url and display it in the ImageView.

Picasso can be used in many ways. You can call Picasson.with(Context).load(url).fit().centerCrop().into(imageview)

Save picture:

Set listening for item. When clicking a sub item, a full screen dialog will pop up. When clicking save, you will check whether you can read and write sd card permission first. If you do not have permission, you will apply dynamically

My other blog has written:

Save bitmap to local

Dynamic request permission

ok...

Posted by adrafa on Thu, 30 Apr 2020 00:46:42 -0700