app/src/main/java/com/socks/jiandan/utils/ShareUtil.java
public class ShareUtil {

    public static void sharePicture(Activity activity, String url) {

        String[] urlSplits = url.split("\\.");

        File cacheFile = ImageLoader.getInstance().getDiskCache().get(url);

        //如果不存在，则使用缩略图进行分享
        if (!cacheFile.exists()) {
            String picUrl = url;
            picUrl = picUrl.replace("mw600", "small").replace("mw1200", "small").replace
                    ("large", "small");
            cacheFile = ImageLoader.getInstance().getDiskCache().get(picUrl);
        }

        File newFile = new File(CacheUtil.getSharePicName
                (cacheFile, urlSplits));

        if (FileUtil.copyTo(cacheFile, newFile)) {
            ShareUtil.sharePicture(activity, newFile.getAbsolutePath(),
                    "分享自煎蛋 " + url);
        } else {
            ToastHelper.Short(ConstantString.LOAD_SHARE);
        }
    }


    public static void shareText(Activity activity, String shareText) {

        Intent intent = new Intent(Intent.ACTION_SEND);
        intent.setType("text/plain");
        intent.putExtra(Intent.EXTRA_TEXT,
                shareText);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        activity.startActivity(Intent.createChooser(intent, activity.getResources().getString(R
                .string.app_name)));
    }

    public static void sharePicture(Activity activity, String imgPath, String shareText) {

        Intent intent = new Intent(Intent.ACTION_SEND);
        File f = new File(imgPath);
        if (f != null && f.exists() && f.isFile()) {
            intent.setType("image/*");
            intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f));
        } else {
            ToastHelper.Short("分享图片不存在哦");
            return;
        }

        //GIF图片指明出处url，其他图片指向项目地址
        if (imgPath.endsWith(".gif")) {
            intent.putExtra(Intent.EXTRA_TEXT, shareText);
        }

        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        activity.startActivity(Intent.createChooser(intent, activity.getResources().getString(R
                .string.app_name)));
    }


}
app/src/main/java/com/socks/jiandan/cache/PictureCache.java
public class PictureCache extends BaseCache {

	private static PictureCache instance;
	private static PictureCacheDao mPictureCacheDao;

	private PictureCache() {
	}

	public static PictureCache getInstance(Context context) {

		if (instance == null) {

			synchronized (PictureCache.class) {
				if (instance == null) {
					instance = new PictureCache();
				}
			}

			mDaoSession = JDApplication.getDaoSession(context);
			mPictureCacheDao = mDaoSession.getPictureCacheDao();
		}
		return instance;
	}

	/**
	 * 清楚全部缓存
	 */
	public void clearAllCache() {
		mPictureCacheDao.deleteAll();
	}

	/**
	 * 根据页码获取缓存数据
	 *
	 * @param page
	 * @return
	 */
	@Override
	public ArrayList<Picture> getCacheByPage(int page) {

		QueryBuilder<com.socks.greendao.PictureCache> query = mPictureCacheDao.queryBuilder().where(PictureCacheDao
				.Properties.Page.eq("" + page));

		if (query.list().size() > 0) {
			return (ArrayList<Picture>) JSONParser.toObject(query.list().get(0).getResult(),
					new TypeToken<ArrayList<Picture>>() {
					}.getType());
		} else {
			return new ArrayList<>();
		}

	}

	/**
	 * 添加Jokes缓存
	 *
	 * @param result
	 * @param page
	 */
	@Override
	public void addResultCache(String result, int page) {
		com.socks.greendao.PictureCache pictureCache = new com.socks.greendao.PictureCache();
		pictureCache.setResult(result);
		pictureCache.setPage(page);
		pictureCache.setTime(System.currentTimeMillis());

		mPictureCacheDao.insert(pictureCache);
	}

}
app/src/main/java/com/socks/jiandan/utils/GsonHelper.java
public class GsonHelper<T> {

    public static Gson mGson;

    static {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            GsonBuilder gsonBuilder = new GsonBuilder()
                    .excludeFieldsWithModifiers(
                            Modifier.FINAL,
                            Modifier.TRANSIENT,
                            Modifier.STATIC);
            mGson = gsonBuilder.create();
        } else {
            mGson = new Gson();
        }
    }


    public static String toString(Object obj) {
        return mGson.toJson(obj);
    }

    public T fromJson(String json, Class<T> classOfT) {
        return mGson.fromJson(json, classOfT);
    }

    public T fromJson(String json, Type typeOfT) {
        return mGson.fromJson(json, typeOfT);
    }

}
app/src/main/java/com/socks/jiandan/model/Picture.java
public class Picture implements Serializable {

