糖葫芦


  • Startseite

  • Tags

  • Archiv

  • Suche

获取手机屏幕的密度

Veröffentlicht am 2018-04-24 |

目前有两种方式,一种是根据手机的分辨率计算,另外一种是通过代码获取。

第一种:根据手机分辨率进行计算(计算得出实际的dpi)

比如我的手机魅族分辨率是:1920*1080,屏幕尺寸大小是:5.5寸的,那么计算:
(宽的平方+高的平方之后开根号,最后除以屏幕的尺寸)
dpi = (√1920^2+1080^2 ) / 5.5 ≈ 401

参照下图:

ldpi(低240*320)~120dpi density=0.75
mdpi(中320*480)~160dpi density=1
hdpi(高480*800)~240dpi density=1.5
xhdpi(超高720*1080)~320dpi density=2
xxhdpi(超超高1080*1920)~480dpi density=3
xxxhdpi(超超超高)~640dpi density=4

对应图片的目录应该是:xxhdpi

第二种:通过代码方式(系统定义的dpi)

1
2
float xdpi = getResources().getDisplayMetrics().xdpi;
float ydpi = getResources().getDisplayMetrics().ydpi;

不同手机获取的xdpi ydpi 值有的一模一样,有的有些差异,但是相差不会太大,两者获取的值近乎一样。

两者计算出的结果并不完全相同,因为你们想,实际计算得出的dpi 很容易根据屏幕尺寸的不同,得出不同的dpi ,这样的话得到的值很多,无法适配。我查阅网上相关介绍,就是每个手机初始有一个固定的dpi ,分别是上述的:120,160,240,320,480,640,安卓实际进行缩放的时候按照的是系统定义的这些,而不是实际计算得出的dpi,这一点需要注意。

像素和dp之间的转化

1
2
3
4
5
px = dp * desity
// 这里的dpi就是上述第一种的计算方法
//dpi = (√1920^2+1080^2 ) / 5.5(屏幕尺寸) ≈ 401
desity = dpi / 160
所以:px = dp * (dpi/160)

DisplayMetrics.java

1
2
3
DisplayMetrics#density //就是我们熟知的desity
DisplayMetrics#densityDpi //dpi
DisplayMetrics#scaleDensity //字体缩放因子,正常情况下和density相同,但是我手动调整字体大小后会改变这个值

关于手机的 density 可以在 /system/build.prop 文件中查看的定义值:

1
ro.sf.lcd_density=480 // 这个字段

这个定义的数值,可能会跟计算得到的density 不相同。

今日头条适配核心代码

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
float sNoncompatScaledDensity;
float sNoncompatDensity;
public void setCustomerDensity(Activity activity, final Application application){

DisplayMetrics displayMetrics = application.getResources().getDisplayMetrics();
Log.e("xx","density::"+displayMetrics.density);
float targetDensity = displayMetrics.widthPixels / 360f;
final int targetDensityDpi = (int) (targetDensity * 160);

if(sNoncompatDensity == 0){
sNoncompatDensity = displayMetrics.density;
sNoncompatScaledDensity = displayMetrics.scaledDensity;

application.registerComponentCallbacks(new ComponentCallbacks() {
@Override
public void onConfigurationChanged(Configuration newConfig) {
if(newConfig != null && newConfig.fontScale > 0){

sNoncompatScaledDensity = application.getResources().getDisplayMetrics().scaledDensity;
}
}
@Override
public void onLowMemory() {
}
});
}

final float targetScaleDensity = targetDensity * (sNoncompatScaledDensity / sNoncompatDensity);

displayMetrics.density = targetDensity;
displayMetrics.scaledDensity = targetScaleDensity;
displayMetrics.densityDpi = targetDensityDpi;

DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
activityDisplayMetrics.density = targetDensity;
activityDisplayMetrics.scaledDensity = targetScaleDensity;
activityDisplayMetrics.densityDpi = targetDensityDpi;

Log.e("xx","修改后的density::"+displayMetrics.density);
btn.postDelayed(new Runnable() {
@Override
public void run() {
Log.e("xx","width::"+btn.getWidth());
}
},1000);
}

EventBus 为什么订阅的方法必须是public?

Veröffentlicht am 2018-04-08 |

在看了源码之后发现是这样的:

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
31
32
33
34
35
36
37
38
39
40
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
//获取所有声明的方法
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
for (Method method : methods) {
//获取方法的标识符
int modifiers = method.getModifiers();
//方法的标识符必须是public
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException("@Subscribe method " + methodName +
"must have exactly 1 parameter but has " + parameterTypes.length);
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
//否则抛出异常 ,说这个方法必须加上@Subscribe ,并且是public 的,不能是静态的,抽象的
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}

