Diycode开源项目 ImageActivity分析
1.首先看一下效果
1.1做成了一个GIF
1.2.我用格式工厂有点问题,大小无法调到手机这样的大小,目前还没有解决方案。
1.3.网上有免费的MP4->GIF,参考一下这个网站吧。
1.4.讲解一下这个图片吧,首先是从话题中点击了其中一张图片,进入图片Activity,
然后可以自由放大,自由翻转。
2.分析一下继承的BaseImageActivity
2.1因为ImageActivity继承了BaseImageActivtiy,首先看看源代码。
- /*
- * Copyright 2017 GcsSloop
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Last modified 2017-03-15 20:02:59
- *
- * GitHub: https://github.com/GcsSloop
- * Website: http://www.gcssloop.com
- * Weibo: http://weibo.com/GcsSloop
- */
- package com.gcssloop.diycode.base.app;
- import android.content.Intent;
- import java.util.ArrayList;
- /**
- * 对数据进行预处理
- */
- public abstract class BaseImageActivity extends BaseActivity {
- public static final String ALL_IMAGE_URLS = "all_images";
- public static final String CURRENT_IMAGE_URL = "current_image";
- protected static final String MODE_NORMAL = "normal";
- protected static final String MODE_ERROR = "error";
- protected String mCurrentMode = MODE_NORMAL;
- protected ArrayList<String> images = new ArrayList<>(); // 所有图片
- protected String current_image_url = null; // 当前图片
- protected int current_image_position = 0; // 当前图片位置
- @Override
- protected void initDatas() {
- super.initDatas();
- // 初始化图片 url 和 图片集合,保证两个数据都存在
- Intent intent = getIntent();
- // 没有传递当前图片,设置模式为错误
- String imageUrl = intent.getStringExtra(CURRENT_IMAGE_URL);
- if (imageUrl == null || imageUrl.isEmpty()) {
- toastShort("没有传递图片链接");
- mCurrentMode = MODE_ERROR;
- return;
- }
- mCurrentMode = MODE_NORMAL;
- ArrayList<String> temp = intent.getStringArrayListExtra(ALL_IMAGE_URLS);
- if (temp == null || temp.size() <= 0) {
- // 记录当前图片,计算位置
- images.clear();
- images.add(imageUrl);
- } else if (temp.size() > 0) {
- // 如果图片集合大于0
- images = new ArrayList<>(temp);
- }
- if (!images.contains(imageUrl)) {
- images.add(imageUrl);
- }
- current_image_url = imageUrl;
- current_image_position = images.indexOf(current_image_url);
- }
- }
2.2这里需要回顾一下BaseActivity。
BaseActivity==>主要提供了项目本身API提供的Diycode类,ViewHolder类,Toast类,两个抽象方法。ActionBar。结束
当前活动。
打开活动。
2.3.私有成员变量。
·存放图片链接的一个ArrayList<String>
·存放当前图片的链接current_image_url
·存放当前图片位置,整型current_image_positon
2.4.注意点,Override一个在基类中已经实现过的函数。
重载,也是可以Override的。以前理解的Override就是抽象方法,接口方法。这里又涨知识了。
如果写了一个父类中有的方法,就相当于重载了父类中的方法,就不会执行父类中的那个方法,而是执行自己的方法了。
名字是一样的。
2.5.在BaseActivity中写了一个空的initDatas方法。而且规定了这个方法执行的顺序。
然后在子类BaseImageActivity中重载这个方法。
这个类主要处理图片数据的。
2.6分析这个重载方法。
2.6.1首先从intent中获得当前图片,如果没有,设置模式为错误。否则,设置模式为正常。
2.6.2然后从intent中获得所有图片集合,如果没有,就把当前图片加进images去,如果有,就将集合加到一个images中。
2.6.3然后它还判断了一下images中是否包含了当前url,应该是双保险吧,感觉没必要。
2.6.4最后,就把当前图片和当前位置更新了一下。
3.分析一下图片缓存DiskImageCache
3.1首先看看在ImageActivity中定义的一个变量。DiskImageCache mCache;源代码如下:
- /*
- * Copyright 2017 GcsSloop
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Last modified 2017-03-12 00:56:52
- *
- * GitHub: https://github.com/GcsSloop
- * Website: http://www.gcssloop.com
- * Weibo: http://weibo.com/GcsSloop
- */
- package com.gcssloop.diycode.base.webview;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.os.Environment;
- import android.os.StatFs;
- import android.support.annotation.NonNull;
- import android.util.Log;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.OutputStream;
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- import java.util.Arrays;
- import java.util.Comparator;
- public class DiskImageCache {
- private static final String CACHE_SUFFIX = ".cache";
- private static final int MB = 1024 * 1024;
- private static final int CACHE_SIZE = 50; // 缓存占用空间大小
- private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 10; // 为 SD 卡保留多少空间
- private File cacheDir;
- public DiskImageCache(Context context) {
- cacheDir = getDiskCacheDir(context, "web-image");
- // 整理缓存
- organizeCache(cacheDir);
- }
- /**
- * 从缓存中获取图片
- **/
- public Bitmap getBitmap(final String key) {
- final String path = getCachePath(key);
- File file = new File(path);
- if (file.exists()) {
- Bitmap bmp = BitmapFactory.decodeFile(path);
- if (bmp == null) {
- file.delete();
- } else {
- updateFileTime(path);
- return bmp;
- }
- }
- return null;
- }
- /**
- * 将图片存入文件缓存
- **/
- public void saveBitmap(String key, Bitmap bm) {
- if (bm == null) {
- return;
- }
- //判断sdcard上的空间
- if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
- return; //SD空间不足
- }
- File file = new File(getCachePath(key));
- try {
- file.createNewFile();
- OutputStream outStream = new FileOutputStream(file);
- bm.compress(Bitmap.CompressFormat.PNG, 100, outStream);
- outStream.flush();
- outStream.close();
- } catch (FileNotFoundException e) {
- Log.w("ImageFileCache", "FileNotFoundException");
- } catch (IOException e) {
- Log.w("ImageFileCache", "IOException");
- }
- }
- /**
- * 保存 bytes 数据
- *
- * @param key url
- * @param bytes bytes 数据
- */
- public void saveBytes(String key, byte[] bytes) {
- if (bytes == null) {
- return;
- }
- //判断sdcard上的空间
- if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
- return; //SD空间不足
- }
- File file = new File(getCachePath(key));
- try {
- file.createNewFile();
- OutputStream outStream = new FileOutputStream(file);
- outStream.write(bytes);
- outStream.flush();
- outStream.close();
- } catch (FileNotFoundException e) {
- Log.w("ImageFileCache", "FileNotFoundException");
- } catch (IOException e) {
- Log.w("ImageFileCache", "IOException");
- }
- }
- /**
- * 获取一个本地缓存的输入流
- *
- * @param key url
- * @return FileInputStream
- */
- public FileInputStream getStream(String key) {
- File file = new File(getCachePath(key));
- if (!file.exists())
- return null;
- try {
- FileInputStream inputStream = new FileInputStream(file);
- return inputStream;
- } catch (FileNotFoundException e) {
- Log.e("getStream", "FileNotFoundException");
- e.printStackTrace();
- }
- return null;
- }
- /**
- * 获取本地缓存路径
- *
- * @param key url
- * @return 路径
- */
- public String getDiskPath(String key) {
- File file = new File(getCachePath(key));
- if (!file.exists())
- return null;
- return file.getAbsolutePath();
- }
- /**
- * 是否有缓存
- *
- * @param key url
- * @return 是否有缓存
- */
- public boolean hasCache(String key) {
- File file = new File(getCachePath(key));
- return file.exists();
- }
- /**
- * 计算存储目录下的文件大小,
- * 当文件总大小大于规定的CACHE_SIZE或者sdcard剩余空间小于FREE_SD_SPACE_NEEDED_TO_CACHE的规定
- * 那么删除40%最近没有被使用的文件
- */
- private boolean organizeCache(@NonNull File cacheDir) {
- File[] files = cacheDir.listFiles();
- if (files == null) {
- return true;
- }
- if (!Environment.getExternalStorageState().equals(
- Environment.MEDIA_MOUNTED)) {
- return false;
- }
- int dirSize = 0;
- for (int i = 0; i < files.length; i++) {
- if (files[i].getName().contains(CACHE_SUFFIX)) {
- dirSize += files[i].length();
- }
- }
- if (dirSize > CACHE_SIZE * MB || FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
- int removeFactor = (int) ((0.4 * files.length) + 1);
- Arrays.sort(files, new FileLastModifSort());
- for (int i = 0; i < removeFactor; i++) {
- if (files[i].getName().contains(CACHE_SUFFIX)) {
- files[i].delete();
- }
- }
- }
- if (freeSpaceOnSd() <= CACHE_SIZE) {
- return false;
- }
- return true;
- }
- /**
- * 修改文件的最后修改时间
- **/
- public void updateFileTime(String path) {
- File file = new File(path);
- long newModifiedTime = System.currentTimeMillis();
- file.setLastModified(newModifiedTime);
- }
- /**
- * 计算sdcard上的剩余空间
- **/
- private int freeSpaceOnSd() {
- StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
- double sdFreeMB = ((double) stat.getAvailableBlocks() * (double) stat.getBlockSize()) / MB;
- return (int) sdFreeMB;
- }
- /**
- * 根据文件的最后修改时间进行排序
- */
- private class FileLastModifSort implements Comparator<File> {
- public int compare(File arg0, File arg1) {
- if (arg0.lastModified() > arg1.lastModified()) {
- return 1;
- } else if (arg0.lastModified() == arg1.lastModified()) {
- return 0;
- } else {
- return -1;
- }
- }
- }
- /**
- * 获取缓存文件的绝对路径
- */
- private String getCachePath(String key) {
- return cacheDir.getAbsolutePath() + File.separator + convertKey(key);
- }
- /**
- * 获取磁盘缓存文件夹 优先获取外置磁盘
- *
- * @param context 上下文
- * @param uniqueName 自定义名字
- */
- public File getDiskCacheDir(Context context, String uniqueName) {
- String cachePath;
- if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
- || !Environment.isExternalStorageRemovable()) {
- cachePath = context.getExternalCacheDir().getPath();
- } else {
- cachePath = context.getCacheDir().getPath();
- }
- File cacheDir = new File(cachePath + File.separator + uniqueName);
- if (!cacheDir.exists())
- cacheDir.mkdir();
- return cacheDir;
- }
- /**
- * 哈希编码
- */
- public String convertKey(String key) {
- String cacheKey;
- try {
- final MessageDigest mDigest = MessageDigest.getInstance("MD5");
- mDigest.update(key.getBytes());
- cacheKey = bytesToHexString(mDigest.digest());
- } catch (NoSuchAlgorithmException e) {
- cacheKey = String.valueOf(key.hashCode());
- }
- return cacheKey + CACHE_SUFFIX;
- }
- private String bytesToHexString(byte[] bytes) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < bytes.length; i++) {
- String hex = Integer.toHexString(0xFF & bytes[i]);
- if (hex.length() == 1) {
- sb.append('0');
- }
- sb.append(hex);
- }
- return sb.toString();
- }
- }
3.2定义的常量及变量预览。
3.3.构造函数就一个。实现方法在后面。
3.4.如何从缓存中获取图片(通过一个String返回一个Bitmap),这个项目暂时没有用到。
3.5.如何将图片存入文件缓存?(将一个bitmap,存放一个缓存路径为一个key下)
3.6.如何保存bytes数据?(也是存放到一个key中)
3.7.如何获取一个本地缓存的输入流?(通过一个key获得FileInputStream)
3.8.如何获取本地缓存路径?(通过一个key得到一个String)
3.9.如何判断是否有缓存?(通过一个key返回boolean)
3.10.然后是关键的整理存储空间了。这个删除文件很关键,不然数据会越来越大的。
3.11.如何修改文件的最后修改时间?(参数为文件path)
3.12.如何计算sdcard上的剩余空间?
3.13.如何根据文件的最后修改时间进行排序?(继承了一个Comparator<File>的内部类)
FileLastModifSort其实就是一个类,类中有一个比较的函数,有两个File的参数,比较哪个更加最后而已。
3.14.如何获取缓存文件的绝对路径?(通过key得到一个String)
3.15.如何获取磁盘缓存文件夹,优先获取外置磁盘?(参数为context和一个string返回一个File)
3.16.什么是哈希编码?(参数为key返回一个String)
通过MD5加密后加了一个后缀为.cache,返回这个字符串。
3.17.bytes数组转化为哈希String?(参数为byte[]返回一个String)
这个在3.16.哈希编码中用到了,就是系统函数很多会转化为bytes,这个函数就是将byte[]类型的数据整合成String,
然后再处理逻辑。
这个DiskImageCache比较长,主要处理的就是一些缓存问题了,图片缓存,和本地的存储器挂钩了,所以就有很多函数
要调用。
4.回到ImageActivity
4.1这里首先复写了一个getLayoutId,返回一个资源id,其实就是ImageActivity布局
贴一下activity_image源代码。
- <?xml version="1.0" encoding="utf-8"?>
- <!--
- ~ Copyright 2017 GcsSloop
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- ~
- ~ Last modified 2017-03-15 23:45:17
- ~
- ~ GitHub: https://github.com/GcsSloop
- ~ Website: http://www.gcssloop.com
- ~ Weibo: http://weibo.com/GcsSloop
- -->
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/activity_image"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- tools:context="com.gcssloop.diycode.activity.ImageActivity">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <android.support.v4.view.ViewPager
- android:id="@+id/view_pager"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- </android.support.v4.view.ViewPager>
- <com.rd.PageIndicatorView
- android:id="@+id/pageIndicator"
- android:layout_marginBottom="16dp"
- android:layout_centerHorizontal="true"
- android:layout_alignParentBottom="true"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:piv_viewPager="@id/view_pager"
- app:piv_animationType="worm"
- app:piv_autoVisibility="false"
- app:piv_radius="4dp"
- app:piv_padding="12dp"
- app:piv_unselectedColor="@color/diy_gray2"
- app:piv_selectedColor="@color/diy_red"
- />
- </RelativeLayout>
- </LinearLayout>
4.2分析一下布局代码的结构
4.3.和真实页面对比一下。
4.4.这里有一个新的知识点==>PageIndicatorView
这是一个开源框架。挺不错的。简单实用。
作用就是当页面在切换时,一个提示作用,下面的小红点会告诉用户这是第几张图或者第几个页面。
4.5.然后是复写一个initViews方法。
4.5.1.注意,这个函数在initDatas之后调用。initDatas()函数在BaseImageActivity中调用了。
4.5.2.这里面通过setTitle设置了标题栏的查看图片。
4.5.3.这里从参数ViewHolder中获得了布局中的ViewPager,显然ViewHolder中BaseActivity中定义
然后ViewHolder初始化其实也是在BaseActivity中进行的,利用了一个抽象函数getLayoutId()
然后initData(),然后initViews(),所以这个ImageActivity才能直接获得这个ViewPager的Id。
4.5.4.这里看一下initViews中的部分代码。
对于getLayoutInflater不太理解,参考一下这篇文章。
4.5.4.1.它的作用类似于findViewById()。
4.5.4.2.LayoutInflater是用来找res/layout/下的xml布局文件,并且实例化。
4.5.4.3.FindViewById是找xml布局文件下的具体widget控件(如Button、TextView等)
4.5.5.这里继续initViews中的部分代码。
4.5.5.1.这里是在ImageActivity中定义的布局文件中的viewPager设置适配器的过程。
4.5.5.2.首先是复写了getCount方法,直接返回图片的张数。
4.5.5.3.然后是复写了isViewFromObject方法,两个参数(View,Object),使两者相等。
4.5.5.4.然后复写了一个关键的函数,instantiateItem(ViewGroup,int)
4.5.5.6.这里不得不提一下的是PhotoView。
也是第三方开源库,支持双指缩放,旋转。
看一下效果图吧!
4.5.5.7.分析一下instantiateItem==>这个方法返回一个对象,这个对象表明了PagerAdapter适配器选
择那个对象放在当前的ViewPager中。
然后这里还处理了缓存,如果缓存中有,就利用Glide.with(context).load(file).into()
如果缓存中没有,就利用Glide.with(context).load(图片url).into()方法
然后将这个photoView添加到容器中,这个容器就是instantiateItem中的第一个参数。
4.5.5.8.分析一下复写的destroyItem()方法,3个参数(ViewGroup,int,Object)
这个方法,是从ViewGroup中移除当前View。
4.5.5.9.然后将viewPager确定到第几项。
调用了基类BaseImageActivity中的静态常量current_image_position。
这样可以确定指示剂的位置。
4.6.然后回到ImageActivity中,最后一个函数是loadImage(string,photoView)
作用:给一个url和一个photoView,加载一张图到photoView中。
这里用到了一个第三方库。图片加载库。
源码如下:
这个应该是设置了缓存策略。
5.总结一下
5.1.首先理解一下哪里会用到ImageActivity这个活动,这个活动不是局限于某一个模块,而是所有地方,只要包含了图片
的地方,都是有可能调用intent来跳转到这里的。所以这个有点像之前做的大学喵,点击图片查看大图,支持缩放。
5.2.然后理解一下为什么这个ImageActivity要继承一个BaseImageActivity,这个BaseImageActivity实际上是一个抽象类,
定义了所有图片数据,所以真实数据在这里面处理,确定当前图片url,当前是第几个图片。
5.3.然后定义了一个DiskImageCache,主要是处理图片缓存的,基本上每个项目都会涉及到图片缓存,而且这些方法都是
必须实现而且基本一样,所以今后的项目也可以参考一下这个类,封装好的,耦合很低。
5.4.然后是一个imageActivity的布局,通过实现了BaseActivity中的抽象函数getLayoutId,来获得这个布局的资源id。
然后在initViews中的参数holder中,利用holder.get(R.id.view_pager)就能访问到这个ViewPager。
5.5.初始化view,注意是在initDatas调用之后,因为有了数据,才能填充到真实的视图。这里可以setTilte()来设置标题。
然后就是一些缓存处理了。
5.6.真正的图片要加载处理,必须要有一个adapter,所以这里new了一个PagerAdapter,实现了4个必须实现的方法。主要
逻辑在instantiateItem(ViewGroup container,int position)中处理,比如开启photoView缩放功能。以及缓存处理。
5.7.initViews函数执行结束之前一定要设置这个viewPager当前的页面,调用setCurrentItem(int)即可。
这个int其实是在父类中定义,因为这个是继承了父类,也可以直接调用父类中的变量。
5.8.最后是一个图片缓存策略,因为是灰色的,也没有执行,可以也不是必须要实现的。但是要是不得不说Glide有点强大,
特别是处理图片问题,图片缓存问题,图片加载问题。有空再深究一下。
Diycode开源项目 ImageActivity分析的更多相关文章
- Diycode开源项目 BaseApplication分析+LeakCanary第三方+CrashHandler自定义异常处理
1.BaseApplication整个应用的开始 1.1.看一下代码 /* * Copyright 2017 GcsSloop * * Licensed under the Apache Licens ...
- DiyCode开源项目 BaseActivity 分析
1.首先将这个项目的BaseActivity源码拷贝过来. /* * Copyright 2017 GcsSloop * * Licensed under the Apache License, Ve ...
- Diycode开源项目 TopicContentActivity分析
1.效果预览以及布局分析 1.1.实际效果预览 左侧话题列表的布局是通过TopicProvider来实现的,所以当初分析话题列表就没有看到布局. 这里的话题内容不是一个ListView,故要自己布局. ...
- Diycode开源项目 UserActivity分析
1.效果预览 1.1.实际界面预览 1.2. 这是MainActivity中的代码 这里执行了跳转到自己的用户界面的功能. 1.3.点击头像或者用户名跳转到别人的页面 UserActivity的结构由 ...
- Diycode开源项目 LoginActivity分析
1.首先看一下效果 1.1.预览一下真实页面 1.2.分析一下: 要求输入Email或者用户名,点击编辑框,弹出键盘,默认先进入输入Email或用户名编辑框. 点击密码后,密码字样网上浮动一段距离,E ...
- Diycode开源项目 MainActivity分析
1.分析MainActivity整体结构 1.1.首先看一下这个界面的整体效果. 1.2.活动源代码如下 /* * Copyright 2017 GcsSloop * * Licensed under ...
- DiyCode开源项目 AboutActivity分析
1.首先看一下效果 这是手机上显示的效果: 1.1首先是一个标题栏,左侧一个左箭头,然后一个图标. 1.2然后下方是一个可以滑动的页面. 1.3分成了7个部分. 1.4DiyCode的图标. 1.5然 ...
- DiyCode开源项目 TopicActivity 分析
1.首先看看TopActivity效果. 2.TopicActivity是一个继承BaseActivity的.前面分析过BaseActivity了.主要有一个标题栏,有返回的图标. 3.贴一下T ...
- Diycode开源项目 SitesListFragment分析
1.效果预览 1.1.网站列表实际界面 1.2.注意这个界面没有继承SimpleRefreshRecycleFragment 前面的话题和新闻继承了SimpleRefreshRecyclerFragm ...
随机推荐
- 私有npm下载资源
私有npm库下载资源需要用户名和密码,这个需要创建npm库的人提供. 使用方法: npm login --registry=仓库地址 Username: 用户名 Password: 密码 Email: ...
- 卸载gitlab
一.停止gitlab sudo gitlab-ctl stop 二.卸载gitlab sudo rpm -e gitlab-ce三.查看gitlab进程 杀掉第一个守护进程 kill -9 4473 ...
- 爬虫技术-httpClent+jsoup
技术:httpClent+jsoup 任务:利用httpClent爬去网站信息,在利用jsoup解析 方法说明: parseUrl(String url):传入相应的url返回该网页内容,网页必须是h ...
- jsop解析获得htmldome
package com.open1111.jsoup; import org.apache.http.HttpEntity;import org.apache.http.client.methods. ...
- TP5.0:同一个控制器访问不同方法
首先,我把TP框架的内容放置在manualtp5文件夹 在manualtp5/application/index/controller/index控制器中定义两个方法: 我们都知道,如果我们网址中不输 ...
- 【强力卸载】使用Uninstall Tool卸载各类不易卸载的软件
Uninstall Tool 经测试卸载MySql5.7.18成功. 下载地址: http://files.cnblogs.com/files/xiaohi/%E3%80%90%E8%BD%AF%E4 ...
- Producer & Consumer
需要与Eureka结合使用 Eureka环境搭建 Producer 一.pom文件 <?xml version="1.0" encoding="UTF-8" ...
- 【BZOJ1059】[ZJOI2007] 矩阵游戏(匈牙利算法)
点此看题面 大致题意: 有一个\(N*N\)的\(01\)矩阵,可以任意交换若干行和若干列,问是否有方案使得左上角到右下角的连线上全是\(1\). 题意转换 首先,让我们来对题意进行一波转化. 如果我 ...
- 实现带复选框的TreeView控件
实现效果: 知识运用: TreeView控件的CheckView属性 //是否在树形视图控件中显示复选框 public bool CheckBoxs{ get;ser } 实现代码: TreeView ...
- TypeScript task
Ctrl+Shift+B 生成 js 文件.