    public static final String URL_BORING_PICTURE = "http://jandan.net/?oxwlxojflwblxbsapi=jandan.get_pic_comments&page=";
    public static final String URL_SISTER = "http://jandan.net/?oxwlxojflwblxbsapi=jandan.get_ooxx_comments&page=";

    public static final int BoringPicture = 1;
    public static final int Sister = 2;

    private String comment_ID;
    private String comment_author;
    private String comment_date;
    private String text_content;
    private String vote_positive;
    private String vote_negative;
    private String[] pics;
    //评论数量，需要单独获取
    private String comment_counts;

    public Picture() {
    }

    public static String getRequestUrl(int type, int page) {

        switch (type) {
            case BoringPicture:
                return URL_BORING_PICTURE + page;
            case Sister:
                return URL_SISTER + page;
            default:
                return "";
        }
    }

    public String getComment_ID() {
        return comment_ID;
    }

    public String getComment_author() {
        return comment_author;
    }

    public String getComment_date() {
        return comment_date;
    }

    public String getText_content() {
        return text_content;
    }

    public String getVote_positive() {
        return vote_positive;
    }

    public String getVote_negative() {
        return vote_negative;
    }

    public String getComment_counts() {
        return comment_counts;
    }

    public void setComment_counts(String comment_counts) {
        this.comment_counts = comment_counts;
    }

    public String[] getPics() {
        return pics;
    }

}
app/src/main/java/com/socks/jiandan/ui/activity/CommentListActivity.java
public class CommentListActivity extends BaseActivity implements LoadResultCallBack {

    @Bind(R.id.swipe_refresh)
    SwipeRefreshLayout mSwipeRefreshLayout;
    @Bind(R.id.recycler_view)
    RecyclerView mRecyclerView;
    @Bind(R.id.toolbar)
    Toolbar mToolbar;
    @Bind(R.id.loading)
    RotateLoading loading;

    private boolean isFromFreshNews;
    private CommentAdapter mAdapter;

    @Override
    protected void initView(@Nullable Bundle savedInstanceState) {
        setContentView(R.layout.activity_comment_list);
        ButterKnife.bind(this);

        mToolbar.setTitleTextColor(Color.WHITE);
        setSupportActionBar(mToolbar);
        mToolbar.setTitle("评论");
        mToolbar.setNavigationIcon(R.drawable.ic_actionbar_back);

        mRecyclerView.setHasFixedSize(false);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));

        mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_bright,
                android.R.color.holo_green_light,
                android.R.color.holo_orange_light,
                android.R.color.holo_red_light);

        mSwipeRefreshLayout.setOnRefreshListener(() -> {
            if (isFromFreshNews) {
                mAdapter.loadData4FreshNews();
            } else {
                mAdapter.loadData();
            }
        });
    }

    @Override
    protected void loadData() {
        String thread_key = getIntent().getStringExtra(DATA_THREAD_KEY);
        String thread_id = getIntent().getStringExtra(DATA_THREAD_ID);
        isFromFreshNews = getIntent().getBooleanExtra(DATA_IS_FROM_FRESH_NEWS, false);

        if (isFromFreshNews) {
            mAdapter = new CommentAdapter(this, thread_id, true, this);
            if (TextUtils.isEmpty(thread_id) || thread_id.equals("0")) {
                ToastHelper.Short(FORBID_COMMENTS);
                finish();
            }
        } else {
            mAdapter = new CommentAdapter(this, thread_key, false, this);
            if (TextUtils.isEmpty(thread_key) || thread_key.equals("0")) {
                ToastHelper.Short(FORBID_COMMENTS);
                finish();
            }
        }
        mRecyclerView.setAdapter(mAdapter);
        if (isFromFreshNews) {
            mAdapter.loadData4FreshNews();
        } else {
            mAdapter.loadData();
        }
        loading.start();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            if (isFromFreshNews) {
                mAdapter.loadData4FreshNews();
            } else {
                mAdapter.loadData();
            }
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_comment_list, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                finish();
                return true;
            case R.id.action_edit:
                Intent intent = new Intent(this, PushCommentActivity.class);
                intent.putExtra(DATA_THREAD_ID, mAdapter.getThreadId());
                startActivityForResult(intent, 0);
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onSuccess(int result, Object object) {
        if (result == LoadResultCallBack.SUCCESS_NONE) {
            ToastHelper.Short(NO_COMMENTS);
        }
        loading.stop();
        mSwipeRefreshLayout.setRefreshing(false);
    }

    @Override
    public void onError(int code) {
        mSwipeRefreshLayout.setRefreshing(false);
        loading.stop();
        ToastHelper.Short(LOAD_FAILED);
    }

}
app/src/main/java/com/socks/jiandan/JDApplication.java
public class JDApplication extends Application {

    public static int COLOR_OF_DIALOG = R.color.primary;
    public static int COLOR_OF_DIALOG_CONTENT = Color.WHITE;

