2016/4/29
GitHub:https://github.com/qq137712630/MeiZiNews
碗豆夹下载地址:http://www.wandoujia.com/apps/com.ms.meizinewsapplication
#MeiZiNews
#Ночной режим: Colorful
Адрес: https://github.com/hehonghui/Colorful/issues/5
В итоге я добавил ((RecyclerView) rootView).getRecycledViewPool().clear(); в clearRecyclerViewRecyclerBin под retrofit+okhttp3.
public class RecyclerViewSetter extends ViewGroupSetter {
public RecyclerViewSetter(ViewGroup targetView, int resId) {
super(targetView, resId);
}
public RecyclerViewSetter(ViewGroup targetView) {
super(targetView);
}
@Override
protected void clearRecyclerViewRecyclerBin(View rootView) {
super.clearRecyclerViewRecyclerBin(rootView);
((RecyclerView) rootView).getRecycledViewPool().clear();
}
@Override
public void setValue(Resources.Theme newTheme, int themeId) {
clearRecyclerViewRecyclerBin(mView);
// Проходимся по дочерним элементам и свойствам, которые нужно изменить, если они совпадают, то меняем свойства дочернего View
for (ViewSetter setter : mItemViewSetters) {
for (int i = 0; i < ((RecyclerView) mView).getAdapter().getItemCount(); i++) {
View itemView = ((RecyclerView) mView).getChildAt(i);
if (itemView == null) {
continue;
}
boolean isBaseAdapterHelper = ((RecyclerView) mView).getChildViewHolder(itemView) instanceof BaseAdapterHelper;
if (!isBaseAdapterHelper) {
continue;
}
BaseAdapterHelper baseAdapterHelper = (BaseAdapterHelper) ((RecyclerView) mView).getChildViewHolder(itemView);
setter.mView = baseAdapterHelper.getView(setter.mViewId);
int itemId = setter.getViewId();
if (baseAdapterHelper.getView(itemId) == null) {
continue;
}
setter.setValue(newTheme, themeId);
}
}
}
}
#RxJava
Если читать в следующем порядке, то примерно поймёшь, как использовать
Объяснение Subject: перевод документации ReactiveX на китайский язык
Использование RxJava: Подробное руководство по RxJava для разработчиков Android На диаграмме всего 5 операций, связанных с событиями.
Из диаграммы видно, что операции ① и ② находятся под влиянием первого subscribeOn() и выполняются в красном потоке;
операции ③ и ④ находятся под влиянием первого observeOn() и выполняются в зелёном потоке;
операция ⑤ находится под влиянием второго observeOn() и выполняется в фиолетовом потоке;
а второй subscribeOn(), поскольку в процессе уведомления поток был прерван первым subscribeOn(), поэтому на весь процесс никак не влияет.
Здесь также был дан ответ на предыдущий вопрос: когда используется несколько subscribeOn(), действует только первый subscribeOn();
set subscribeOn() влияет на операции, находящиеся выше него, и только первый subscribeOn() вступает в силу;
set observeOn() влияет на операции ниже него до следующего set observeOn().
#GreenDAO
DbUtil /**
#Использование Retrofit
Настройка Retrofit 2.0 + OkHttp 3.0
Retrofit Создание среды RxAndroid+Retrofit
Конвертеры могут быть добавлены для поддержки других типов. Модули Six Sibling адаптируют популярные библиотеки сериализации для вашего удобства. Converters can be added to support other types. Six sibling modules adapt popular serialization libraries for your convenience.
Gson: com.squareup.retrofit2:converter-gson Jackson: com.squareup.retrofit2:converter-jackson Moshi: com.squareup.retrofit2:converter-moshi Protobuf: com.squareup.retrofit2:converter-protobuf Wire: com.squareup.retrofit2:converter-wire Simple XML: com.squareup.retrofit2:converter-simplexml Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars
Чтобы вернуть тип String, необходимо импортировать: ScalarsConverterFactory.create()
retrofit = new Retrofit.Builder() .client(MyOkHttpClient.getMyOkHttpClient().getOkHttpClient()) // установка другой базовой сетевой библиотеки .baseUrl(strBaseUrl) .addConverterFactory(ScalarsConverterFactory.create()) // добавление преобразователя типа String [Scalars (примитивы, упакованные и строковые)] .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // добавление адаптера RxJava .build();
Для возврата типа Gson необходимо импортировать: GsonConverterFactory.create()
retrofit = new Retrofit.Builder() .client(MyOkHttpClient.getMyOkHttpClient().getOkHttpClient()) // установка другой базовой сетевой библиотеки .baseUrl(strBaseUrl) .addConverterFactory(GsonConverterFactory.create()) // добавление json-преобразователя .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // добавление адаптера RxJava .build();
Использование Retrofit с RxJava
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4' compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
compile 'io.reactivex:rxandroid:1.1.0' compile 'io.reactivex:rxjava:1.1.0'
Первые два являются зависимостями Retrofit и Gson, третий — зависимостью RxJava-конвертера в Retrofit, последние два — зависимостями RxJava и Rx Android.
При использовании RxJava интерфейс файла немного изменяется, тип возвращаемого значения метода интерфейса больше не является Call, а является типом Observable:
public interface GitHub {
@GET("/repos/{owner}/{repo}/contributors") ``` Call<List> contributors(@Path("owner") String owner,@Path("repo") String repo);
// 使用 RxJava 的方法,返回一个 Observable
@GET("/repos/{owner}/{repo}/contributors")
Observable<List<Contributor>> RxContributors(@Path("owner") String owner, @Path("repo") String repo);
}
结合 RxJava 使用的 接口就定义好了,模型类不需要变动,接下来直接进行网络请求
使用 RxJava 的 Retrofit 可以直接在 主线程中编写。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create()) //添加 json 转换器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) //添加 RxJava 适配器
.build();
GitHub gitHub = retrofit.create(GitHub.class);
gitHub.RxContributors("square", "retrofit")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<List<Contributor>>() {
@Override
public void onCompleted() {
Log.i("TAG", "onCompleted");
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(List<Contributor> contributors) {
for (Contributor c : contributors) {
Log.i("TAG", "RxJava-->" + c.getLogin() + " " + c.getId() + " " + c.getContributions());
}
}
});
}
okhttp 请求设置官方文档 使用Retrofit和Okhttp实现网络缓存。无网读缓存,有网根据过期时间重新请求 OuNews 新闻:RetrofitManager类下的 initOkHttpClient 方法 okhttp3.X,retrofit:2.0.0-beta4适用
配置okhttp中的Cache
OkHttpClient okHttpClient; File cacheFile = new File(DemoActivity.this.getCacheDir(), "[缓存目录]"); Cache cache = new Cache(cacheFile, 1024 * 1024 * 10); //100Mb okHttpClient = new OkHttpClient.Builder() .cache(cache) .build();
栗子:
// 完成缓存
public class MyOkHttpClient {
//设缓存有效期为两天
protected static final long CACHE_STALE_SEC = 60 * 60 * 24 * 2;
//查询缓存的Cache-Control设置,为if-only-cache时只查询缓存而不会请求服务器,max-stale可以配合设置缓存失效时间
protected static final String CACHE_CONTROL_CACHE = "only-if-cached, max-stale=" + CACHE_STALE_SEC;
//查询网络的Cache-Control设置,头部Cache-Control设为max-age=0时则不会使用缓存而请求服务器
protected static final String CACHE_CONTROL_NETWORK = "max-age=0";
private String TAG = "MyOkHttpClient";
private OkHttpClient okHttpClient;
private static MyOkHttpClient myOkHttpClient;
public static MyOkHttpClient getMyOkHttpClient() {
if (myOkHttpClient == null) {
myOkHttpClient = new MyOkHttpClient();
}
return myOkHttpClient;
}
/**
* 初始化
*
* @param mContext
*/
public void init(final Context mContext) {
if (okHttpClient != null) {
return;
}
Log.e(TAG, "初始化okHttpClient");
// 因为BaseUrl不同所以这里Retrofit不为静态,但是OkHttpClient配置是一样的,静态创建一次即可
File cacheFile = new File(
mContext.getCacheDir(),
"HttpCache"
); // 指定缓存路径
Cache cache = new Cache(cacheFile, 1024 * 1024 * 100); // 指定缓存大小100Mb
// 云端响应头拦截器,用来配置缓存策略
Interceptor rewriteCacheControlInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!NetUtil.isConnected(mContext)) {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE).build();
Log.e(TAG, "no network");
}
Response originalResponse = chain.proceed(request);
if (NetUtil.isConnected(mContext)) {
//有网的时候读接口上的@Headers里的配置,你可以在这里进行统一的设置
String cacheControl = request.cacheControl().toString();
return originalResponse.newBuilder()
.header("Cache-Control", cacheControl)
.removeHeader("Pragma").build();
} else {
return originalResponse.newBuilder().header("Cache-Control",
"public, only-if-cached," + CACHE_STALE_SEC)
.removeHeader("Pragma").build();
}
}
};
okHttpClient = new OkHttpClient.Builder().cache(cache)
.addNetworkInterceptor(rewriteCacheControlInterceptor)
.addInterceptor(rewriteCacheControlInterceptor)
.connectTimeout(30, TimeUnit.SECONDS).build();
}
public OkHttpClient getOkHttpClient() {
return okHttpClient;
}
/**
* 根据网络状况获取缓存的策略
*
* @return
*/
@NonNull
public static String getCacheControl(Context mContext) {
return NetUtil.isConnected(mContext) ? CACHE_CONTROL_NETWORK : CACHE_CONTROL_CACHE;
}
}
配置请求头中的cache-control
//使用 RxJava 的方法,返回一个 Observable
@Headers("Cache-Control: public, max-age=3600")
@GET("/repos/{owner}/{repo}/contributors")
Observable<List<Contributor>> RxContributors(@Path("owner") String owner,@Path("repo") String repo);
配置请求 Retrofit 设置不同的底层网络库
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClient)
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())//添加 json 转换器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())//添加 RxJava 适配器
.build();
开启打印连接日志
/**
* 开启打印连接日志
* @return
*/
private HttpLoggingInterceptor getHttpLoggingInterceptor() {
boolean isDebug= false;//是否开启
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
if(isDebug)
{
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
}
//开启打印连接日志
return interceptor;
}
OkHttpClient.Builder().addInterceptor(getHttpLoggingInterceptor())
okHttpClient = new OkHttpClient.Builder()
.addInterceptor(getHttpLoggingInterceptor())
.cache(cache)
.addNetworkInterceptor(rewriteCacheControlInterceptor)
.addInterceptor(rewriteCacheControlInterceptor)
.connectTimeout(30, TimeUnit.SECONDS).build();
参考 ````` MzituImgListModel ````
/**
* Retrofit 使用Observable.from发出多条连接
* @param context
* @param listener
* @return
*/
@Override
public Subscription loadWeb(final Context context, final OnModelListener<ImgItem> listener) {
Перевод на русский язык:
Кэш кэш = новый Кэш(кэшФайл, 1024 * 1024 * 100); // Указать размер кэша 100 Мб // Перехватчик заголовков ответов в облаке, используемый для настройки стратегии кэширования Перехватчик rewriteCacheControlInterceptor = новый Перехватчик() { @Override public Ответ перехватить(Цепь цепь) выбрасывает IOException { Запрос запрос = цепь.запрос(); если (!NetUtil.подключено(mКонтекст)) { запрос = запрос.новыйСтроитель() .кэширование(Кэширование.FORCE_КЭШ).построить(); Журнал.е(ТЕГ, "нет сети"); } Ответ оригинальныйОтвет = цепь.продолжить(запрос); если (NetUtil.подключено(mКонтекст)) { // При наличии сети прочитайте конфигурацию в @Headers на интерфейсе, здесь можно выполнить единую настройку Строка кэширование = запрос.кэширование().toString(); вернуть оригинальныйОтвет.новыйСтроитель() .заголовок("Кэширование-Контроль", кэширование) .удалитьЗаголовок("Прагма").построить(); } еще { возврат оригинальныйОтвет.новыйСтроитель().заголовок("Кэширование-Контроль", "общедоступно, только-если-кэшировано," + CACHE_STALE_SEC) .удалитьЗаголовок("Прагма").построить(); } } }; окHttpClient = новый ОкHttpClient.Строитель().кэш(кэш) .добавитьСетевойПерехватчик(rewriteCacheControlInterceptor) .добавитьПерехватчик(rewriteCacheControlInterceptor) .времяПодключения(30, ЕдиницаВремени.СЕКУНДЫ).построить();
}
общедоступный ОкHttpClient получитьОкHttpClient() {
возврат окHttpClient;
}
/**
* Получить стратегию кэширования в зависимости от состояния сети
*
* @return
*/
@NonNull
публичная статическая строка getCacheControl(контекст mContext) {
возвращение NetUtil.подключено(mContext)? CACHE_CONTROL_СЕТЬ: CACHE_CONTROL_КЭШ;
}
}
Настройка cache-control в заголовках запросов
// Использование метода RxJava, возвращает Observable
@Заголовки("Кэширование-Управление: общедоступное, максимальный возраст=3600")
@ПОЛУЧИТЬ("/repos/{владелец}/{репо}/участники")
Наблюдаемый<Список<Участник>> RxУчастники(@Путь("владелец") Строка владелец, @Путь("репо") Строка репо);
Настройка запроса Retrofit для установки различных базовых сетевых библиотек
Ретрофит ретрофит = новый Ретрофит.Строитель()
.клиент(окHttpClient)
.базовыйURL("https://api.github.com")
.добавитьФабрикаПреобразователей(GsonConverterFactory.создать()) // Добавить преобразователь JSON
.добавитьФабрикаАдаптеровВызовов(RxJavaCallAdapterFactory.создать()) // Добавить адаптер RxJava
.построить();
Включение ведения журнала подключений
/**
* Включение ведения журнала подключений
* @return
*/
частный HttpLoggingInterceptor получитьHttpLoggingInterceptor() {
логическое значение isDebug = false; // Включить ли
HttpLoggingInterceptor перехватчик = новый HttpLoggingInterceptor();
если (isDebug) {
перехватчик.setLevel(HttpLoggingInterceptor.Уровень.ТЕЛО);
}
// Включить ведение журнала подключений
возврат перехватчика;
}
ОкHttpClient.Строитель().добавитьПерехватчик(получитьHttpLoggingInterceptor())
окHttpClient = новый ОкHttpClient.Строитель()
.добавитьПерехватчик(получитьHttpLoggingInterceptor())
.кэш(кэш)
.добавитьСетевойПерехватчик(rewriteCacheControlInterceptor)
.добавитьПерехватчик(rewriteCacheControlInterceptor)
.времяПодключения(30, ЕдиницаВремени.СЕКУНДЫ).построить();
См. ````` MzituImgListModel ```
/**
* Использование Observable.from в Retrofit для отправки нескольких подключений
* @param контекст
* @param слушатель
* @return
*/
@Переопределить
общедоступная подписка loadWeb(окончательный контекст контекста, окончательный OnModelListener<ImgItem> слушатель) { ```
MyStringRetrofit.getMyStringRetrofit().init(context, MeiZiApi.MZITU_API); final MzituApi mzituApi = MyStringRetrofit.getMyStringRetrofit().getCreate(MzituApi.class);
Observable observable = mzituApi.RxImgList( MyOkHttpClient.getCacheControl(context), imgId, page ).flatMap( new Func1<String, Observable>() { @Override public Observable call(String s) { // 第一次请求先请求页数,从而获得要发的链接数
Elements mElements = JsoupUtil.getMzituImgPage(s);
Elements tempElements = mElements.select("span");
String size = tempElements.get(tempElements.size() - 2).text();
if (TextUtils.isEmpty(size)) {
return null;
}
ArrayList<Integer> numList = new ArrayList<Integer>();
for (int i = 1; i <= Integer.parseInt(size); i++) {
numList.add(i);
}
return Observable.from(numList);
}
}
).flatMap( new Func1<Integer, Observable>() { @Override public Observable call(Integer integer) { // 发出单次网络请求连接 return mzituApi.RxImgList( MyOkHttpClient.getCacheControl(context), imgId, integer + "" ); } } ).map( new Func1<String, ImgItem>() { @Override public ImgItem call(String s) { // 处理每次请问的结果
ImgItem img = new ImgItem();
Elements mElements = JsoupUtil.getMzituImgItem(s);
Element tempElement = mElements.first();
img.setImgUrl(tempElement.select("img").attr("src"));
img.setUrl(tempElement.select("img").attr("src"));
img.setStory_title(tempElement.select("img").attr("alt"));
return img;
}
}
);
return RxJavaUtil.rxIoAndMain( observable, new Subscriber() { @Override public void onCompleted() { listener.onCompleted(); }
@Override
public void onError(Throwable e) {
listener.onError(e.toString());
DebugUtil.debugLogErr(e, e.toString());
}
@Override
public void onNext(ImgItem imgItem) {
listener.onSuccess(imgItem);
}
}
);
}
{
"hls_url": "http://hls3a.douyutv.com/live/73334rRfZajWPCGs_550/playlist.m3u8?wsSecret=c52bca967d3b341d878291b7901c800b&wsTime=1462084010",
"is_pass_player": false,
"is_ticket": 0
}
### 熊猫TV
分类:
http://www.panda.tv/cate
分页
http://www.panda.tv/ajax_sort?pageno=1&pagenum=20&classification=lol
http://www.panda.tv/ajax_sort?token=&pageno=2&pagenum=120&classification=lol
房间:
http://www.panda.tv/354095
房间信息
http://room.api.m.panda.tv/index.php?method=room.shareapi&roomid=354095
http://room.api.m.panda.tv/index.php?method=room.shareapi&roomid=354095&callback=jQuery1910274208655487177_1462807801662&_=1462807801663
http://room.api.m.panda.tv/index.php?method=room.recommend&callback=jQuery1910274208655487177_1462807801664&_=1462807801665
## 妹子图集
// 专题
http://www.mzitu.com/zhuanti
// 首页
http://www.mzitu.com/
http://www.mzitu.com/page/1
// 热门
http://www.mzitu.com/hot
http://www.mzitu.com/hot/page/2
// 推荐
http://www.mzitu.com/best
http://www.mzitu.com/best/page/2
// 性感妹子
http://www.mzitu.com/xinggan
http://www.mzitu.com/xinggan/page/2
// 日本妹子
http://www.mzitu.com/japan
http://www.mzitu.com/japan/page/2
// 台湾妹子
http://www.mzitu.com/taiwan
http://www.mzitu.com/taiwan/page/2
// 清纯
http://www.mzitu.com/mm
http://www.mzitu.com/mm/page/2
// 图集查看
http://www.mzitu.com/{图集ID}/{页数}
http://www.mzitu.com/65054/48
## 永久免费的基于深度学习的中文在线抽词-PullWord
[永久免费的基于深度学习的中文在线抽词-PullWord](http://www.pullword.com/)
[API 使用](http://api.pullword.com/)
API:
http://103.37.149.178:16888/pullword/get.php?source=清华大学是好学校¶m1=0¶m2=1
## 知乎日报
//Zhihu API
public static final String BASE_URL = "http://news-at.zhihu.com/api/4/news/";//日报详情
public static final String NEWS_LATEST = "http://news-at.zhihu.com/api/4/news/latest";//最新日报
public static final String NEWS_BEFORE = "http://news-at.zhihu.com/api/4/news/before/";//指定日期的日报
public static final String SPLASH = "http://news-at.zhihu.com/api/4/start-image/1080*1920";//封面
http://news-at.zhihu.com/api/4/themes // 主题日报列表查看
http://news-at.zhihu.com/api/4/theme/{id} //主题日报内容查看
- 日报详情
BASE_URL+日报ID
[http://news-at.zhihu.com/api/4/news/7942211](http://news-at.zhihu.com/api/4/news/7942211)
- 最新日报
直接访问:NEWS_LATEST
[http://news-at.zhihu.com/api/4/news/latest](http://news-at.zhihu.com/api/4/news/latest)
- 指定日期的日报
NEWS_BEFORE+(指定日期+1天),格式为全数字,YYYYMMDD,如:
2016年02月29号的数据:
[http://news-at.zhihu.com/api/4/news/before/20160301](http://news-at.zhihu.com/api/4/news/before/20160301)
- 主题日报
http://news-at.zhihu.com/api/4/themes // 主题日报列表查看
http://news-at.zhihu.com/api/4/theme/{id} //主题日报内容查看
[http://news-at.zhihu.com/api/4/theme/11](http://news-at.zhihu.com/api/4/theme/11)
## 豆瓣美女
public static String DB_BREAST = "http://www.dbmeinv.com/dbgroup/show.htm?cid=2&pager_offset=";
public static String DB_BUTT = "http://www.dbmeinv.com/dbgroup/show.htm?cid=6&pager_offset=";
public static String DB_SILK = "http://www.dbmeinv.com/dbgroup/show.htm?cid=7&pager_offset=";
public static String DB_LEG = "http://www.dbmeinv.com/dbgroup/show.htm?cid=3&pager_offset=";
public static String DB_RANK="http://www.dbmeinv.com/dbgroup/rank.htm?pager_offset=";
## Android开发技术周报
网址
[http://androidweekly.cn](http://androidweekly.cn)
例子:
[http://androidweekly.cn/page/2/](http://androidweekly.cn/page/2/)
---
#MD实践
- [Android Design Support Library使用详解](http://blog.csdn.net/eclipsexys/article/details/46349721)
- [NestedScrollView: 兼容MD的 ScrollView ](http://blog.csdn.net/hangeqq685042/article/details/48129911)
- [Android L动画入门](http://blog.jobbole.com/77015/)
- [ANDROID L——Material Design详解(动画篇)](http://blog.csdn.net/a396901990/article/details/40187203)
- [ Android M新控件之FloatingActionButton,TextInputLayout,Snackbar,TabLayout的使用](http://blog.csdn.net/feiduclear_up/article/details/46500865)
- [Android ## Боковая панель NavigationView
Самый быстрый способ — создать новый модуль боковой панели.
- [windowDrawsSystemBarBackgrounds: как отобразить DrawerLayout поверх ActionBar/Toolbar и под строкой состояния](http://solo.farbox.com/blog/how-do-i-use-drawerlayout-to-display-over-the-actionbar-or-toolbar-and-under-the-status-bar)
- [Android: собственная реализация NavigationView [Design Support Library]](http://blog.csdn.net/lmj623565791/article/details/46405409)
- [android, NavigationView's setItemTextColor and setItemIconTinList have no effects](http://stackoverflow.com/questions/33114154/android-navigationviews-setitemtextcolor-and-setitemicontinlist-have-no-effect)
### Установка цвета элемента
В коде:
int[][] states = new int[][] { new int[] { android.R.attr.state_selected }, // selected new int[] { android.R.attr.state_focused, android.R.attr.state_pressed }, // pressed new int[] { }, // default };
int[] colors = new int[] { 0, 0, getColor(newTheme) }; navigationView.setItemTextColor(new ColorStateList( states, colors ));
XML
<android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" android:fitsSystemWindows="true" android:background="?attr/root_view_bg" app:headerLayout="@layout/nav_header_main" app:itemTextColor="?attr/text_color" app:menu="@menu/activity_main_drawer" />
## Свайп вверх-вниз: SwipeRefreshLayout
- [Официальный обзор компонента SwipeRefreshLayout для Android](http://blog.csdn.net/lmj623565791/article/details/24521483)
- [Полное объяснение RecyclerView: свайп вниз для обновления и свайп вверх для загрузки с помощью SwipeRefreshLayout](http://www.lcode.org/recyclerview%E5%AE%8C%E5%85%A8%E8%A7%A3%E6%9E%90%E4%B9%8B%E4%B8%8B%E6%8B%89%E5%88%B7%E6%96%B0%E4%B8%8E%E4%B8%8A%E6%8B%89%E5%8A%A0%E8%BD%BDswiperefreshlayout/)
- [Разбор примеров: SwipeRefreshLayout + RecyclerView + CardView](http://www.lcode.org/%E5%AE%9E%E4%BE%8B%E8%A7%A3%E6%9E%90%E4%B9%8Bswiperefreshlayoutrecyclerviewcardview/)
- [Компонент официального обновления Google — SwipeRefreshLayout](https://github.com/stormzhang/SwipeRefreshLayoutDemo)
## Шапка: CoordinatorLayout CollapsingToolbarLayout
- [Обработка CoordinatorLayout с прокруткой](http://www.open-open.com/lib/view/open1437312265428.html)
- [Стоит ли использовать fitsSystemWindows!](http://ju.outofmemory.cn/entry/247350) или [Стоит ли использовать fitsSystemWindows!]( http://blog.chengyunfeng.com/?p=905)
以哪个为固定:
android:fitsSystemWindows="true"
### CoordinatorLayout
- [Свойства компонентов Android](http://blog.csdn.net/mg505/article/details/7714658)
Резюме: чтобы у Toolbar был эффект скольжения, необходимо выполнить следующие три условия:
Примечание: если CoordinatorLayout является самым внешним макетом, его следует удалить:
1. CoordinatorLayout должен быть родительским контейнером всего макета.
2. Установите свойство app:layout_scrollFlags=”scroll|enterAlways” для компонентов, которые должны скользить.
3. Установите для своих скользящих компонентов (RecyclerView или NestedScrollView) следующее свойство:
app:layout_behavior="@string/appbar_scrolling_view_behavior"
---
# RecyclerView
[Введение в использование RecyclerView](http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1118/2004.html)
[Версия base-adapter-helper для RecyclerView](http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0809/3277.html)
## Прослушивание свайпа вверх-вниз
`SwipeRefreshLayout.OnRefreshListener` прослушивает свайпы вниз
`RecyclerView.OnScrollListener` отслеживает до конца
[Одноточечный RecyclerView для обновления Android](http://blog.csdn.net/qqqgl/article/details/50353642)
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == RecyclerView.SCROLL_STATE_IDLE) { onListScrolled(); } } });
## Несколько элементов RecyclerView
[Несколько элементов RecyclerView](http://ju.outofmemory.cn/entry/185097)
Здесь getItemViewType используется для возврата типа макета текущего элемента, а getViewTypeCount возвращает общее количество типов макетов в текущем ListView.
Если вы хотите реализовать несколько типов элементов в RecyclerView, вам нужно только реализовать один метод getItemType, который используется для возврата типа элемента. В методах onCreateViewHolder и onBindViewHolder вторым параметром является тип элемента.
# Glide
[Предварительный просмотр серии Glide](http://mrfu.me/2016/02/27/Glide_Getting_Started/)
# Github Android библиотека с открытым исходным кодом
[Топ-100 библиотек Android с открытым исходным кодом на GitHub](https://github.com/Freelander/Android_Data/blob/master/Android-Librarys-Top-100.md#rd)
# Прочее
- [Введение в интернет-протоколы (часть 1)](http://blog.jobbole.com/77851/#comment-64486)
- [12 уроков для начинающих разработчиков Android](http://android.jobbole.com/76447/)
- [Свойство android:configChanges](http://blog.csdn.net/goyoung/article/details/8921139)
- [Свойство android:screenOrientation](http://blog.csdn.net/nmgchfzhzhg/article/details/8077133)
- [Подробное руководство по ToolBar для Android (руководство)](http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1118/2006.html)
- [Чтобы Fragment не создавался заново, напишите код onCreateView и onDestroyView в BaseFragment класса OuNews](https://github.com/oubowu/OuNews/blob/a42f773e26a27eeadda385afaa40f8fc8e5745dc/app/src/main/java/com/oushangfeng/ounews/base/BaseFragment.java)
- [menu-Подробное объяснение ActionBar в Android](http://blog.csdn.net/huiguixian/article/details/9836189)
- [Изучение Android (27): Menu](http://blog.csdn.net/flowingflying/article/details/6317632)
- [spinBars-Android – Navigation Drawer на панели инструментов](http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1123/2050.html)
- [Шаблон проектирования Android – Singleton](http://mp.weixin.qq.com/s?__biz=MzA4NTQwNDcyMA==&mid=403126596&idx=1&sn=101c6d4e363213bcdbe1879edeb08736&scene=23&srcid=0405dfOnHTLZxrgDaQMKMcNR#rd)
- [Обработка виртуальной клавиатуры: анализ методов скрытия и отображения виртуальной клавиатуры в Android и предотвращения автоматического появления клавиатуры](http://www.jb51.net/article/36653.htm)
- [Обработка виртуальной клавиатуры: подробное объяснение свойства android:windowSoftInputMode](http://blog.csdn.net/twoicewoo/article/details/7384398)
- [win10 Genymotion не запускается: virtualbox не может запустить виртуальное устройство: GenyMotion не может запустить виртуальное устройство Genymotion](http://stackoverflow.com/questions/19922077/genymotion-unable-to-start-the-genymotion-virtual-device)
- [Прозрачность аннотаций Gson@Expose, @SerializedName, анализ данных json](http://blog.csdn.net/andywuchuanlong/article/details/44077913)
- [Встроенный совместимый элемент управления RecyclerView для Android 5.0](http://blog.csdn.net/rozol/article/details/50225593)
- [Реализация pull-to-refresh и автоматической загрузки в RecyclerView](http://www.jianshu.com/p/4feb0c16d1b5)
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int lastVisibleItem = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition(); int totalItemCount = mLayoutManager.getItemCount(); //lastVisibleItem >= totalItemCount - 4 表示剩下4个item自动加载,各位自由选择 // dy>0 表示向下滑动 if (lastVisibleItem >= totalItemCount - 4 && dy > 0) { if(isLoadingMore){ Log.d(TAG,"ignore manually update!"); } else{ loadPage();//这里多线程也要手动控制isLoadingMore isLoadingMore = false; } } } });
- [Отслеживание прокрутки RecyclerView до конца путём переопределения OnScrollListener](http://www.cnblogs.com/tianzhijiexian/p/4397552.html)
# Вопрос
- Можно ли динамически загружать XML-макет, как Jsp?
# Странные ошибки
## Ошибки, возникающие во время компиляции
Решаются путём очистки кэша проекта.
Первый:
04-19 20:57:09.844 31614-31614/com.ms.meizinewsapplication E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.ms.meizinewsapplication, PID: 31614
java.lang.NoSuchMethodError: Нет виртуального метода setMenuItemIconByCollect(Z)V в классе Lcom/ms/meizinewsapplication/features/main/iview/DevWeekDetailIVew или его суперклассах (объявление 'com.ms.meizinewsapplication.features.main.iview.DevWeekDetailIVew' появляется в /data/data/com.ms.meizinewsapplication/files/instant-run/dex/slice-slice_4-classes.dex)
at com.ms.meizinewsapplication.features.main.activity.DevWeekDetailActivity$2.onMenuItemClick(DevWeekDetailActivity.java:160)
at android.support.v7.widget.Toolbar$1.onMenuItemClick(Toolbar.java:169)
at android.support.v7.widget.ActionMenuView$MenuBuilderCallback.onMenuItemSelected(ActionMenuView.java:760) android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:811)
at android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:152)
at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:958)
at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:948)
at android.support.v7.widget.ActionMenuView.invokeItem(ActionMenuView.java:618)
at android.support.v7.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:139)
at android.view.View.performClick(View.java:4908)
at android.view.View$PerformClick.run(View.java:20378)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5691)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:959)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:754)
Второй:
04-19 20:13:37.194 5338-5416/com.ms.meizinewsapplication E/AndroidRuntime: FATAL EXCEPTION: RxCachedThreadScheduler-2
Process: com.ms.meizinewsapplication, PID: 5338
java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.Worker thread.
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:62)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.NoSuchMethodError: No virtual method addCollectByUrl(Ljava/lang/String;Ljava/lang/String;)Z in class Lcom/ms/meizinewsapplication/features/base/utils/db/DbUtil; or its super classes (declaration of 'com.ms.meizinewsapplication.features.base.utils/db/DbUtil' appears in /data/data/com.ms.meizinewsapplication/files/instant-run/dex/slice-slice_9-classes.dex)
at com.ms.meizinewsapplication.features.base.model.CollectModel$1.call(CollectModel.java:44)
at com.ms.meizinewsapplication.features.base.model.CollectModel$1.call(CollectModel.java:39)
at rx.internal.operators.OperatorMap$1.onNext(OperatorMap.java:54)
at rx.internal.util.ScalarSynchronousObservable$1.call(ScalarSynchronousObservable.java:46)
at rx.internal.util.ScalarSynchronousObservable$1.call(ScalarSynchronousObservable.java:35)
at rx.Observable$2.call(Observable.java:162)
at rx.Observable$2.call(Observable.java:154)
at rx.Observable.unsafeSubscribe(Observable.java:8098)
at rx.internal.operators.OperatorSubscribeOn$1$1.call(OperatorSubscribeOn.java:62)
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at ```
java.lang.Thread.run(Thread.java:818)
## app首次打开要很长时间
First launch take long time in Android Studio 2.0 & Gradle 2.0
所报日志:
04-27 10:24:16.241 12442-12450/com.ms.meizinewsapplication W/art: Приостановка всех потоков заняла: 8.750 мс
04-27 10:24:16.394 12442-12442/com.ms.meizinewsapplication W/art: До Android 4.1 метод android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) неправильно переопределял закрытый пакетный метод в android.graphics.drawable.Drawable
04-27 10:24:16.552 12442-12802/com.ms.meizinewsapplication D/OpenGLRenderer: Используйте EGL_SWAP_BEHAVIOR_PRESERVED: true
[ 04-27 10:24:16.554 12442:12442 D/ ]
HostConnection::get() Новое соединение Host Connection установлено 0xb4305d40, tid 12442
04-27 10:24:16.556 12442-12442/com.ms.meizinewsapplication D/Atlas: Проверка карты...
原因:
В версии 2.0 была добавлена новая функция — «мгновенный запуск».
Чтобы включить эту функцию, инструмент добавляет большое количество метаданных, поэтому первая сборка и загрузка занимают больше времени.
Обратите внимание на установку minSdkVersion 15 или выше, чтобы получить любую прибыль.
In version 2.0 a new feature was added instant-run.
To enable this feature tool adds a lots of meta information, so the first build and upload takes more time.
Be aware about setting minSdkVersion 15 or higher to get any profit.
解决步骤:
1. Нажмите: Settings → Build, Execution, Deployment → Instant Run
2. Снимите флажок: Enable Instant Run to hot swap code/resoure changes on deploy
Это отключит функцию «мгновенного запуска», но может решить эту проблему.
## VerticalDrawerLayout можно нажать на элемент управления за выдвижным ящиком
- [можно нажать на элемент управления за выдвижным ящиком #2](https://github.com/corerzhang/VerticalDrawerLayout/issues/2)
## Изменение строки состояния
- [sdk21 и выше изменение строки состояния: как изменить цвет строки состояния в Android](http://stackoverflow.com/questions/22192291/how-to-change-the-status-bar-color-in-android)
- [Android KITKAT и выше реализация погружной строки состояния](http://www.jianshu.com/p/f8374d6267ef/)
---
# Увеличение адаптера для групп: BaseTypeItemQuickAdapter
Главным образом это образец BaseQuickAdapter, перезапись getItemViewType, основные изменения следующие:
/**
* Возвращаемое расположение суждения
* @param position
* @return
*/
@Override
public int getItemViewType(int position) {
if (position == 0 || oldCount == position) {
return TYPE_TITLE;
} else {
return TYPE_ITEM;
}
}
/**
* Для различных типов операций
* @param viewGroup
* @param viewType
* @return
*/
@Override
public BaseAdapterHelper onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View view = null;
switch (viewType) {
case TYPE_TITLE:
view = LayoutInflater.from(viewGroup.getContext()).inflate(titleLayoutResId, viewGroup, false);
break;
case TYPE_ITEM:
view = LayoutInflater.from(viewGroup.getContext()).inflate(itemLayoutResId, viewGroup, false);
break;
}
if (view == null) {
return null;
}
view.setOnClickListener(this);
BaseAdapterHelper vh = new BaseAdapterHelper(view);
return vh;
}
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )