最后说一下我的学习路线
其实很简单就下面这张图,含概了Android所有需要学的知识点,一共8大板块:
- 架构师筑基必备技能
- Android框架体系架构(高级UI+FrameWork源码)
- 360°Androidapp全方位性能调优
- 设计思想解读开源框架
- NDK模块开发
- 移动架构师专题项目实战环节
- 移动架构师不可不学习微信小程序
- 混合开发的flutter
Android学习的资料
我呢,把上面八大板块的分支都系统的做了一份学习系统的资料和视频,大概就下面这些,我就不全部写出来了,不然太长了影响大家的阅读。
330页PDF Android学习核心笔记(内含上面8大板块)
Android学习的系统对应视频
总结
我希望通过我自己的学习方法来帮助大家去提升技术:
-
1、多看书、看源码和做项目,平时多种总结
-
2、不能停留在一些基本api的使用上,应该往更深层次的方向去研究,比如activity、view的内部运行机制,比如Android内存优化,比如aidl,比如JNI等,并不仅仅停留在会用,而要通过阅读源码,理解其实现原理
-
3、同时对架构是有一定要求的,架构是抽象的,但是设计模式是具体的,所以一定要加强下设计模式的学习
-
4、android的方向也很多,高级UI,移动架构师,数据结构与算法和音视频FFMpeg解码,如果你对其中一项比较感兴趣,就大胆的进阶吧!
希望大家多多点赞,转发,评论加关注,你们的支持就是我继续下去的动力!加油!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
-
public static void e(String tag, String msg)
-
{
-
if (isDebug)
-
Log.i(tag, msg);
-
}
-
public static void v(String tag, String msg)
-
{
-
if (isDebug)
-
Log.i(tag, msg);
-
}
-
}
网上看到的类,注释上应该原创作者的名字,很简单的一个类;网上也有很多提供把日志记录到SDCard上的,不过我是从来没记录过,所以引入个最简单的,大家可以进行评价是否需要扩充~~
===========================================================================
[java] view plain copy
-
package com.zhy.utils;
-
import android.content.Context;
-
import android.widget.Toast;
-
/**
-
* Toast统一管理类
-
*
-
*/
-
public class T
-
{
-
private T()
-
{
-
/* cannot be instantiated */
-
throw new UnsupportedOperationException(“cannot be instantiated”);
-
}
-
public static boolean isShow = true;
-
/**
-
* 短时间显示Toast
-
*
-
* @param context
-
* @param message
-
*/
-
public static void showShort(Context context, CharSequence message)
-
{
-
if (isShow)
-
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
-
}
-
/**
-
* 短时间显示Toast
-
*
-
* @param context
-
* @param message
-
*/
-
public static void showShort(Context context, int message)
-
{
-
if (isShow)
-
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
-
}
-
/**
-
* 长时间显示Toast
-
*
-
* @param context
-
* @param message
-
*/
-
public static void showLong(Context context, CharSequence message)
-
{
-
if (isShow)
-
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
-
}
-
/**
-
* 长时间显示Toast
-
*
-
* @param context
-
* @param message
-
*/
-
public static void showLong(Context context, int message)
-
{
-
if (isShow)
-
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
-
}
-
/**
-
* 自定义显示Toast时间
-
*
-
* @param context
-
* @param message
-
* @param duration
-
*/
-
public static void show(Context context, CharSequence message, int duration)
-
{
-
if (isShow)
-
Toast.makeText(context, message, duration).show();
-
}
-
/**
-
* 自定义显示Toast时间
-
*
-
* @param context
-
* @param message
-
* @param duration
-
*/
-
public static void show(Context context, int message, int duration)
-
{
-
if (isShow)
-
Toast.makeText(context, message, duration).show();
-
}
-
}
也是非常简单的一个封装,能省则省了~~
===========================================================================================
[java] view plain copy
-
package com.zhy.utils;
-
import java.lang.reflect.InvocationTargetException;
-
import java.lang.reflect.Method;
-
import java.util.Map;
-
import android.content.Context;
-
import android.content.SharedPreferences;
-
public class SPUtils
-
{
-
/**
-
* 保存在手机里面的文件名
-
*/
-
public static final String FILE_NAME = “share_data”;
-
/**
-
* 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法
-
*
-
* @param context
-
* @param key
-
* @param object
-
*/
-
public static void put(Context context, String key, Object object)
-
{
-
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
-
Context.MODE_PRIVATE);
-
SharedPreferences.Editor editor = sp.edit();
-
if (object instanceof String)
-
{
-
editor.putString(key, (String) object);
-
} else if (object instanceof Integer)
-
{
-
editor.putInt(key, (Integer) object);
-
} else if (object instanceof Boolean)
-
{
-
editor.putBoolean(key, (Boolean) object);
-
} else if (object instanceof Float)
-
{
-
editor.putFloat(key, (Float) object);
-
} else if (object instanceof Long)
-
{
-
editor.putLong(key, (Long) object);
-
} else
-
{
-
editor.putString(key, object.toString());
-
}
-
SharedPreferencesCompat.apply(editor);
-
}
-
/**
-
* 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值
-
*
-
* @param context
-
* @param key
-
* @param defaultObject
-
* @return
-
*/
-
public static Object get(Context context, String key, Object defaultObject)
-
{
-
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
-
Context.MODE_PRIVATE);
-
if (defaultObject instanceof String)
-
{
-
return sp.getString(key, (String) defaultObject);
-
} else if (defaultObject instanceof Integer)
-
{
-
return sp.getInt(key, (Integer) defaultObject);
-
} else if (defaultObject instanceof Boolean)
-
{
-
return sp.getBoolean(key, (Boolean) defaultObject);
-
} else if (defaultObject instanceof Float)
-
{
-
return sp.getFloat(key, (Float) defaultObject);
-
} else if (defaultObject instanceof Long)
-
{
-
return sp.getLong(key, (Long) defaultObject);
-
}
-
return null;
-
}
-
/**
-
* 移除某个key值已经对应的值
-
* @param context
-
* @param key
-
*/
-
public static void remove(Context context, String key)
-
{
-
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
-
Context.MODE_PRIVATE);
-
SharedPreferences.Editor editor = sp.edit();
-
editor.remove(key);
-
SharedPreferencesCompat.apply(editor);
-
}
-
/**
-
* 清除所有数据
-
* @param context
-
*/
-
public static void clear(Context context)
-
{
-
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
-
Context.MODE_PRIVATE);
-
SharedPreferences.Editor editor = sp.edit();
-
editor.clear();
-
SharedPreferencesCompat.apply(editor);
-
}
-
/**
-
* 查询某个key是否已经存在
-
* @param context
-
* @param key
-
* @return
-
*/
-
public static boolean contains(Context context, String key)
-
{
-
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
-
Context.MODE_PRIVATE);
-
return sp.contains(key);
-
}
-
/**
-
* 返回所有的键值对
-
*
-
* @param context
-
* @return
-
*/
-
public static Map<String, ?> getAll(Context context)
-
{
-
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
-
Context.MODE_PRIVATE);
-
return sp.getAll();
-
}
-
/**
-
* 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类
-
*
-
* @author zhy
-
*
-
*/
-
private static class SharedPreferencesCompat
-
{
-
private static final Method sApplyMethod = findApplyMethod();
-
/**
-
* 反射查找apply的方法
-
*
-
* @return
-
*/
-
@SuppressWarnings({ “unchecked”, “rawtypes” })
-
private static Method findApplyMethod()
-
{
-
try
-
{
-
Class clz = SharedPreferences.Editor.class;
-
return clz.getMethod(“apply”);
-
} catch (NoSuchMethodException e)
-
{
-
}
-
return null;
-
}
-
/**
-
* 如果找到则使用apply执行,否则使用commit
-
*
-
* @param editor
-
*/
-
public static void apply(SharedPreferences.Editor editor)
-
{
-
try
-
{
-
if (sApplyMethod != null)
-
{
-
sApplyMethod.invoke(editor);
-
return;
-
}
-
} catch (IllegalArgumentException e)
-
{
-
} catch (IllegalAccessException e)
-
{
-
} catch (InvocationTargetException e)
-
{
-
}
-
editor.commit();
-
}
-
}
-
}
对SharedPreference的使用做了建议的封装,对外公布出put,get,remove,clear等等方法;
注意一点,里面所有的commit操作使用了SharedPreferencesCompat.apply进行了替代,目的是尽可能的使用apply代替commit
首先说下为什么,因为commit方法是同步的,并且我们很多时候的commit操作都是UI线程中,毕竟是IO操作,尽可能异步;
所以我们使用apply进行替代,apply异步的进行写入;
但是apply相当于commit来说是new API呢,为了更好的兼容,我们做了适配;
SharedPreferencesCompat也可以给大家创建兼容类提供了一定的参考~~
==================================================================================
[java] view plain copy
-
package com.zhy.utils;
-
import android.content.Context;
-
import android.util.TypedValue;
-
/**
-
* 常用单位转换的辅助类
-
*
-
*
-
*
-
*/
-
public class DensityUtils
-
{
-
private DensityUtils()
-
{
-
/* cannot be instantiated */
-
throw new UnsupportedOperationException(“cannot be instantiated”);
-
}
-
/**
-
* dp转px
-
*
-
* @param context
-
* @param val
-
* @return
-
*/
-
public static int dp2px(Context context, float dpVal)
-
{
-
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-
dpVal, context.getResources().getDisplayMetrics());
-
}
-
/**
-
* sp转px
-
*
-
* @param context
-
* @param val
-
* @return
-
*/
-
public static int sp2px(Context context, float spVal)
-
{
-
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
-
spVal, context.getResources().getDisplayMetrics());
-
}
-
/**
-
* px转dp
-
*
-
* @param context
-
* @param pxVal
-
* @return
-
*/
-
public static float px2dp(Context context, float pxVal)
-
{
-
final float scale = context.getResources().getDisplayMetrics().density;
-
return (pxVal / scale);
-
}
-
/**
-
* px转sp
-
*
-
* @param fontScale
-
* @param pxVal
-
* @return
-
*/
-
public static float px2sp(Context context, float pxVal)
-
{
-
return (pxVal / context.getResources().getDisplayMetrics().scaledDensity);
-
}
-
}
====================================================================================
[java] view plain copy
-
package com.zhy.utils;
-
import java.io.File;
-
import android.os.Environment;
-
import android.os.StatFs;
-
/**
-
* SD卡相关的辅助类
-
*
-
*
-
*
-
*/
-
public class SDCardUtils
-
{
-
private SDCardUtils()
-
{
-
/* cannot be instantiated */
-
throw new UnsupportedOperationException(“cannot be instantiated”);
-
}
-
/**
-
* 判断SDCard是否可用
-
*
-
* @return
-
*/
-
public static boolean isSDCardEnable()
-
{
-
return Environment.getExternalStorageState().equals(
-
Environment.MEDIA_MOUNTED);
-
}
-
/**
-
* 获取SD卡路径
-
*
-
* @return
-
*/
-
public static String getSDCardPath()
-
{
-
return Environment.getExternalStorageDirectory().getAbsolutePath()
-
+ File.separator;
-
}
-
/**
-
* 获取SD卡的剩余容量 单位byte
-
*
-
* @return
-
*/
-
public static long getSDCardAllSize()
-
{
-
if (isSDCardEnable())
-
{
-
StatFs stat = new StatFs(getSDCardPath());
-
// 获取空闲的数据块的数量
-
long availableBlocks = (long) stat.getAvailableBlocks() - 4;
-
// 获取单个数据块的大小(byte)
-
long freeBlocks = stat.getAvailableBlocks();
-
return freeBlocks * availableBlocks;
-
}
-
return 0;
-
}
-
/**
-
* 获取指定路径所在空间的剩余可用容量字节数,单位byte
-
*
-
* @param filePath
-
* @return 容量字节 SDCard可用空间,内部存储可用空间
-
*/
-
public static long getFreeBytes(String filePath)
-
{
-
// 如果是sd卡的下的路径,则获取sd卡可用容量
-
if (filePath.startsWith(getSDCardPath()))
-
{
-
filePath = getSDCardPath();
-
} else
-
{// 如果是内部存储的路径,则获取内存存储的可用容量
-
filePath = Environment.getDataDirectory().getAbsolutePath();
-
}
-
StatFs stat = new StatFs(filePath);
-
long availableBlocks = (long) stat.getAvailableBlocks() - 4;
-
return stat.getBlockSize() * availableBlocks;
-
}
-
/**
-
* 获取系统存储路径
-
*
-
* @return
-
*/
-
public static String getRootDirectoryPath()
-
{
-
return Environment.getRootDirectory().getAbsolutePath();
-
}
-
}
===================================================================================
[java] view plain copy
-
package com.zhy.utils;
-
import android.app.Activity;
-
import android.content.Context;
-
import android.graphics.Bitmap;
-
import android.graphics.Rect;
-
import android.util.DisplayMetrics;
-
import android.view.View;
-
import android.view.WindowManager;
-
/**
-
* 获得屏幕相关的辅助类
-
*
-
*
-
*
-
*/
-
public class ScreenUtils
-
{
-
private ScreenUtils()
-
{
-
/* cannot be instantiated */
-
throw new UnsupportedOperationException(“cannot be instantiated”);
-
}
-
/**
-
* 获得屏幕高度
-
*
-
* @param context
-
* @return
-
*/
-
public static int getScreenWidth(Context context)
-
{
-
WindowManager wm = (WindowManager) context
-
.getSystemService(Context.WINDOW_SERVICE);
-
DisplayMetrics outMetrics = new DisplayMetrics();
-
wm.getDefaultDisplay().getMetrics(outMetrics);
-
return outMetrics.widthPixels;
-
}
-
/**
-
* 获得屏幕宽度
-
*
-
* @param context
-
* @return
-
*/
-
public static int getScreenHeight(Context context)
-
{
-
WindowManager wm = (WindowManager) context
-
.getSystemService(Context.WINDOW_SERVICE);
-
DisplayMetrics outMetrics = new DisplayMetrics();
-
wm.getDefaultDisplay().getMetrics(outMetrics);
-
return outMetrics.heightPixels;
-
}
-
/**
-
* 获得状态栏的高度
-
*
-
* @param context
-
* @return
-
*/
-
public static int getStatusHeight(Context context)
-
{
-
int statusHeight = -1;
-
try
-
{
-
Class<?> clazz = Class.forName(“com.android.internal.R$dimen”);
-
Object object = clazz.newInstance();
-
int height = Integer.parseInt(clazz.getField(“status_bar_height”)
-
.get(object).toString());
-
statusHeight = context.getResources().getDimensionPixelSize(height);
-
} catch (Exception e)
-
{
-
e.printStackTrace();
-
}
-
return statusHeight;
-
}
-
/**
-
* 获取当前屏幕截图,包含状态栏
-
*
-
* @param activity
-
* @return
-
*/
-
public static Bitmap snapShotWithStatusBar(Activity activity)
-
{
-
View view = activity.getWindow().getDecorView();
-
view.setDrawingCacheEnabled(true);
-
view.buildDrawingCache();
-
Bitmap bmp = view.getDrawingCache();
-
int width = getScreenWidth(activity);
-
int height = getScreenHeight(activity);
-
Bitmap bp = null;
-
bp = Bitmap.createBitmap(bmp, 0, 0, width, height);
-
view.destroyDrawingCache();
-
return bp;
-
}
-
/**
-
* 获取当前屏幕截图,不包含状态栏
-
*
-
* @param activity
-
* @return
-
*/
-
public static Bitmap snapShotWithoutStatusBar(Activity activity)
-
{
-
View view = activity.getWindow().getDecorView();
-
view.setDrawingCacheEnabled(true);
-
view.buildDrawingCache();
-
Bitmap bmp = view.getDrawingCache();
-
Rect frame = new Rect();
-
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
-
int statusBarHeight = frame.top;
-
int width = getScreenWidth(activity);
-
int height = getScreenHeight(activity);
-
Bitmap bp = null;
-
bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height
-
- statusBarHeight);
-
view.destroyDrawingCache();
-
return bp;
-
}
-
}
========================================================================
[java] view plain copy
-
package com.zhy.utils;
-
import android.content.Context;
-
import android.content.pm.PackageInfo;
-
import android.content.pm.PackageManager;
-
import android.content.pm.PackageManager.NameNotFoundException;
-
/**
-
* 跟App相关的辅助类
-
*
-
*
-
*
-
*/
-
public class AppUtils
-
{
-
private AppUtils()
-
{
-
/* cannot be instantiated */
-
throw new UnsupportedOperationException(“cannot be instantiated”);
-
}
-
/**
-
* 获取应用程序名称
-
*/
-
public static String getAppName(Context context)
-
{
-
try
-
{
-
PackageManager packageManager = context.getPackageManager();
-
PackageInfo packageInfo = packageManager.getPackageInfo(
-
context.getPackageName(), 0);
-
int labelRes = packageInfo.applicationInfo.labelRes;
-
return context.getResources().getString(labelRes);
-
} catch (NameNotFoundException e)
-
{
-
e.printStackTrace();
-
}
-
return null;
-
}
结语
看到这篇文章的人不知道有多少是和我一样的Android程序员。
35岁,这是我们这个行业普遍的失业高发阶段,这种情况下如果还不提升自己的技能,进阶发展,我想,很可能就是本行业的职业生涯的终点了。
我们要有危机意识,切莫等到一切都成定局时才开始追悔莫及。只要有规划的,有系统地学习,进阶提升自己并不难,给自己多充一点电,你才能走的更远。
千里之行始于足下。这是上小学时,那种一元钱一个的日记本上每一页下面都印刷有的一句话,当时只觉得这句话很短,后来渐渐长大才慢慢明白这句话的真正的含义。
有了学习的想法就赶快行动起来吧,不要被其他的事情牵绊住了前行的脚步。不要等到裁员时才开始担忧,不要等到面试前一晚才开始紧张,不要等到35岁甚至更晚才开始想起来要学习要进阶。
给大家一份系统的Android学习进阶资料,希望这份资料可以给大家提供帮助。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
“cannot be instantiated”);
-
}
-
/**
-
* 获取应用程序名称
-
*/
-
public static String getAppName(Context context)
-
{
-
try
-
{
-
PackageManager packageManager = context.getPackageManager();
-
PackageInfo packageInfo = packageManager.getPackageInfo(
-
context.getPackageName(), 0);
-
int labelRes = packageInfo.applicationInfo.labelRes;
-
return context.getResources().getString(labelRes);
-
} catch (NameNotFoundException e)
-
{
-
e.printStackTrace();
-
}
-
return null;
-
}
结语
看到这篇文章的人不知道有多少是和我一样的Android程序员。
35岁,这是我们这个行业普遍的失业高发阶段,这种情况下如果还不提升自己的技能,进阶发展,我想,很可能就是本行业的职业生涯的终点了。
我们要有危机意识,切莫等到一切都成定局时才开始追悔莫及。只要有规划的,有系统地学习,进阶提升自己并不难,给自己多充一点电,你才能走的更远。
千里之行始于足下。这是上小学时,那种一元钱一个的日记本上每一页下面都印刷有的一句话,当时只觉得这句话很短,后来渐渐长大才慢慢明白这句话的真正的含义。
有了学习的想法就赶快行动起来吧,不要被其他的事情牵绊住了前行的脚步。不要等到裁员时才开始担忧,不要等到面试前一晚才开始紧张,不要等到35岁甚至更晚才开始想起来要学习要进阶。
给大家一份系统的Android学习进阶资料,希望这份资料可以给大家提供帮助。
[外链图片转存中…(img-3cYjElOl-1715741346905)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!