    private static Context mContext;
    private static DaoMaster daoMaster;
    private static DaoSession daoSession;

    private RefWatcher refWatcher;

    @Override
    public void onCreate() {
        StrictModeUtil.init();
        super.onCreate();
        mContext = this;

        refWatcher = LeakCanary.install(this);
        ImageLoadProxy.initImageLoader(this);
        initHttpClient();
        SPHelper.init(mContext);
        KLog.init(BuildConfig.DEBUG);
    }

    private void initHttpClient() {

        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(30, TimeUnit.SECONDS);
        builder.readTimeout(30, TimeUnit.SECONDS);
        builder.writeTimeout(30, TimeUnit.SECONDS);
        builder.retryOnConnectionFailure(true);
        OkHttpProxy.setInstance(builder.build());

    }

    public static Context getContext() {
        return mContext;
    }

    public static RefWatcher getRefWatcher(Context context) {
        JDApplication application = (JDApplication) context.getApplicationContext();
        return application.refWatcher;
    }


    public static DaoMaster getDaoMaster(Context context) {
        if (daoMaster == null) {
            DaoMaster.OpenHelper helper = new DaoMaster.DevOpenHelper(context, BaseCache.DB_NAME, null);
            daoMaster = new DaoMaster(helper.getWritableDatabase());
        }
        return daoMaster;
    }

    public static DaoSession getDaoSession(Context context) {
        if (daoSession == null) {
            if (daoMaster == null) {
                daoMaster = getDaoMaster(context);
            }
            daoSession = daoMaster.newSession();
        }
        return daoSession;
    }

}
app/src/main/java/com/socks/jiandan/callback/LoadFinishCallBack.java
public interface LoadFinishCallBack<T> {
    
    void loadFinish(T t);

}
app/src/main/java/com/socks/jiandan/view/ShowMaxImageView.java
public class ShowMaxImageView extends ImageView {

	private float mHeight = 0;

	public ShowMaxImageView(Context context) {
		super(context);
	}

	public ShowMaxImageView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public ShowMaxImageView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
	}

	@Override
	public void setImageBitmap(Bitmap bm) {

		if (bm != null) {
			getHeight(bm);
		}

		super.setImageBitmap(bm);
		requestLayout();
	}

	@Override
	public void setImageDrawable(Drawable drawable) {

		if (drawable != null) {
			getHeight(drawableToBitamp(drawable));
		}

		super.setImageDrawable(drawable);
		requestLayout();
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

		if (mHeight != 0) {

			int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
			int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);

			int resultHeight = (int) Math.max(mHeight, sizeHeight);

			if (resultHeight >= ScreenSizeUtil.getScreenHeight((Activity) getContext())) {
				resultHeight = ScreenSizeUtil.getScreenHeight((Activity) getContext()) / 3;
			}

			setMeasuredDimension(sizeWidth, resultHeight);
		} else {
			super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		}

	}

	private void getHeight(Bitmap bm) {

		float bitmapWidth = bm.getWidth();
		float bitmapHeight = bm.getHeight();

		if (bitmapWidth > 0 && bitmapHeight > 0) {
			float scaleWidth = getWidth() / bitmapWidth;
			mHeight = bitmapHeight * scaleWidth;
		}

	}


	private Bitmap drawableToBitamp(Drawable drawable) {

		if (drawable != null) {
			BitmapDrawable bd = (BitmapDrawable) drawable;
			return bd.getBitmap();
		} else {
			return null;
		}
	}

}
app/src/main/java/com/socks/jiandan/utils/ToastHelper.java
public class ToastHelper {

    public static void Short(@NonNull CharSequence sequence) {
        Toast.makeText(JDApplication.getContext(), sequence, Toast.LENGTH_SHORT).show();
    }

    public static void Short(@StringRes int id) {
        Toast.makeText(JDApplication.getContext(), id, Toast.LENGTH_SHORT).show();
    }

    public static void Long(@StringRes int id) {
        Toast.makeText(JDApplication.getContext(), id, Toast.LENGTH_LONG).show();
    }

    public static void Long(@NonNull CharSequence sequence) {
        Toast.makeText(JDApplication.getContext(), sequence, Toast.LENGTH_LONG).show();
    }

}
app/src/main/java/com/socks/jiandan/base/BaseActivity.java
public abstract class BaseActivity extends AppCompatActivity implements ConstantString {