然后就没有然后了,之前怀疑private 修饰的方法,反射后不能被其他类调用,后来查了相关资料,发现可以,后来去网上寻找无果,后来在我微信关注的公众号里,群主伯特说:虽然可以反射调用private 的方法,但是必须通过setAccess来修改访问权限。说是修改,实则破坏了java中的作用域,迫不得已不推荐这么做。EventBus 作为三方库,显然不会在你设置为private 时,好心办坏事,强制访问。

仅此而已,仅此而已。分享给还不知道的童鞋。

Activity状态保存与恢复

Veröffentlicht am 2018-03-23 |

四大组件是什么与它们的生命周期(及Fragment)

Veröffentlicht am 2018-03-22 |

首先当我们一开始学习安卓的时候想必就是四大组件了以及它们的生命周期,现在就来复习回想下。

四大组件有:Activity, ContentProvider, BroadcastReceiver, Service

Activity

提供与用户交互的界面或者可以说是一个窗口

下面我是从官方文档中关于Activity生命周期 的一张图

lifetcycle.jpg

正常启动时:onCreate() -> onStart() -> onResume()

  • 而后我们看到当 Another activity comes into the foreground 执行 onPause() 方法
    当按 home 键的时候: 当前Activity 已经不可见了,所以执行:onPause() -> onStop()

  • 当重新回到app时,分为两种情况就是:①是app还在后台,执行:onRestart() -> onStart() -> onResume(); ②是app被系统杀死了,则执行:onCreate() -> onStart() > onResume()

  • 当在app 里 从 A -> B 此时A隐藏,B显示,当重新返回A 时,执行:onPause() -> onResume(),这种应用场景一般是比如需要返回做刷新操作的,可以将刷新方法写在onResume() 方法中执行。

  • 最后当退出应用程序的时候执行 onDestroy()

Service

服务,有前台服务和后台服务,一般提供需在后台长期运行的服务,例如:音乐播放器等

它的生命周期如下图:

lifetcycle.jpg

因为启动服务的方法有两个:startService() 和 bindService() 两者的生命周期略有不同。

  • 首先来看:startService() 方式
    启动:onCreate() -> onStartCommand() 调用stopServcie() 停止服务,随后执行 onDestroy()

  • 其次是:bindService() 方式
    启动:onCreate() -> onBind() 服务启动起来了,调用unbindService() 停止服务,随后执行 onUnbind() -> onDestroy()

Broadcastreceiver

广播,可以接受来自应用内或者应用外的广播,分为两个角色:广播发送者,广播接收者

  • 广播的注册方式有两种:一种是代码注册,一种是清单文件注册,代码注册的优先级要比清单文件注册的优先级要高;
  • 广播的发送可以是有序广播也可以是无序广播,有序广播接收到广播的顺序按照优先级的顺序;
  • 注意广播接收器onReceive() 方法运行在 UI 线程中,不可以做耗时操作,否则会导致ANR异常;

ContentProvider

内容提供者,应用内数据共享

Fragment

一般和 viewpager 配合使用,不能单独使用,要配合Activity使用,但是有自己的生命周期

fragment

一般在onAttach()中获取参数值一些,onCreateView()中创建布局,布局加载完成后在onActivityCreated()中执行一些初始化操作,随后onStart(),onResume().onPause(),onStop(), fragment 销毁,onDestroyView() -> onDestroy() ->onDetach()

Android知识点总结

Veröffentlicht am 2018-03-22 |

网上别人列出一些来,我把它拿过来了,需要自己一项一项复习查阅,以后有会继续添加新的,特此总结。

  • 四大组件是什么与它们的生命周期(及Fragment);

  • Acitivty的四种启动模式与特点。

  • 获取手机屏幕的密度

  • Activity状态保存与恢复。

  • Service的生命周期,启动方法,有什么区别。

  • service和activity怎么进行数据交互。

  • 怎么保证service不被杀死。

  • 广播使用的方式和场景以及广播的几种分类。

  • Intent的使用方法,可以传递哪些数据类型。

  • ContentProvider使用方法。

  • ContentProvider、ContentResolver、ContentObserver 之间的关系。

  • Thread、AsycTask、IntentService的使用场景与特点。

  • FrameLayout 、 LinearLayout 、 RelativeLayout 各自特点及绘制效率对比。

  • Android的数据存储形式。

  • Android两种序列化的区别和作用。

  • Sqlite的基本操作。

  • Android中的MVC、MVP模式。

  • Merge、ViewStub的作用。

  • 动画有哪几类,各有什么特点?

  • Handler、Loop消息队列模型,各部分的作用。

  • Android的消息机制,子线程更新UI的方法和原理。

  • Android怎么加速启动Activity。

  • App的启动过程。

  • Android优化方法。

  • 如何防止内存泄漏?

  • Android中弱引用与软引用的应用场景。

  • Bitmap的四种属性,如何加载大图(inJustDecodeBounds)。

  • View与View Group分类。自定义View过程:onMeasure()、onLayout()、onDraw()。

  • View刷新机制和绘制流程。

  • Activity、Window、View的联系和理解。

  • invalidate和requestLayout的区别及使用。

  • Touch事件分发机制和冲突处理。

  • Android IPC:Binder原理。

  • Android5.0(UI库)、6.0(权限)、7.0特性、8.0特性。

