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:
ok...