    private CompositeSubscription mCompositeSubscription;
    protected Context mContext;
    protected boolean isTransitionAnimation = true;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = this;
        initView(savedInstanceState);
        loadData();
    }

    protected abstract void initView(@Nullable Bundle savedInstanceState);

    protected abstract void loadData();

    @Override
    protected void onDestroy() {
        super.onDestroy();
        JDApplication.getRefWatcher(this).watch(this);
        if (mCompositeSubscription != null) {
            mCompositeSubscription.unsubscribe();
        }
    }

    @Override
    public void finish() {
        super.finish();
        if (isTransitionAnimation) {
            overridePendingTransition(R.anim.anim_none, R.anim.trans_center_2_right);
        }
    }

    public CompositeSubscription getCompositeSubscription() {
        if (this.mCompositeSubscription == null) {
            this.mCompositeSubscription = new CompositeSubscription();
        }

        return this.mCompositeSubscription;
    }


    public void addSubscription(Subscription s) {
        if (this.mCompositeSubscription == null) {
            this.mCompositeSubscription = new CompositeSubscription();
        }

        this.mCompositeSubscription.add(s);
    }

    ///////////////////////////////////////////////////////////////////////////
    // Fragment Method
    ///////////////////////////////////////////////////////////////////////////

    protected Fragment findFragmentByTag(String tag) {
        FragmentManager manager = getSupportFragmentManager();
        return manager.findFragmentByTag(tag);
    }

    protected void addFragment(@IdRes int containerId, Fragment fragment, String tag) {
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        transaction.add(containerId, fragment, tag);
        transaction.commit();
    }

    protected void showFragment(Fragment fragment) {
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        transaction.show(fragment);
        transaction.commit();
    }

    protected void hideFragment(Fragment fragment) {
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        transaction.hide(fragment);
        transaction.commit();
    }

    protected void removeFragment(Fragment fragment) {
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        transaction.remove(fragment);
        transaction.commit();
    }

    protected void hideFragmentByTag(String... tags) {

        if (tags.length <= 0) {
            return;
        }

        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        for (String tag : tags) {
            if (TextUtils.isEmpty(tag)) {
                continue;
            }
            Fragment fragment = manager.findFragmentByTag(tag);
            if (fragment != null) {
                transaction.hide(fragment);
            }
        }
        transaction.commit();
    }

    public void replaceFragment(@IdRes int id_content, Fragment fragment) {
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.replace(id_content, fragment);
        transaction.commit();
    }
}
app/src/main/java/com/socks/jiandan/utils/FileUtil.java
public class FileUtil {

    /**
     * 获取文件夹总大小
     *
     * @param file
     * @return
     */
    public static double getDirSize(File file) {
        //判断文件是否存在
        if (file.exists()) {
            //如果是目录则递归计算其内容的总大小
            if (file.isDirectory()) {
                File[] children = file.listFiles();
                double size = 0;
                for (File f : children) {
                    size += getDirSize(f);
                }
                return size;
            } else {//如果是文件则直接返回其大小,以“兆”为单位
                return (double) file.length() / 1024 / 1024;
            }
        } else {
            return 0.0;
        }
    }

    public static void savePicture(String picUrl, LoadFinishCallBack<Bundle> loadFinishCallBack) {

        boolean isSmallPic = false;
        String[] urls = picUrl.split("\\.");
        File cacheFile = ImageLoader.getInstance().getDiskCache().get(picUrl);

        //如果是GIF格式，优先保存GIF动态图，如果不存在，则保存缩略图
        if (!cacheFile.exists()) {
            String cacheUrl = picUrl.replace("mw600", "small").replace("mw1200", "small")
                    .replace("large", "small");
            cacheFile = ImageLoader.getInstance().getDiskCache().get(cacheUrl);
            isSmallPic = true;
        }

        File picDir = new File(CacheUtil.getSaveDirPath());

        if (!picDir.exists()) {

            if (picDir.mkdir()) {
                final File newFile = new File(picDir, CacheUtil.getSavePicName(cacheFile, urls));
                if (FileUtil.copyTo(cacheFile, newFile)) {
                    Bundle bundle = new Bundle();
                    bundle.putBoolean(BaseActivity.DATA_IS_SMALL_PIC, isSmallPic);
                    bundle.putString(BaseActivity.DATA_FILE_PATH, newFile.getAbsolutePath());
                    loadFinishCallBack.loadFinish(bundle);
                } else {
                    ToastHelper.Short(ConstantString.SAVE_FAILED);
                }
            }
        }
    }

    /**
     * 复制文件
     *
     * @param src 源文件
     * @param dst 目标文件
     * @return
     */
    public static boolean copyTo(File src, File dst) {

        FileInputStream fi = null;
        FileOutputStream fo = null;
        FileChannel in = null;
        FileChannel out = null;
        try {
            fi = new FileInputStream(src);
            fo = new FileOutputStream(dst);
            in = fi.getChannel();//得到对应的文件通道
            out = fo.getChannel();//得到对应的文件通道
            in.transferTo(0, in.size(), out);//连接两个通道，并且从in通道读取，然后写入out通道
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } finally {
            try {

                if (fi != null) {
                    fi.close();
                }

                if (in != null) {
                    in.close();
                }

                if (fo != null) {
                    fo.close();
                }

                if (out != null) {
                    out.close();
                }

            } catch (IOException e) {
                e.printStackTrace();
                return false;
            }
        }

    }


}
app/src/main/java/com/socks/jiandan/utils/TextUtil.java
public class TextUtil {