Kotlin 传递数据

Veröffentlicht am 2018-03-14 |

今天在掘金看到使用 Kotlin 高阶函数传递Intent 数据很简洁,觉着可以试试,并应用到项目中去,自己再加以理解,记录笔记,方便查阅。掘金原文章地址:https://mp.weixin.qq.com/s/0TuDlsfBtO7wP9TwI8CeJw

传统的Intent 数据传递我就不介绍了,只介绍Kotlin实现方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//目标 假设叫`KTestActivity4`  定义   
object IntentOptions{
private const val MSG_KEY = "key for message"

var Intent.message: String?
get() = getStringExtra(MSG_KEY)
set(message) {
putExtra(MSG_KEY,message)
}
}
//跳转时
with(KTestActivity4.IntentOptions){
intent = Intent(this@KTestActivity5,KTestActivity4::class.java)
intent.message = "I am KTestActivity5"
startActivity(intent)
}
//使用
with(IntentOptions){
var message= intent.message
Toast.makeText(this@KTestActivity4,"显示信息:"+message,Toast.LENGTH_SHORT).show()
}

假设有多个数据传递:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
object IntentOptions{
private const val MSG_KEY = "key for message"
private const val MSG_ID = "ID for message"

var Intent.message: String?
get() = getStringExtra(MSG_KEY)
set(message) {
putExtra(MSG_KEY,message)
}
// 再多增加一条即可
var Intent.id: String?
get() = getStringExtra(MSG_ID)
set(id) {
putExtra(MSG_ID,id)
}
}
// 传递时
with(KTestActivity4.IntentOptions){
intent = Intent(this@KTestActivity5,KTestActivity4::class.java)
intent.message = "I am KTestActivity5"
intent.id = "I am id"
startActivity(intent)
}

还有另外一种传递方式:委托机制,不是特别明白。国外大神封装的github地址:https://github.com/Takhion/android-extras-delegates

阿里巴巴Android开发手册

Veröffentlicht am 2018-03-13 |

摘自阿里巴巴Android开发手册

强制要求的

  • 1. Activity 间的数据通信,对于数据量比较大的,避免使用 intent + Parcelable 的方式,可以考虑 EventBus等替代方案,以免造成 TransationTooLargeException
  • 2. Activity 间通过隐士 Intent的跳转,在发出 Intent 之前必须通过 resolveActivity 检查,避免找不到合适的调用组件,造成 ActivityNotFoundException 的异常。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
      public void viewUrl(String url, String mimeType) {
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(Uri.parse(url), mimeType);
    if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_
    ONLY) != null) {
    startActivity(intent);
    }else {
    // 找不到指定的 Activity
    }
    }

而不应该:

1
2
3
4
5
6
7
Intent intent = new Intent();
intent.setAction("com.example.DemoIntent ");
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
}

  • 3. 避免在Service#onStartCommand/onBind()方法中执行耗时操作,如果确实有需求,应采用IntentService 或采用其他异步机制完成。
    正例:

    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
    public class MainActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    }
    public void startIntentService(View source) {
    Intent intent = new Intent(this, MyIntentService.class);
    startService(intent);
    }
    }
    public class MyIntentService extends IntentService {
    public MyIntentService() {
    super("MyIntentService");
    }
    @Override
    protected void onHandleIntent(Intent intent) {
    synchronized (this) {
    try {
    ......
    } catch (Exception e) {
    }
    }
    }
    }
  • 4. 避免在 BroadcastReceive#onReceive()中执行耗时操作,如果有耗时工作,应该创建 IntentService完成,而不应该在BroadcastReceiver 内创建子线程去做。

