Java tutorial
/* * Copyright (C) 2015 Drakeet <drakeet.me@gmail.com> * * This file is part of Meizhi * * Meizhi is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Meizhi is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Meizhi. If not, see <http://www.gnu.org/licenses/>. */ package me.drakeet.meizhi.ui; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.support.design.widget.Snackbar; import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityOptionsCompat; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; import android.view.Menu; import android.view.MenuItem; import android.view.View; import butterknife.Bind; import butterknife.ButterKnife; import butterknife.OnClick; import com.litesuits.orm.db.assit.QueryBuilder; import com.litesuits.orm.db.model.ConflictAlgorithm; import com.squareup.picasso.Callback; import com.squareup.picasso.Picasso; import com.umeng.analytics.MobclickAgent; import com.umeng.update.UmengUpdateAgent; import java.util.ArrayList; import java.util.Date; import java.util.List; import me.drakeet.meizhi.App; import me.drakeet.meizhi.R; import me.drakeet.meizhi.data.MeizhiData; import me.drakeet.meizhi.data.entity.Gank; import me.drakeet.meizhi.data.entity.Meizhi; import me.drakeet.meizhi.data.?Data; import me.drakeet.meizhi.func.OnMeizhiTouchListener; import me.drakeet.meizhi.ui.adapter.MeizhiListAdapter; import me.drakeet.meizhi.ui.base.SwipeRefreshBaseActivity; import me.drakeet.meizhi.util.AlarmManagers; import me.drakeet.meizhi.util.Dates; import me.drakeet.meizhi.util.Once; import me.drakeet.meizhi.util.PreferencesLoader; import me.drakeet.meizhi.util.Toasts; import rx.Observable; import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; public class MainActivity extends SwipeRefreshBaseActivity { private static final int PRELOAD_SIZE = 6; @Bind(R.id.rv_meizhi) RecyclerView mRecyclerView; private MeizhiListAdapter mMeizhiListAdapter; private List<Meizhi> mMeizhiList; private boolean mIsFirstTimeTouchBottom = true; private int mPage = 1; private boolean mMeizhiBeTouched; @Override protected int provideContentViewId() { return R.layout.activity_main; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ButterKnife.bind(this); mMeizhiList = new ArrayList<>(); QueryBuilder query = new QueryBuilder(Meizhi.class); query.appendOrderDescBy("publishedAt"); query.limit(0, 10); mMeizhiList.addAll(App.sDb.query(query)); setupRecyclerView(); setupUmeng(); AlarmManagers.register(this); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); new Handler().postDelayed(() -> setRefresh(true), 358); loadData(true); } private void setupUmeng() { UmengUpdateAgent.update(this); UmengUpdateAgent.setDeltaUpdate(false); UmengUpdateAgent.setUpdateOnlyWifi(false); } private void setupRecyclerView() { final StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL); mRecyclerView.setLayoutManager(layoutManager); mMeizhiListAdapter = new MeizhiListAdapter(this, mMeizhiList); mRecyclerView.setAdapter(mMeizhiListAdapter); new Once(this).show("tip_guide_6", () -> { Snackbar.make(mRecyclerView, getString(R.string.tip_guide), Snackbar.LENGTH_INDEFINITE) .setAction(R.string.i_know, v -> { }).show(); }); mRecyclerView.addOnScrollListener(getOnBottomListener(layoutManager)); mMeizhiListAdapter.setOnMeizhiTouchListener(getOnMeizhiTouchListener()); } /** * ??? * * @param clean ??? */ private void loadData(boolean clean) { mLastVideoIndex = 0; // @formatter:off Subscription s = Observable .zip(sGankIO.getMeizhiData(mPage), sGankIO.get?Data(mPage), this::createMeizhiDataWith?Desc) .map(meizhiData -> meizhiData.results) .flatMap(Observable::from) .toSortedList((meizhi1, meizhi2) -> meizhi2.publishedAt.compareTo(meizhi1.publishedAt)) .doOnNext(this::saveMeizhis) .observeOn(AndroidSchedulers.mainThread()) .finallyDo(() -> setRefresh(false)) .subscribe(meizhis -> { if (clean) mMeizhiList.clear(); mMeizhiList.addAll(meizhis); mMeizhiListAdapter.notifyDataSetChanged(); setRefresh(false); }, throwable -> loadError(throwable)); // @formatter:on addSubscription(s); } private void loadError(Throwable throwable) { throwable.printStackTrace(); Snackbar.make(mRecyclerView, R.string.snap_load_fail, Snackbar.LENGTH_LONG).setAction(R.string.retry, v -> { requestDataRefresh(); }).show(); } private void saveMeizhis(List<Meizhi> meizhis) { App.sDb.insert(meizhis, ConflictAlgorithm.Replace); } private MeizhiData createMeizhiDataWith?Desc(MeizhiData data, ?Data love) { for (Meizhi meizhi : data.results) { meizhi.desc = meizhi.desc + " " + getFirstVideoDesc(meizhi.publishedAt, love.results); } return data; } private int mLastVideoIndex = 0; private String getFirstVideoDesc(Date publishedAt, List<Gank> results) { String videoDesc = ""; for (int i = mLastVideoIndex; i < results.size(); i++) { Gank video = results.get(i); if (video.publishedAt == null) video.publishedAt = video.createdAt; if (Dates.isTheSameDay(publishedAt, video.publishedAt)) { videoDesc = video.desc; mLastVideoIndex = i; break; } } return videoDesc; } private void loadData() { loadData(/* clean */false); } private OnMeizhiTouchListener getOnMeizhiTouchListener() { return (v, meizhiView, card, meizhi) -> { if (meizhi == null) return; if (v == meizhiView && !mMeizhiBeTouched) { mMeizhiBeTouched = true; Picasso.with(this).load(meizhi.url).fetch(new Callback() { @Override public void onSuccess() { mMeizhiBeTouched = false; startPictureActivity(meizhi, meizhiView); } @Override public void onError() { mMeizhiBeTouched = false; } }); } else if (v == card) { startGankActivity(meizhi.publishedAt); } }; } private void startGankActivity(Date publishedAt) { Intent intent = new Intent(this, GankActivity.class); intent.putExtra(GankActivity.EXTRA_GANK_DATE, publishedAt); startActivity(intent); } private void startPictureActivity(Meizhi meizhi, View transitView) { Intent intent = PictureActivity.newIntent(MainActivity.this, meizhi.url, meizhi.desc); ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this, transitView, PictureActivity.TRANSIT_PIC); try { ActivityCompat.startActivity(MainActivity.this, intent, optionsCompat.toBundle()); } catch (IllegalArgumentException e) { e.printStackTrace(); startActivity(intent); } } @Override public void onToolbarClick() { mRecyclerView.smoothScrollToPosition(0); } @OnClick(R.id.main_fab) public void onFab(View v) { if (mMeizhiList != null && mMeizhiList.size() > 0) { startGankActivity(mMeizhiList.get(0).publishedAt); } } @Override public void requestDataRefresh() { super.requestDataRefresh(); mPage = 1; loadData(true); } private void openGitHubTrending() { String url = getString(R.string.url_github_trending); String title = getString(R.string.action_github_trending); Intent intent = WebActivity.newIntent(this, url, title); startActivity(intent); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); MenuItem item = menu.findItem(R.id.action_notifiable); initNotifiableItemState(item); return true; } private void initNotifiableItemState(MenuItem item) { PreferencesLoader loader = new PreferencesLoader(this); item.setChecked(loader.getBoolean(R.string.action_notifiable, true)); } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); switch (id) { case R.id.action_trending: openGitHubTrending(); return true; case R.id.action_notifiable: boolean isChecked = !item.isChecked(); item.setChecked(isChecked); PreferencesLoader loader = new PreferencesLoader(this); loader.saveBoolean(R.string.action_notifiable, isChecked); Toasts.showShort(isChecked ? R.string.notifiable_on : R.string.notifiable_off); return true; } return super.onOptionsItemSelected(item); } RecyclerView.OnScrollListener getOnBottomListener(StaggeredGridLayoutManager layoutManager) { return new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView rv, int dx, int dy) { boolean isBottom = layoutManager.findLastCompletelyVisibleItemPositions( new int[2])[1] >= mMeizhiListAdapter.getItemCount() - PRELOAD_SIZE; if (!mSwipeRefreshLayout.isRefreshing() && isBottom) { if (!mIsFirstTimeTouchBottom) { mSwipeRefreshLayout.setRefreshing(true); mPage += 1; loadData(); } else { mIsFirstTimeTouchBottom = false; } } } }; } @Override public void onResume() { super.onResume(); MobclickAgent.onResume(this); } @Override public void onPause() { super.onPause(); MobclickAgent.onPause(this); } @Override protected void onDestroy() { super.onDestroy(); ButterKnife.unbind(this); } }