    public static final String REG_EMAIL = "\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*";


    public static boolean isEmail(String email) {
        Pattern p = Pattern.compile(REG_EMAIL);
        Matcher m = p.matcher(email);
        return m.matches();
    }


    /**
     * 判断是否为null、空字符串或者是"null"
     *
     * @param str
     * @return
     */
    public static boolean isNull(CharSequence... str) {

        for (CharSequence cha : str) {
            if (cha == null || cha.length() == 0 || cha.equals("null")) {
                return true;
            } else {
                return false;
            }
        }

        return true;
    }

    public static void copy(Activity activity, String copyText) {
        ClipboardManager clip = (ClipboardManager)
                activity.getSystemService(Context
                        .CLIPBOARD_SERVICE);
        clip.setPrimaryClip(ClipData.newPlainText
                (null, copyText));
        ToastHelper.Short(ConstantString.COPY_SUCCESS);
    }

    public static String getHtml(FreshNews freshNews, String content) {
        final StringBuilder sb = new StringBuilder();
        sb.append("<!DOCTYPE html>");
        sb.append("<html dir=\"ltr\" lang=\"zh\">");
        sb.append("<head>");
        sb.append("<meta name=\"viewport\" content=\"width=100%; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;\" />");
        sb.append("<link rel=\"stylesheet\" href='file:///android_asset/style.css' type=\"text/css\" media=\"screen\" />");
        sb.append("</head>");
        sb.append("<body style=\"padding:0px 8px 8px 8px;\">");
        sb.append("<div id=\"pagewrapper\">");
        sb.append("<div id=\"mainwrapper\" class=\"clearfix\">");
        sb.append("<div id=\"maincontent\">");
        sb.append("<div class=\"post\">");
        sb.append("<div class=\"posthit\">");
        sb.append("<div class=\"postinfo\">");
        sb.append("<h2 class=\"thetitle\">");
        sb.append("<a>");
        sb.append(freshNews.title);
        sb.append("</a>");
        sb.append("</h2>");
        sb.append(freshNews.author.getName() + " @ " + String2TimeUtil
                .dateString2GoodExperienceFormat(freshNews.date));
        sb.append("</div>");
        sb.append("<div class=\"entry\">");
        sb.append(content);
        sb.append("</div>");
        sb.append("</div>");
        sb.append("</div>");
        sb.append("</div>");
        sb.append("</div>");
        sb.append("</div>");
        sb.append("</body>");
        sb.append("</html>");
        return sb.toString();
    }

}
app/src/main/java/com/socks/jiandan/callback/LoadResultCallBack.java
public interface LoadResultCallBack {

    int SUCCESS_OK = 1001;
    int SUCCESS_NONE = 1002;
    int ERROR_NET = 1003;

    void onSuccess(int result, Object object);

    void onError(int code);
}
app/src/main/java/com/socks/jiandan/net/JDApi.java
public class JDApi {

    public static Observable<ArrayList<Video>> getVideos(int page) {
        return Observable.create(new Observable.OnSubscribe<ArrayList<Video>>() {
            @Override
            public void call(Subscriber<? super ArrayList<Video>> subscriber) {
                try {
                    subscriber.onNext(new VideoParser().parse(OkHttpProxy.get().url(Video.getUrlVideos(page)).execute()));
                    subscriber.onCompleted();
                } catch (IOException e) {
                    subscriber.onError(e);
                }
            }
        }).compose(applySchedulers());
    }


    public static Observable<ArrayList<Joke>> getJokes(int page) {
        return Observable.create(new Observable.OnSubscribe<ArrayList<Joke>>() {
            @Override
            public void call(Subscriber<? super ArrayList<Joke>> subscriber) {
                try {
                    subscriber.onNext(new JokeParser().parse(OkHttpProxy.get().url(Joke.getRequestUrl(page)).execute()));
                    subscriber.onCompleted();
                } catch (IOException e) {
                    e.printStackTrace();
                    subscriber.onError(e);
                }
            }
        }).compose(applySchedulers());
    }


    public static Observable<ArrayList<CommentNumber>> getCommentNumber(String comments) {

        return Observable.create(new Observable.OnSubscribe<ArrayList<CommentNumber>>() {
            @Override
            public void call(Subscriber<? super ArrayList<CommentNumber>> subscriber) {
                String url = CommentNumber.getCommentCountsURL(comments);
                try {
                    subscriber.onNext(new CommentCountsParser().parse(OkHttpProxy.get().url(url).execute()));
                    subscriber.onCompleted();
                } catch (IOException e) {
                    subscriber.onError(e);
                }
            }
        }).compose(applySchedulers());
    }


