TabLayout

  • 步骤:
    1. 布局(TabLayout和ViewPager位置关系);
    2. 自定义Adapter(继承自 FragmentPagerAdapter),并配置Fragment和tab标题内容;
    3. java代码中给ViewPager绑定Adapter;
  1. 布局

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    <?xml version="1.0" encoding="utf-8"?>
    <merge xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <View
    android:layout_width="match_parent"
    android:layout_height="0.1dp"
    android:background="@color/tab_sep"/>

    <android.support.design.widget.TabLayout
    android:id="@+id/sliding_tabs"
    style="@style/MyCustomTabLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:tabMode="fixed"/>

    <View
    android:layout_width="match_parent"
    android:layout_height="0.1dp"
    android:background="@color/tab_sep"/>

    <android.support.v4.view.ViewPager
    android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="0px"
    android:layout_weight="1"/>
    </merge>
  2. 自定义Adapter

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29

    public class ModeListVpAdapter extends FragmentPagerAdapter {
    private final String mTabTitles[];
    private final Mode.Position[] mPosition = Mode.Position.values();
    private final int PAGE_COUNT = mPosition.length;
    private Context mContext;

    public ModeListVpAdapter(FragmentManager fm, Context context) {
    super(fm);
    mContext = context;
    mTabTitles = context.getResources().getStringArray(R.array.main_tabs);
    }

    @Override
    public int getCount() {
    return PAGE_COUNT;
    }

    @Override
    public Fragment getItem(int position) {
    return ModeListFragment.newInstance(position); // 根据position返回对应的fragment
    }

    @Override
    public CharSequence getPageTitle(int position) {
    return mTabTitles[position]; // 根据position返回对应的tab标题
    }

    }
  3. 绑定

    1
    2
    3
    4
    5
    6
    ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
    viewPager.setAdapter(new ModeListVpAdapter(getSupportFragmentManager(), mContext));

    TabLayout tabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
    tabLayout.setupWithViewPager(viewPager);
    viewPager.setCurrentItem(2); // 默认选中第二个tab

DrawerLayout & NavigationView

  • NavigationView隐藏menu:不使用app:menu属性即可;
  • 给NavigationView头部布局组件设置点击事件:可以通过mNavView.getHeaderView(0)获取根布局的view引用;
  • 禁用滑动
    1
    2
    3
    4
    // lock
    mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
    // unlock
    mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);

外部链接

ToolBar

  • 切换fragment时对应显示不同的菜单:
    通过控制自定义的标志,然后调用invalidateOptionsMenu();刷新菜单即可;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Override
    protected boolean onPrepareOptionsPanel(View view, Menu menu) {
    if (mMode == DEVICE_FRAGMENT) {
    menu.findItem(R.id.action_add).setVisible(true);
    menu.findItem(R.id.action_ok).setVisible(false);
    } else if (mMode == SETTING_TIME_FRAGMENT) {
    menu.findItem(R.id.action_add).setVisible(false);
    menu.findItem(R.id.action_ok).setVisible(true);
    }
    return super.onPrepareOptionsPanel(view, menu);
    }
  • 在Fragment中获取ToolBar对象,并监听点击事件;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.toolbar);
    TextView tvTitle = (TextView) toolbar.findViewById(R.id.tv_nav_title);
    tvTitle.setText("标题1");

    // 处理toolbar上的菜单点击事件;
    toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
    @Override
    public boolean onMenuItemClick(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.action_ok:
    Usp.init(mContext).putInt(CKeys.KEY_TS, indexInTIMES(mRgSettingTime.getCheckedRadioButtonId()));
    Utoast.toastOnMain(mContext, mContext.getString(R.string.time_setting_setted));
    break;
    }
    return false;
    }
    });

适配

Toolbar 里面有两个属性很关键:
android:minHeight=”?attr/actionBarSize”,这个表示引用系统 ActionBar 的高度.
android:paddingTop=”@dimen/tool_bar_top_padding”这个是来引用资源文件里面的tool_bar_top_padding的高度,这个高度主要是为了对5.0做适配,在5.0 上为24dp,其他版本为0dp

外部链接

外部链接

在正式环境中关闭日志

1
2
3
4
5
6
7
8
# insert below code to proguard-rules.pro

# 移除日志
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** i(...);
public static *** w(...);
}
1
2
3
4
5
6
7
8
9
# insert below code to build.gradle