说明:
由于该方法是在主线程执行,如果执行耗时操作会导致 UI 不流畅,可以使用 IntentService,创建 HanlderThread 或者调用 Context#registerReceiver(BroadcastReceiver,IntentFitter,String,Handler) 方法等方式,在其他 Worker 线程执行 onReceive.BroadcastReceiver#onReceive() 方法耗时超过10秒钟,可能会被系统杀死。
正例:

1
2
3
4
5
6
7
8
9
10
11
IntentFilter filter = new IntentFilter();
filter.addAction(LOGIN_SUCCESS);
this.registerReceiver(mBroadcastReceiver, filter);
mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Intent userHomeIntent = new Intent();
userHomeIntent.setClass(this, UserHomeService.class);
this.startService(userHomeIntent);
}
};

反例:

1
2
3
4
5
6
7
8
9
mBroadcastReceiver = new BroadcastReceiver() {

@Override
public void onReceive(Context context, Intent intent) {
MyDatabaseHelper myDB = new MyDatabaseHelper(context);
myDB.initData();
// have more database operation here
}
};

  • 5. 避免使用隐士 Intent 广播敏感信息,信息可能被其他注册了对应 BroadcastReceiver 的App接收。

说明:
通过Context#sendBroadcast()发送的隐士广播会被感兴趣的 receiver 接收,恶意应用注册监听该广播的 receiver可能会获取到 Intent 中传递的敏感信息,并进行其他危险操作。如果发送的广播为使用 Context#sendOrderedBroadcast()方法发送的有序广播,优先级较高的恶意 receiver可能直接丢弃该广播,造成服务不可用,或者向广播结果塞入恶意数据。

如果广播仅限于应用内,则可以是iyongLocalBroadcastManager#sendBroadcast()实现,避免敏感信息外泄和intent拦截的风险。

正例:

1
2
3
Intent intent = new Intent("my-sensitive-event");
intent.putExtra("event", "this is a test event");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

反例:

1
2
3
4
5
6
7
8
9
10
11
Intent intent = new Intent();
v1.setAction("com.sample.action.server_running");
v1.putExtra("local_ip", v0.h);
v1.putExtra("port", v0.i);
v1.putExtra("code", v0.g);
v1.putExtra("connected", v0.s);
v1.putExtra("pwd_predefined", v0.r);
if (!TextUtils.isEmpty(v0.t)) {
v1.putExtra("connected_usr", v0.t);
}
context.sendBroadcast(v1);

以上广播可能被其他应用的如下 receiver 接收导致敏感信息泄露:

1
2
3
4
5
6
7
8
9
10
11
12
13
final class MyReceiver extends BroadcastReceiver {
public final void onReceive(Context context, Intent intent) {
if (intent != null && intent.getAction() != null) {
String s = intent.getAction();
if (s.equals("com.sample.action.server_running") {
String ip = intent.getStringExtra("local_ip");
String pwd = intent.getStringExtra("code");
String port = intent.getIntExtra("port", 8888);
boolean status = intent.getBooleanExtra("connected", false);
}
}
}
}

监听键盘显示与隐藏

Veröffentlicht am 2018-03-08 |

项目中有时候需要监听keyboard的显示与隐藏,特此备注,方便使用。

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
public class KeyboardWatcher {
private ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener;
private View rootView;
private int viewSize = -1;
private boolean isShowing = false;
private OnKeyboardListener onKeyboardListener;
public KeyboardWatcher(Activity activity){
rootView = activity.getWindow().getDecorView().getRootView();
}

public KeyboardWatcher register(OnKeyboardListener listener){
onKeyboardListener = listener;
if(onGlobalLayoutListener == null) {
onGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
rootView.getWindowVisibleDisplayFrame(r);
int viewHeight = r.bottom - r.top;
if(viewSize < 0){
viewSize = viewHeight;
return;
}
if(viewHeight != viewSize){
// 大于100dp才算变化
if(Math.abs(viewHeight - viewSize) > dpToPx(rootView.getContext(),100)) {
if (viewHeight < viewSize && !isShowing) {
onKeyboardListener.onShow(viewHeight);
isShowing = true;
} else if(isShowing){
onKeyboardListener.onHide();
isShowing = false;
}
}
viewSize = viewHeight;
}
}
};
}

rootView.post(new Runnable() {
@Override
public void run() {
viewSize = rootView.getHeight();
rootView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);
}
});

return this;
}

public void unRegister(){
rootView.getViewTreeObserver().removeGlobalOnLayoutListener(onGlobalLayoutListener);
rootView = null;
}

public interface OnKeyboardListener{

void onShow(int viewSize);

void onHide();

}

private int dpToPx(Context context,int dp) {
return (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics()
);
}
}