    public static Observable<ArrayList<Picture>> getPictures(int type, int page) {

        return Observable.create(new Observable.OnSubscribe<ArrayList<Picture>>() {
            @Override
            public void call(Subscriber<? super ArrayList<Picture>> subscriber) {
                String url = Picture.getRequestUrl(type, page);
                try {
                    subscriber.onNext(new PictureParser().parse(OkHttpProxy.get().url(url).execute()));
                    subscriber.onCompleted();
                } catch (IOException e) {
                    subscriber.onError(e);
                }
            }
        }).compose(applySchedulers());
    }


    public static Observable<Boolean> pushComment4DuoShuo(Map<String, String> params) {

        return Observable.create(new Observable.OnSubscribe<Boolean>() {
            @Override
            public void call(Subscriber<? super Boolean> subscriber) {
                try {
                    subscriber.onNext(new PushCommentParser().parse(OkHttpProxy.post().url(Commentator.URL_PUSH_COMMENT).setParams(params).execute()));
                    subscriber.onCompleted();
                } catch (IOException e) {
                    e.printStackTrace();
                    subscriber.onError(e);
                }
            }
        }).compose(applySchedulers());
    }


    public static Observable<Boolean> pushComment4FreshNews(String url) {

        return Observable.create(new Observable.OnSubscribe<Boolean>() {
            @Override
            public void call(Subscriber<? super Boolean> subscriber) {
                try {
                    subscriber.onNext(new Push4FreshCommentParser().parse(OkHttpProxy.get().url(url).execute()));
                    subscriber.onCompleted();
                } catch (IOException e) {
                    subscriber.onError(e);
                }
            }
        }).compose(applySchedulers());
    }


    public static Observable<ArrayList<Comment4FreshNews>> getCommentator4FreshNews(final String thread_key, LoadFinishCallBack callBack) {

        return Observable.create(new Observable.OnSubscribe<ArrayList<Comment4FreshNews>>() {

            @Override
            public void call(Subscriber<? super ArrayList<Comment4FreshNews>> subscriber) {
                String url = Comment4FreshNews.getUrlComments(thread_key);
                try {
                    subscriber.onNext(new FreshNewsCommentParser(callBack).parse(OkHttpProxy.get()
                            .url(url)
                            .execute()));
                    subscriber.onCompleted();
                } catch (IOException e) {
                    subscriber.onError(e);
                }
            }
        }).compose(applySchedulers());
    }


    public static Observable<ArrayList<Commentator>> getCommentator(final String thread_key, LoadFinishCallBack callBack) {

        return Observable.create(new Observable.OnSubscribe<ArrayList<Commentator>>() {

            @Override
            public void call(Subscriber<? super ArrayList<Commentator>> subscriber) {
                String url = Commentator.getUrlCommentList(thread_key);
                try {
                    subscriber.onNext(new CommentListParser(callBack).parse(OkHttpProxy.get()
                            .url(url)
                            .execute()));
                    subscriber.onCompleted();
                } catch (IOException e) {
                    subscriber.onError(e);
                }
            }
        }).compose(applySchedulers());
    }


    public static Observable<ArrayList<FreshNews>> getFreshNews(final int page) {

        return Observable.create(new Observable.OnSubscribe<ArrayList<FreshNews>>() {

            @Override
            public void call(Subscriber<? super ArrayList<FreshNews>> subscriber) {
                String url = FreshNews.getUrlFreshNews(page);
                try {
                    subscriber.onNext(new FreshNewsParser().parse(OkHttpProxy.get()
                            .url(url)
                            .execute()));
                    subscriber.onCompleted();
                } catch (IOException e) {
                    subscriber.onError(e);
                }
            }
        }).compose(JDApi.<ArrayList<FreshNews>>applySchedulers());
    }


    public static Observable<String> getFreshDetail(String id) {
        return Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                String url = FreshNews.getUrlFreshNewsDetail(id);
                try {
                    subscriber.onNext(new FreshNewsDetailParser().parse(OkHttpProxy.get().url(url).execute()));
                    subscriber.onCompleted();
                } catch (IOException e) {
                    subscriber.onError(e);
                }
            }
        }).compose(applySchedulers());
    }

    public static <T> Observable.Transformer<T, T> applySchedulers() {
        return observable -> observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

}
app/src/main/java/com/socks/jiandan/base/ConstantString.java
public interface ConstantString {

    String COMMENT_FAILED = "神秘力量导致评论失败 ⊙︿⊙";
    String VOTE_FAILED = "神秘力量导致投票失败 ⊙︿⊙";
    String LOAD_FAILED = "神秘力量导致加载失败 ⊙︿⊙";
    String SAVE_FAILED = "神秘力量导致保存失败 ⊙︿⊙";
    String LOAD_SHARE = "神秘力量导致分享失败 ⊙︿⊙";