release {
signingConfig signingConfigs.renrenDebug // 密钥配置
shrinkResources true // 删除不必要的源文件
zipAlignEnabled true // 压缩对齐
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}

ButterKnife注解

网址https://github.com/JakeWharton/butterknife

注意:如果想要在lib/app中使用Butterknife库,则需要在当前module的build.gradle中添加compile信息;
如果你在lib库的build.gradle中引用了Butterknife的compile信息,
然后想要在app中直接使用Butterknife,这样的结果是注解失败;就会出现NullpointException;
https://www.google.com/search?q=NullPointerException+butterknife

AS插件:Android Butterknife Zelezny

  • 在使用的时候,注意,把光标放置在R.layout.layout_other上面,点击Alt+Insert,选择Generate ButterKnife Injections
  • 自定义live template模块:ButterKnife.findById –> fbi。(即按一下fbi,就显示出来ButterKnife.findById(, R.id.)

使用 ButterKnife 可能会让你的IDE编译速度变慢。

In the initial configuration incremental compilation takes 45s out of 1m 10s, but if Butterknife is removed then project is compiled in 15s only! Three times faster! Whole incremental build without Butterknife is 40s.
First and most important, the hypothesis was correct, modularizing project can significantly speed up build process, but not for all configurations.

Volley

步骤

  • 依据application上下文,初始化volley组件;
  • 配置参数和请求数据;
  • 添加到请求队列;
  • 结果处理;

注意

一般情况下,用get和post两种请求方式;
post请求使用:StringRequest对象;
get请求使用:JsonObjectRequest对象;

外部链接

Stetho - A debug bridge for Android applications

Stetho is a debug bridge for Android applications from Facebook that integrates with the Chrome desktop browser’s Developer Tools. With Stetho you can easily inspect your application, most notably the network traffic. It also allows you to easily inspect and edit SQLite databases and the shared preferences in your app. You should, however, make sure that Stetho is only enabled in the debug build and not in the release build variant.
https://github.com/futurice/android-best-practices#use-stetho

AndroidUtilCode

Android developers should collect the following utils

BaseMoudle

BaseMoudle是一个支持rxjava+retrofit2+mvp 同时支持mvc开发的一款框架

UltimateAndroidReference

Ultimate Android Reference - Your Road to Become a Better Android Developer (学习什么?这里清除了)

MultiType

Effective-MultiType

现在好了,我们有了 MultiType,简单来说,MultiType 就是一个多类型列表视图的中间分发框架,它能帮助你快速并且清晰地开发一些复杂的列表页面。 它本是为聊天页面开发的,聊天页面的消息类型也是有大量不同种类,且新增频繁,而 MultiType 能够轻松胜任。

注意

引入开源库的时候,注意要及时引入 proguard (以免忘记)

alias

1
2
3
4
5
6
7
8
9
10
11
alias cdt='cd ~/t'
alias cdw='cd ~/w'
alias e.='caja .'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias gl='git lg'
alias grep='grep --color=auto'
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -alF'
alias ls='ls --color=auto'

java

1
sudo apt-get install openjdk-8-jdk
1
2
3
4
5
6
#set oracle jdk environment
export JAVA_HOME=/usr/lib/jvm/jdk1.8.0_121 ## 这里要注意目录要换成自己解
压的jdk 目录
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export ${JAVA_HOME}/bin:$PATH

go

1
2
3
4
export GOROOT=$HOME/c/go
export PATH=$PATH:$GOROOT/bin
export GOPATH=$HOME/w/go
export PATH=${GOPATH}/bin:$PATH

git

to set

1
2
3
4
5
6
git config --global user.name lilou
git config --global user.email lilou@lyloou.com
git config --global core.autocrlf false
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
git config --global http.proxy 'socks5://127.0.0.1:1080'
git config --global https.proxy 'socks5://127.0.0.1:1080'

result

1
2
3
4
5
6
7
[user]
email = lilou@lyloou.com
name = lilou
[alias]
lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
[core]
autocrlf = false

UnsupportedOperationException at java.util.AbstractList.remove(AbstractList.java:638)

【问题场景】

  • 在给RecyclerView.Adapter传递数据源的时候,
    我传递进去了Arrays.asList构成的列表,在调用lists.remove()方法删除某个元素的时候,出现了这个异常;

【解答】

  • 我使用了Arrays.asList()方法,通过查看源码知道,这个方法调用了Arras.ArrayList(E[])来构建列表,
    而这个列表是final的,不可modify的,所以会出现UnsupportedOperationException异常;
  • 解决办法1:使用new ArrayList<>();的方式来新建列表,而不是Arrays.asList或数组的方式;
  • 解决方法2:new ArrayList<>(Arrays.asList(“1”,”2”)); // 即封装下就可;

【外部链接】

App响应外部链接(类似:http, https, tel, mailto)

主要步骤是,配置、使用、获取数据;

配置

1
2
3
4
5
6
7
8
9
10
在自定义的 webview中点击<a href="lyloou://...">链接,可以跳转到app。
在系统浏览器中(魅族)打开一个页面,页面中包含<a href="lyloou://...">链接,可以跳转
在chrome浏览器中打开一个页面,页面中包含<a href="lyloou://...">链接,可以跳转
在qq浏览器中打开一个页面,页面中包含<a href="lyloou://...">链接,可以跳转

直接通过浏览器的地址栏输入,不可以跳转到app。
微信对话中点击,不可以跳转app。
qq对话中点击,不可以跳转app。

app没有安装的时候,点击链接都没有任何反应。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>

<!-- 必要的 -->
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:host="lou.app"
android:pathPrefix="/openwith"
android:scheme="lyloou"/>
</intent-filter>
</activity>

在html中使用

1
2
3
4
5
<!-- 
如果把html代码放在了 WebView中,如果设置了setWebViewClient(),
其中重写的方法不要拦截,否则app无法响应; (即,重写shouldOverrideUrlLoading方法时需要小心,不设置webviewClient为妙)
-->
<a href="lyloou://lou.app/openwith?name=zhangsan&age=26">启动应用程序</a>

获取数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void getData() {
Intent i_getvalue = getIntent();
String action = i_getvalue.getAction();

if (Intent.ACTION_VIEW.equals(action)) {
Uri uri = i_getvalue.getData();
if (uri != null) {
String name = uri.getQueryParameter("name");
String age = uri.getQueryParameter("age");
Log.i(TAG, "getData: name=" + name);
Log.i(TAG, "getData: age=" + age);
}
}
}

参考资料:

assets文件夹和raw文件夹的区别

【解答】

  • 相同点:以原有形式保存到apk中,均不会被编译成二进制文件;
  • raw里的文件会被映射到R.id中,assets不会;
  • assets文件夹里面可以包含目录结构,raw不可;
  • 引用方式不同:参考下面的外部链接;

【外部链接】

invalidate和postInvalidate的区别

【解答】

  • invalidate必须在主线程中调用,变量发生改变时用来刷新界面;
  • postInvalidate可以在非主线程中调,用来刷新界面;
  • 通过查看源码发现:postInvalidate是通过Handler间接调用了invalidate;

【外部链接】

java.lang.RuntimeException: Performing stop of activity that is not resumed

以GitBlit来讲解

  1. 安装Java;
  2. 配置Java的环境变量;
  3. 下载并安装GitBlit
  4. 配置GitBlit(以1.8.0为例):
  • 打开配置文件:C:\Git\gitblit-1.8.0\data\defaults.properties
  • 修改资料库路径(也可以使用默认的):git.repositoriesFolder = C:\\Git\\GitRepository
  • 修改http协议端口:server.httpPort = 10108
  • 设定服务器http地址:server.httpBindInterface = 192.168.0.30
  • 设定服务器https地址:server.httpsBindInterface = localhost
  • 保存并关闭文件;
  • 运行服务器,双击打开:gitblit.bat
  1. 浏览器中打开GitBlit:http://192.168.0.30:10108
  2. 作为服务自动运行在后台:
  • 打开installService.bat文件;
  • 根据系统环境配置ARCH:SET ARCH=amd64
  • 设置程序目录:C:\\Git\\gitblit-1.8.0
  • 设置启动参数:--StartParams=""
  • 关闭bat文件,并以管理员身份运行;
  • 查看服务是否安装成功:Win+R,输入services.msc,找得到gitbit服务;
  • 启动gitbit服务;
  1. 再次在浏览器中验证是否安装成功;
  2. 登陆:账号密码默认均为admin

其它 git 服务


外部链接

摘要:

主要内容:
本文介绍了封装后的SharedPreference,以便快速开发;
只保留必要的定制,重复的代码封装到一个通用类中;

说明

  • 具体用法参照UspDemo.java文件;
  • 通用源文件为Usp.java

代码

0%