使用方法

1
2
3
4
KeyBoardWatcher keyboardWatcher = new  KeyboardWatcher()
keyboardWatcher.register(this)//实现KeyboardWatcher.OnKeyboardListener接口

//实现方法onShow() , onHide(),对应键盘的显示与隐藏

Fragment 懒加载

Veröffentlicht am 2018-02-28 |

因为项目中经常用到tabLayout + viewpager 结合使用,页面切换时要用到延迟加载的情况,所以单独写出一个demo,方便查看和便于使用

1.首先新建一个BaseLazyFragment

/**
 * Created by xuqianqian on 2018/2/28.
 */
public  abstract class BaseLazyFragment extends Fragment {

    protected View mRootView;
    public Context mContext;
    protected boolean isVisible;
    private boolean isPrepared;
    private boolean isLoad = false;

    //最先执行
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (getUserVisibleHint()) {//当前显示
            isVisible = true;
            if(!isLoad){
                lazyLoad();
            }
        } else {
            isVisible = false;
            //onInvisible();
        }
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = getActivity();
        setHasOptionsMenu(true);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        if (mRootView == null) {
            mRootView = getLayout();
        }
        return mRootView;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        isPrepared = true;
        //如果已经加载过了,就无需再重新加载
        if(!isLoad){
            lazyLoad();
        }
    }

    /**
     * 懒加载
     */
    protected void lazyLoad() {
        if (!isPrepared || !isVisible) {
            return;
        }
        isLoad = true;
        initData();
    }

//    protected void onInvisible() {
//
//    }
    //初始化布局View
    public abstract View getLayout();

    public abstract void initData();
}

2.让你的fragment extend BaseLazyFragment

public class GankFragment extends BaseLazyFragment {

String type;
public static GankFragment newInstance(String type) {
    GankFragment gankFragment = new GankFragment();
    Bundle bundle = new Bundle();
    bundle.putString("type", type);
    gankFragment.setArguments(bundle);
    return gankFragment;
}
//加载布局
@Override
public View getLayout() {

    type = getArguments().getString("type");
    TextView tv = new TextView(getActivity());
    tv.setText(type);
    tv.setGravity(Gravity.CENTER);
    return tv;
}

@Override
public void initData() {

    //初始化一些控件,加载网络数据
}

}

3.剩下的就是FragmentPagerAdapter了

public class TitleAdapter extends FragmentPagerAdapter {

private List<Fragment> fragments;

private List<String> types;

public TitleAdapter(FragmentManager fm, List<Fragment> fragments, List<String> types) {
    super(fm);
    this.fragments = fragments;
    this.types = types;
}

@Override
public Fragment getItem(int position) {
    return fragments.get(position);
}

@Override
public int getCount() {
    return fragments.size();
}

@Override
public CharSequence getPageTitle(int position) {
    return types.get(position);
}
}

MainActivity.java

private List<String> titles = new ArrayList<>();

private List<Fragment> fragments = new ArrayList<>();
TitleAdapter titleAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    TabLayout tablayout = findViewById(R.id.tablayout);
    ViewPager viewpager = findViewById(R.id.viewpager);

    titles.add("android");
    titles.add("ios");
    titles.add("web");
    titles.add("java");

    fragments.add(GankFragment.newInstance("android"));
    fragments.add(GankFragment.newInstance("ios"));
    fragments.add(GankFragment.newInstance("web"));
    fragments.add(GankFragment.newInstance("java"));

    titleAdapter = new TitleAdapter(getSupportFragmentManager(), fragments, titles);
    viewpager.setAdapter(titleAdapter);
    tablayout.setTabMode(TabLayout.MODE_FIXED);
    tablayout.setupWithViewPager(viewpager);
}

https://github.com/QQabby/LazyFragmentApplication

Dialog

Veröffentlicht am 2018-02-28 |

快速初始化materialDialog

new MaterialDialog.Builder(mContext)
                    .title("title")
                    .content("I'm a content")
                    .negativeText("cancel")
                    .negativeColorRes(R.color.colorNegative)
                    .positiveText("ok")
                    .positiveColorRes(R.color.colorPositive)
                    .onPositive(new     MaterialDialog.SingleButtonCallback() {
                            @Override
                            public void onClick(@NonNull MaterialDialog     dialog, @NonNull DialogAction which) {
                            showMsg("click dialog ok");
                            ...
                    }
                })
                .show();
1…678

QQabby

79 Artikel
63 Tags
© 2020 QQabby
Erstellt mit Hexo
|
Theme — NexT.Pisces v5.1.3