    String INPUT_TOO_SHORT = "你的..太短..";
    String COPY_SUCCESS = "复制成功";
    String SAVE_SUCCESS = "保存成功";
    String SAVE_SMALL_SUCCESS = "保存缩略图成功";
    String VOTE_XX = "疼...轻点插";
    String VOTE_OO = "顶的好舒服~";
    String VOTE_REPEAT = "投过票了";
    String LOAD_NO_NETWORK = "无网络，当前为缓存数据";
    String FORBID_COMMENTS = "禁止评论";
    String NO_COMMENTS = "暂无评论";
    String UN_CLICK = "别点了，这玩意不能用";

    String DATA_FRESH_NEWS = "FreshNews";
    String DATA_POSITION = "position";
    String DATA_THREAD_ID = "thread_id";
    String DATA_THREAD_KEY = "thread_key";
    String DATA_IS_FROM_FRESH_NEWS = "is_from_fresh_news";

    String DATA_IMAGE_URL = "img_url";
    String DATA_IMAGE_ID = "img_id";
    String DATA_IMAGE_AUTHOR = "img_author";
    String DATA_IS_NEED_WEB_VIEW = "is_need_webview";

    String DATA_IS_SMALL_PIC =  "isSmallPic";
    String DATA_FILE_PATH =  "file_path";

}
app/src/main/java/com/socks/jiandan/utils/IntentHelper.java
public class IntentHelper {

    public static void toSettingActivity(Context context) {
        Intent intent = new Intent(
                Settings.ACTION_WIRELESS_SETTINGS);
        context.startActivity(intent);
    }

    public static void toFreshDetailActivity(Context context, ArrayList<FreshNews> mFreshNews, int position) {
        Intent intent = new Intent(context, FreshNewsDetailActivity.class);
        intent.putExtra(FreshNewsDetailActivity.DATA_FRESH_NEWS, mFreshNews);
        intent.putExtra(FreshNewsDetailActivity.DATA_POSITION, position);
        context.startActivity(intent);
    }

    public static void toCommentListActivity(Context context, String id) {
        Intent intent = new Intent(context, CommentListActivity.class);
        intent.putExtra(BaseActivity.DATA_THREAD_ID, id);
        intent.putExtra(BaseActivity.DATA_IS_FROM_FRESH_NEWS, true);
        context.startActivity(intent);
    }

    public static void toPushComment4Result(Activity context, String postId, String threadId, String parentName){
        Intent intent = new Intent
                (context, PushCommentActivity.class);
        intent.putExtra("parent_id", postId);
        intent.putExtra("thread_id", threadId);
        intent.putExtra("parent_name", parentName);
        context.startActivityForResult(intent, 0);
    }


    public static void toImageDetailActivity(Context context, Picture picture){
        Intent intent = new Intent(context, ImageDetailActivity.class);

        intent.putExtra(BaseActivity.DATA_IMAGE_AUTHOR, picture.getComment_author());
        intent.putExtra(BaseActivity.DATA_IMAGE_URL, picture.getPics());
        intent.putExtra(BaseActivity.DATA_IMAGE_ID, picture.getComment_ID());
        intent.putExtra(BaseActivity.DATA_THREAD_KEY, "comment-" + picture.getComment_ID());

        if (picture.getPics()[0].endsWith(".gif")) {
            intent.putExtra(BaseActivity.DATA_IS_NEED_WEB_VIEW, true);
        }

        context.startActivity(intent);
    }
}


Question: package com.socks.jiandan.adapter;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Typeface;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.afollestad.materialdialogs.MaterialDialog;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import com.socks.jiandan.JDApplication;
import com.socks.jiandan.R;
import com.socks.jiandan.base.BaseActivity;
import com.socks.jiandan.base.ConstantString;
import com.socks.jiandan.cache.PictureCache;
import com.socks.jiandan.callback.LoadFinishCallBack;
import com.socks.jiandan.callback.LoadResultCallBack;
import com.socks.jiandan.model.Picture;
import com.socks.jiandan.net.JDApi;
import com.socks.jiandan.ui.activity.CommentListActivity;
import com.socks.jiandan.utils.FileUtil;
import com.socks.jiandan.utils.GsonHelper;
import com.socks.jiandan.utils.IntentHelper;
import com.socks.jiandan.utils.NetWorkUtil;
import com.socks.jiandan.utils.ShareUtil;
import com.socks.jiandan.utils.String2TimeUtil;
import com.socks.jiandan.utils.TextUtil;
import com.socks.jiandan.utils.ToastHelper;
import com.socks.jiandan.view.ShowMaxImageView;
import com.socks.jiandan.view.imageloader.ImageLoadProxy;
import java.util.ArrayList;
import java.util.List;
import butterknife.Bind;
import butterknife.ButterKnife;
import rx.Observable;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import static com.socks.jiandan.R.color.secondary_text_default_material_light;






public class PictureAdapter extends RecyclerView.Adapter<PictureAdapter.PictureViewHolder> {

    private int page;
    private int lastPosition = -1;
    private int mType;
    private boolean isWifiConnected;

    private ArrayList<Picture> mPictures;
    private LoadFinishCallBack<Object> mLoadFinisCallBack;
    private LoadResultCallBack mLoadResultCallBack;
    private BaseActivity mActivity;
    private LoadFinishCallBack mSaveFileCallBack;

    public PictureAdapter(BaseActivity activity, LoadResultCallBack loadResultCallBack, LoadFinishCallBack<Object> loadFinisCallBack, int type) {
        mActivity = activity;
        mType = type;
        mLoadFinisCallBack = loadFinisCallBack;
        mLoadResultCallBack = loadResultCallBack;
        mPictures = new ArrayList<>();
        isWifiConnected = NetWorkUtil.isWifiConnected(mActivity);
    }

    private void setAnimation(View viewToAnimate, int position) {
        if (position > lastPosition) {
            Animation animation = AnimationUtils.loadAnimation(viewToAnimate.getContext(), R
                    .anim.item_bottom_in);
            viewToAnimate.startAnimation(animation);
            lastPosition = position;
        }
    }

    @Override
    public void onViewDetachedFromWindow(PictureViewHolder holder) {
        super.onViewDetachedFromWindow(holder);
        holder.card.clearAnimation();
    }

    @Override
    public PictureViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_pic, parent, false);
        return new PictureViewHolder(v);
    }

    @Override
    public void onBindViewHolder(final PictureViewHolder holder, final int position) {

        final Picture picture = mPictures.get(position);
        String picUrl = picture.getPics()[0];

        if (picUrl.endsWith(".gif")) {
            holder.img_gif.setVisibility(View.VISIBLE);
            //非WIFI网络情况下，GIF图只加载缩略图，详情页才加载真实图片
            if (!isWifiConnected) {
                picUrl = picUrl.replace("mw600", "small").replace("mw1200", "small").replace
                        ("large", "small");
            }
        } else {
            holder.img_gif.setVisibility(View.GONE);
        }

        holder.progress.setProgress(0);
        holder.progress.setVisibility(View.VISIBLE);

        ImageLoadProxy.displayImageList(picUrl, holder.img, R.drawable.ic_loading_large, new
                        SimpleImageLoadingListener() {
                            @Override
                            public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
                                super.onLoadingComplete(imageUri, view, loadedImage);
                                holder.progress.setVisibility(View.GONE);
                            }
                        },
                (imageUri, view, current, total) -> holder.progress.setProgress((int) (current * 100f / total)));

        if (TextUtil.isNull(picture.getText_content().trim())) {
            holder.tv_content.setVisibility(View.GONE);
        } else {
            holder.tv_content.setVisibility(View.VISIBLE);
            holder.tv_content.setText(picture.getText_content().trim());
        }

        holder.img.setOnClickListener(v -> IntentHelper.toImageDetailActivity(mActivity, picture));

        holder.tv_author.setText(picture.getComment_author());
        holder.tv_time.setText(String2TimeUtil.dateString2GoodExperienceFormat(picture.getComment_date()));
        holder.tv_like.setText(picture.getVote_positive());
        holder.tv_comment_count.setText(picture.getComment_counts());

        //用于恢复默认的文字
        holder.tv_like.setTypeface(Typeface.DEFAULT);
        holder.tv_like.setTextColor(mActivity.getResources().getColor(
                secondary_text_default_material_light));
        holder.tv_support_des.setTextColor(mActivity.getResources().getColor(
                secondary_text_default_material_light));

        holder.tv_unlike.setText(picture.getVote_negative());
        holder.tv_unlike.setTypeface(Typeface.DEFAULT);
        holder.tv_unlike.setTextColor(mActivity.getResources().getColor(
                secondary_text_default_material_light));
        holder.tv_un_support_des.setTextColor(mActivity.getResources().getColor(
                secondary_text_default_material_light));

        holder.img_share.setOnClickListener(v -> new MaterialDialog.Builder(mActivity)
                .items(R.array.picture_dialog)
                .backgroundColor(mActivity.getResources().getColor(JDApplication.COLOR_OF_DIALOG))
                .contentColor(JDApplication.COLOR_OF_DIALOG_CONTENT)
                .itemsCallback((dialog, view, which, text) -> {

                    switch (which) {
                        case 0:
Answer:                             ShareUtil.sharePicture(mActivity, picture