首页 文章 精选 留言 我的

精选列表

搜索[启动程序],共10000篇文章
优秀的个人博客,低调大师

Android Studio运行Hello World程序

老的神舟本本装上了深度LINUX了。。。应该是基于ubuntu的,安装软件用的apt-get而不是yum 想重装学下android原生开发,官网下载了android studio, 发现不用FQ也能下载了,不错不错,支持支持 下载后解压了直接双击那个Android Studio.sh运行就行了,新建一个hello world项目,结果运行不起来,那个调试那个地方都没有绿色三角形, 想了下,好像没有装JAVA,又上ORACLE上下载了JAVA的安装,结果又总是下不了,晕。。不知道是不是得FQ。。。 然后不知道从哪里搜索出来的。。在命令行里装了。。装的是OPENJDK。。。装了以后再运行android studio ,还是运行不起来 最后看了下项目设置 File -> Project Structure ,发现NDK没有安装,安装以后再apply一下,再刷新下项目,结果就能运行上了 不错不错,支持支持,特此记录一下....(下载NDK 要800多M的,看下载域名是google.com的,想着得FQ下载的。。结果不用,我的南宁电信2M带宽10分钟左右就下载好了...)

优秀的个人博客,低调大师

退出程序?

有时候我们希望用户双击返回键的时候,再去退出应用,那么怎么实现这种需求呢? 有时候我们希望用户点击一次返回键的时候,不是退出应用,而是返回到桌面,那么怎么实现这种效果呢? 如何管理整个应用的各个环节,做到退出应用呢? 在这里,对相关方法大概整理。 一、容器式 我们在BaseActivity 建立一个全局容器,把所有的Activity存储起来统一维护,另外可以在Base里可以处理一些界面的共同逻辑,退出时循环遍历finish所有Activity @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 添加Activity到堆栈 BaseAtyContainer.getInstance().addActivity(this); } @Override protected void onDestroy() { super.onDestroy(); // 结束Activity&从栈中移除该Activity BaseAtyContainer.getInstance().removeActivity(this); } } class BaseAtyContainer { private BaseAtyContainer() { } private static BaseAtyContainer instance = new BaseAtyContainer(); private static List<Activity> activityStack = new ArrayList<Activity>(); public static BaseAtyContainer getInstance() { return instance; } public void addActivity(Activity aty) { activityStack.add(aty); } public void removeActivity(Activity aty) { activityStack.remove(aty); } /** * 结束所有Activity */ public void finishAllActivity() { for (int i = 0, size = activityStack.size(); i < size; i++) { if (null != activityStack.get(i)) { activityStack.get(i).finish(); } } activityStack.clear(); } } 需要退出的界面中仅需调用以下代码,即可完成退出应用的逻辑。(此方法较为简单, 不过可以发现activityStack持有这些Activity的强引用,也就是说当某个Activity异常退出时,activityStack没有及时释放掉引用,可能存在导致内存问题的隐患。) BaseAtyContainer.getInstance().finishAllActivity(); 二、广播式 通过在BaseActivity中注册一个广播,当退出时发送一个广播,finish退出 public class BaseActivity extends Activity { //退出的广播频段 private static final String EXITACTION = "action2exit"; private ExitReceiver exitReceiver = new ExitReceiver(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //界面创建时注册广播 IntentFilter filter = new IntentFilter(); filter.addAction(EXITACTION); registerReceiver(exitReceiver, filter); } @Override protected void onDestroy() { super.onDestroy(); //界面销毁时解除广播 unregisterReceiver(exitReceiver); } class ExitReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //收到广播时,finish BaseActivity.this.finish(); } } } 需要退出的界面中仅需调用以下代码,即可完成退出应用的逻辑。 sendBroadcast(new Intent("action2exit")); 三、进程式 通过直接杀死当前应用的进程来结束应用,简单粗暴!(不推荐!不推荐!不推荐!!)方式一: android.os.Process.killProcess(android.os.Process.myPid()); 方式二: System.exit(0); 方式三(需要权限: requires android.permission.KILL_BACKGROUND_PROCESSES): ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); manager.killBackgroundProcesses(getPackageName()); 这三种都能达到退出应用的效果。但是部分真机会直接失效,或者只能finish当前Activity,国产ROM改动太多,不建议使用相关方法。 四、 Receiver+singleTask 我们知道Activity有四种加载模式,而singleTask就是其中的一种,使用这个模式之后,当startActivity时,它先会在当前栈中查询是否存在Activity的实例,如果存在,则将其至于栈顶,并将其之上的所有Activity移除栈。 那么我们打开一个app,首先是一个splash页面,然后会finish掉splash页面。跳转到主页。然后会在主页进行N次的跳转,期间会产生数量不定的Activity,有的被销毁,有的驻留在栈中,但是栈底永远是我们的MainActivity。这样就让问题变得简单很多了。我们只需两步操作即可优雅的实现app的退出。 步骤一:在AndroidManifest.xml中找到我们的主界面Activity,并对其设置android:launchMode="singleTask"(这里以MainActivity为例)。 <activity android:name=".MainActivity" android:launchMode="singleTask"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> 步骤二:在MainActivity注册一个退出广播,和第二个广播式一样,但是这里只需要在MainActivity一个页面注册即可。 public class MainActivity extends Activity { //退出的广播频段 private static final String EXITACTION = "action2exit"; private ExitReceiver exitReceiver = new ExitReceiver(); class ExitReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //收到广播时,finish finish(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //界面创建时注册广播 IntentFilter filter = new IntentFilter(); filter.addAction(EXITACTION); registerReceiver(exitReceiver, filter); } @Override protected void onDestroy() { super.onDestroy(); //界面销毁时解除广播 unregisterReceiver(exitReceiver); } } 至此,当我们需要退出的时候只需要startActivity(context,MainActivity,class), 再发送一个退出广播。上面代码首先会把栈中MainActivity之上的所有Activity移除出栈,然后接到广播finish()自己。一切OK ! 没有弹框,不用考虑机型Rom适配。不会有内存问题,就是那么的优雅,简单! startActivity(new Intent(context,MainActivity.class)); sendBroadcast(new Intent(EXITACTION)); 五、singleTask(Receiver+singleTask优化版) 按照第四种方式,注册广播略显麻烦和臃肿,这里提出一种更简单的方式,思路也很简单。步骤一:既然是使用singleTask处理,那么同样需要在AndroidManifest.xml中找到我们的主界面Activity,并对其设置android:launchMode="singleTask"(这里以MainActivity为例)。 <activity android:name=".MainActivity" android:launchMode="singleTask"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> 步骤二:在MainActivity中重写onNewIntent()方法 public class MainActivity extends Activity { private static final String TAG_EXIT = "tag2exit"; @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); if (intent != null) { boolean isExit = intent.getBooleanExtra(TAG_EXIT, false); if (isExit) { this.finish(); } } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } } 至此,当我们需要退出的时候只需要翼指定的tag值去startActivity即可完成退出逻辑 Intent intent = new Intent(context,MainActivity.class); intent.putExtra(MainActivity.TAG_EXIT, true); startActivity(intent); 六、 双击退出(我最喜欢这种) 我们可以看到很多应用都是双击两次BACK键退出应用,大部分就是基于这样的方式来实现的。很简单,步骤一:首先依然是使用singleTask处理,那么同样需要在AndroidManifest.xml中找到我们的主界面Activity,并对其设置android:launchMode="singleTask"(这里以MainActivity为例)。 <activity android:name=".MainActivity" android:launchMode="singleTask"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> 2、将退出出口放置在MainActivity public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } private boolean mIsExit; /** * 双击返回键退出 */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { if (mIsExit) { this.finish(); } else { Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show(); mIsExit = true; new Handler().postDelayed(new Runnable() { @Override public void run() { mIsExit = false; } }, 2000); } return true; } return super.onKeyDown(keyCode, event); } } 七、 返回桌面,不退出应用 有时候我们的应用我们希望他点击一次返回键的时候不是退出应用而是返回到桌面,比如像QQ和微信等聊天软件,在主界面点击返回键的时候不是退出应用而是返回到桌面,那么怎么能够实现这种需求呢?其实也很简单,依然只需要重写onKeyDown()这个方法,在方法里面实现返回的代码,这样就可以实现这个需求了。具体代码如下所示: public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { Intent home = new Intent(Intent.ACTION_MAIN); home.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); home.addCategory(Intent.CATEGORY_HOME); startActivity(home); return true; } return super.onKeyDown(keyCode, event); } } 以上,整体概括了一部分返回桌面,退出应用的相关方法和逻辑 **当然一定还有更多方法和更优化的逻辑,还请大家提出,共同完善,有了需求才有了功能,有了想法才有了创作,你的反馈会是使我进步的最大动力。** 觉得还不够方便?还想要什么功能?告诉我!欢迎反馈,欢迎Star。

优秀的个人博客,低调大师

程序员如何克服焦虑?

克服焦虑的最好方法就是在征服世界之前,请先走好脚下的路 现代社会节奏越来越快,焦虑成为了一种普遍存在的城市病。不知不觉中,竟有很多人都错误地认为:只有焦虑和迷茫的人,才是有追求、有上进心的人。 这种说法之所以看似没有毛病,大抵是因为焦虑的人太多了,其中更是不乏很多成功者。但我想说,为什么只有追求、有上进心的人,才会焦虑和迷茫呢?这样是不是自我矛盾呢? 在帮助职场人做职业咨询时,发现一个问题:他们的焦虑和迷茫都是因为接触太多外面的世界,而后想得太多而导致。 比如,一些人听到罗胖的跨年演讲后,就开始焦虑和迷茫,担心自己所在的行业有黑天鹅事件发生,开始转到陌生的领域去挖矿。 你转移到陌生领域,就不担心黑天鹅事件发生了吗?这真是大错特错的荒谬想法。当听到某一种新的理念或者想法,真的还是要谨慎思考,不要轻易拿来误导自己的人生。 没错,外面的世界非常好。但残酷的是,外面的世界对你来说未必好,或许就是一个非常大的陷阱在等待着你。 看来,如今真的是全民焦虑和迷茫,有钱的也焦虑和迷茫,没钱的更焦虑和迷茫。也正是这些焦虑和迷茫,像稻草一样,压垮了中国的年轻人。 为什么会有焦虑和迷茫呢?根据老王的调研,大致分为几种情况: 1、你的追求和你的能力不匹配。每个人都想实现财务自由,只是空有实现财务自由的心,却没有这个能力。老王也是,但只是想想而已。 现在很多职场人,看别人收入高,就马上琢磨,这个人并没有自己的能力强,他为什么会收入这么高呢?老王想说,能力是行走职场的基础,思维、情商、格局和解决实际问题的方法论,才是决定收入高低的核心。 2、你总是想着外面世界很美好,其实外面世界只是一个传说。很多职场人,总认为以自己的能力,如果跳槽薪酬会更好。但老王想说,真的未必。 前几天,和一位国际非常知名的投行朋友聊天,聊到了非常敏感的部分,就是了解薪酬。当得知到他的真实收入,老王明白,外面的世界没有想象中美好。很多高薪的收入很可能是一种传说。 很多人都误认为在北京,年薪过百万的职场人,遍地都是。 其实,你真的想错了。上个月,老王在人大和一位朋友讨论问题,看到他手中拿着调研数据。数据上显示,在北京税前年薪百万的人员不到5万人,股票期权收入除外。 且不要说这个数字,就某专业调查公司的数据显示,在中国,税前年薪超过10万的,才6500多万人。可见,外面的世界,真的没有你想象中那般美好。 最考验心理素质的,莫过于职场人每年春节回老家。老家的亲戚朋友七嘴八舌,都认为你在外面挣了很多钱,你也只能打肿了脸充门面。可只有自己心知,日子过得有多艰难。 3、被成功学误导,让自己的心处于浮躁和膨胀的边缘。很多人看到别人成功就眼红起来,总是梦想着自己也能一夜之间登上巅峰,成为人生赢家,于是开始盲目效仿,再也无法走回踏实的路线。这样缺少根基的狂热,最后都会成为虚妄。 身边也有这样一位朋友,每次见面时都会非常有激情地分享一番成功案例,然后认定,自己如果做这个事情的话,也会成功。 因为是朋友,听完会直接劝诫他:人的成功,能力只是基础,时机也很重要。还有,不要总看着别人成功带来的光鲜,却没有看到背后的艰辛。就拿王兴来说,很多都羡慕他成功,却全然忘记了他的“九败一胜”。 职场人,不要用眼睛只盯着别人成功,也要看看失败的案例。有机会就去和那些暂时的失败者聊聊天。这些经历或许会改变你的想法,让你收起浮躁和轻狂,回归现实。 作为职场人,如何解决做到不焦虑和迷茫呢? 给出的解决方案如下: 1、相信自己做的事情,坚持下来,你一样能做得很好。 2、忘记财务自由四个字,先脚踏实地、全力以赴做事,其他的都会顺其自然而来。 3、少关注成功者如何成功,因为他们的成功大多是无法复制的;多研究暂时的失败或已经失败的案例,会让你少走弯路,减少浮躁和轻狂,焦虑和迷茫距离你越来越远。 写在最后 职场上,所有的焦虑和迷茫都是野心与能力不匹配导致。减少焦虑和迷茫的唯一方法就是:让自己的心沉静下来,找回自我,回归本心。 原文发布时间为:2018-11-04 本文来自云栖社区合作伙伴“互联网架构师”,了解相关信息可以关注“互联网架构师”。

优秀的个人博客,低调大师

几条曲线构建Android表白程序

每年的情人节和七夕,甜蜜与痛苦的日子,做点什么好呢?写诗画画送礼物,逛街吃饭看电影?作为搬砖爱好者,写个表白脚本或者动画什么的吧。想起之前看到的一段H5动画,在Android平台“临摹”了一遍。效果如下图:其构图还是比较简单的,树枝加上由心形花瓣构成的心形树冠(后面做成动画之后会有随机的花瓣飘落)。 一、树枝 树枝是通过贝塞尔曲线来构造的,二阶贝塞尔曲线。 准备数据getBranches()函数中,定义各个树枝的位置和形状,最终返回树干。绘制的时候,先绘制树干,然后绘制其分支,最后绘制分支的分支(只有三层)。 public static Branch getBranches() { // 共10列,分别是id, parentId, 贝塞尔曲线控制点(3点,6列), 最大半径, 长度 int[][] data = new int[][]{ {0, -1, 217, 490, 252, 60, 182, 10, 30, 100}, {1, 0, 222, 310, 137, 227, 22, 210, 13, 100}, {2, 1, 132, 245, 116, 240, 76, 205, 2, 40}, {3, 0, 232, 255, 282, 166, 362, 155, 12, 100}, {4, 3, 260, 210, 330, 219, 343, 236, 3, 80}, {5, 0, 221, 91, 219, 58, 216, 27, 3, 40}, {6, 0, 228, 207, 95, 57, 10, 54, 9, 80}, {7, 6, 109, 96, 65, 63, 53, 15, 2, 40}, {8, 6, 180, 155, 117, 125, 77, 140, 4, 60}, {9, 0, 228, 167, 290, 62, 360, 31, 6, 100}, {10, 9, 272, 103, 328, 87, 330, 81, 2, 80} }; int n = data.length; Branch[] branches = new Branch[n]; for (int i = 0; i < n; i++) { branches[i] = new Branch(data[i]); int parent = data[i][1]; if (parent != -1) { branches[parent].addChild(branches[i]); } } return branches[0]; } 封装Branch类主要包含树枝的构建(构造函数,addChild函数),以及绘制。绘制树枝时,不断地调用grow函数,绘制点(currLen)逐渐靠近末端(maxLen), 树枝的半径逐渐变小;最终控制点到达树枝末端(currLen==maxLen), 绘制结束。如果是绘制静态画面,while循环直到grow返回false;如果是绘制动画, 可通过调用postInvalidate(),不断地对回调绘制函数, 每一帧树枝成长一截。 public class Branch { private static final int BRANCH_COLOR = Color.rgb(35, 31, 32); // control point Point[] cp = new Point[3]; int currLen; int maxLen; float radius; float part; float growX; float growY; LinkedList<Branch> childList; public Branch(int[] a){ cp[0] = new Point(a[2], a[3]); cp[1] = new Point(a[4], a[5]); cp[2] = new Point(a[6], a[7]); radius = a[8]; maxLen = a[9]; part = 1.0f / maxLen; } public boolean grow(Canvas canvas, float scareFactor){ if(currLen <= maxLen){ bezier(part * currLen); draw(canvas, scareFactor); currLen++; radius *= 0.97f; return true; }else{ return false; } } private void draw(Canvas canvas, float scareFactor){ Paint paint = CommonUtil.getPaint(); paint.setColor(BRANCH_COLOR); canvas.save(); canvas.scale(scareFactor, scareFactor); canvas.translate(growX, growY); canvas.drawCircle(0,0, radius, paint); canvas.restore(); } private void bezier(float t) { float c0 = (1 - t) * (1 - t); float c1 = 2 * t * (1 - t); float c2 = t * t; growX = c0 * cp[0].x + c1 * cp[1].x + c2* cp[2].x; growY = c0 * cp[0].y + c1 * cp[1].y + c2* cp[2].y; } public void addChild(Branch branch){ if(childList == null){ childList = new LinkedList<>(); } childList.add(branch); } } 效果图如下: 二、花瓣 花瓣的绘制,是通过一条曲线实现的:本文的主角,自带爱情故事的心形线。心形线有很多种,有的用标准方程表示,有的用参数方程表示。对于绘制曲线来说,参数方程更方便一些。在网站wolframalpha)上,可以输入方程直接预览曲线。 计算心形线因为要绘制很多花瓣,所以可以将其形状预先计算好,缓存起来。或许是因为精度的原因, 如果直接采样上图的点,绘制时如果有scale(缩放)操作,可能会显示不平滑;所以在采样心形线的点时我们放大一定比率(SCALE_FACTOR )。就像一张图片,如果分辨率是200x200, 缩小到100x100显示,图片还是清晰的,如果放大到400x400,可能会模糊。 public class Heart { private static final Path PATH = new Path(); private static final float SCALE_FACTOR = 10f; private static final float RADIUS = 18 * SCALE_FACTOR; static { // x = 16 sin^3 t // y = 13 cos t - 5 cos 2t - 2 cos 3t - cos 4t // http://www.wolframalpha.com/input/?i=x+%3D+16+sin%5E3+t%2C+y+%3D+(13+cos+t+-+5+cos+2t+-+2+cos+3t+-+cos+4t) int n = 101; Point[] points = new Point[n]; float t = 0f; float d = (float) (2 * Math.PI / (n - 1)); for (int i = 0; i < n; i++) { float x = (float) (16 * Math.pow(Math.sin(t), 3)); float y = (float) (13 * Math.cos(t) - 5 * Math.cos(2 * t) - 2 * Math.cos(3 * t) - Math.cos(4 * t)); points[i] = new Point(SCALE_FACTOR * x , -SCALE_FACTOR * y ); t += d; } PATH.moveTo(points[0].x, points[0].y); for (int i = 1; i < n; i++) { PATH.lineTo(points[i].x, points[i].y); } PATH.close(); } public static Path getPath(){ return PATH; } public static float getRadius(){ return RADIUS; } } 封装Bloom类一片花瓣,除了形状之外,还有方位,颜色,方向,大小等参数。故此,和Branch一样,封装了一个类。花瓣的颜色和方向参数是随机初始化的。颜色方面,ARGB中Red通道固定为最大值0xff, 效果就是花瓣的颜色为红,紫,黄,白等。因为要适应移动设备的多分辨率,所以一些参数要根据分辨率来动态设置。 public class Bloom { protected static float sMaxScale = 0.2f; protected static int sMaxRadius = Math.round(sMaxScale * Heart.getRadius()); protected static float sFactor; /** * 初始化显示参数 * @param resolutionFactor 根据屏幕分辨率设定缩放因子 */ public static void initDisplayParam(float resolutionFactor){ sFactor = resolutionFactor; sMaxScale = 0.2f * resolutionFactor; sMaxRadius = Math.round(sMaxScale * Heart.getRadius()); } Point position; int color; float angle; float scale; // 调速器,控制开花动画的快慢 int governor = 0; public Bloom(Point position) { this.position = position; this.color = Color.argb(CommonUtil.random(76, 255), 0xff, CommonUtil.random(255), CommonUtil.random(255)); this.angle = CommonUtil.random(360); } public boolean grow(Canvas canvas) { if (scale <= sMaxScale) { if((governor & 1) == 0) { scale += 0.0125f * sFactor; draw(canvas); } governor++; return true; } else { return false; } } protected float getRadius() { return Heart.getRadius() * scale; } private void draw(Canvas canvas) { Paint paint = CommonUtil.getPaint(); paint.setColor(color); float r = getRadius(); canvas.save(); canvas.translate(position.x, position.y); canvas.saveLayerAlpha(-r, -r, r, r, Color.alpha(color)); canvas.save(); canvas.rotate(angle); canvas.scale(scale, scale); canvas.drawPath(Heart.getPath(), paint); canvas.restore(); canvas.restore(); canvas.restore(); } } 三、树冠 树冠是由数百片花瓣构成,关键点在于确定这些花瓣的位置。这里用到另一条心形线(x^2 + y^2 -1)^3 - x^2 * y^3 = 0%5E3-x%5E2*y%5E3%3D0)。我们需要做的,是在心形内部选取位置,而非绘制曲线,故此,标准方程相对于参数方程更合适。 坐标系中的点(x,y), 计算ax+by, 大于0和小于0分别在直线的两侧, x^2 + y^2 - r^2 则分别在圆外和圆内;这个现象还蛮奇妙的,虽然我不知道这在数学中叫什么-_-。类似的,在x=[-c, c], y=[-c,c]的范围内随机选取(x^2 + y^2 -1)^3 - x^2 * y^3<0的点,即可使得花瓣的位置错落于心形线中。 private static float r; private static float c; /** * 初始化参数 * @param canvasHeight 画布的高度 * @param crownRadiusFactor 树冠半径的缩放因子 */ public static void init(int canvasHeight, float crownRadiusFactor){ r = canvasHeight * crownRadiusFactor; c = r * 1.35f; } public static void fillBlooms(List<Bloom> blooms, int num) { int n = 0; while (n < num) { float x = CommonUtil.random(-c, c); float y = CommonUtil.random(-c, c); if (inHeart(x, y, r)) { blooms.add(new Bloom(new Point(x, -y))); n++; } } } private static boolean inHeart(float px, float py, float r) { // (x^2+y^2-1)^3-x^2*y^3=0 float x = px / r; float y = py / r; float sx = x * x; float sy = y * y; float a = sx + sy - 1; return a * a * a - sx * sy * y < 0; } 绘制动画 不断地触发onDraw()回调,在每一帧里面改变绘制参数,就形成动画了。在这个例子中,划分了几个动画阶段,每个阶段各自变化自己的参数,到达一定的状态就切换到下一阶段。总之,就是分而治之,然后串联起来。 public class TreeView extends View { private static Tree tree; public TreeView(Context context) { super(context); } @Override protected void onDraw(Canvas canvas) { if(tree == null){ tree = new Tree(getWidth(), getHeight()); } tree.draw(canvas); // 这个函数只是标记view为invalidate状态,并不会马上触发重绘; // 标记invalidate状态后,下一个绘制周期(约16s), 会回调onDraw(); // 故此,要想动画平滑流畅,tree.draw(canvas)需在16s内完成。 postInvalidate(); } } public void draw(Canvas canvas) { // 绘制背景颜色 canvas.drawColor(0xffffffee); // 绘制动画元素 canvas.save(); canvas.translate(snapshotDx + xOffset, 0); switch (step) { case BRANCHES_GROWING: drawBranches(); drawSnapshot(canvas); break; case BLOOMS_GROWING: drawBlooms(); drawSnapshot(canvas); break; case MOVING_SNAPSHOT: movingSnapshot(); drawSnapshot(canvas); break; case BLOOM_FALLING: drawSnapshot(canvas); drawFallingBlooms(canvas); break; default: break; } canvas.restore(); } 后记 本来打算七夕前的周末搞定它的,无奈很多知识忘记了,需要回头温习,没赶上。很多时候就是这样,学的时候不知道有什么用,用的时候又记不起来-_- 调整参数也消耗不少时间,写代码比较客观,调参数则比较主观:方位摆放,显示大小,动画快慢…… 构图中左上角有留白,可以在那里输出一些表白文字。 考虑到移动端的流量,动图部分只截取最后一个阶段的动画。 篇幅限制,文中只是贴了部分代码,完整代码可到github下载HeartTree。

优秀的个人博客,低调大师

小程序https如何购买、配置

在阿里云找到SSL证书页面,阿里云提供免费的SSL证书 image.png 选择品牌 image.png 选择免费型 image.png 进入控制台就可以看到已经购买的证书了 image.png 补全信息 image.png 后面忘了截图,大概有以下几个步骤: 将文件上传到服务器指定位置,需要URL能够访问到(非https) 指定位置是一个隐藏文件夹,window下需要用mkdir命令创建 上传文件过一会就会自动验证成功 第3步很容易失败,建议直接在服务器上下载验证文件,多试几次 配置Apache或者Nginx # 添加 SSL 协议支持协议,去掉不安全的协议 SSLProtocol all -SSLv2 -SSLv3 # 修改加密套件如下 SSLCipherSuite HIGH:!RC4:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!EXP:+MEDIUM SSLHonorCipherOrder on # 证书公钥配置 SSLCertificateFile cert/public.pem # 证书私钥配置 SSLCertificateKeyFile cert/215045620450170.key # 证书链配置,如果该属性开头有 '#'字符,请删除掉 SSLCertificateChainFile cert/chain.pem server { listen 443; server_name localhost; ssl on; root html; index index.html index.htm; ssl_certificate cert/215045620450170.pem; ssl_certificate_key cert/215045620450170.key; ssl_session_timeout 5m; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; location / { root html; index index.html index.htm; } } 分享一下我最终的配置(Apache虚拟站点) <VirtualHost *:443> SSLEngine on ServerName demo.com:443 SSLCertificateKeyFile "${SRVROOT}/conf/ssl_dict/215045620450170.key" SSLCertificateFile "${SRVROOT}/conf/ssl_dict/public.pem" SSLCertificateChainFile "${SRVROOT}/conf/ssl_dict/chain.pem" DocumentRoot "E:\wwwroot\demo.com\public" ServerName demo.com ServerAlias demo.com #START-ERROR-PAGE ErrorDocument 403 /403.html ErrorDocument 404 /404.html ErrorDocument 502 /502.html #END-ERROR-PAGE #startPHP <Files ~ "\.php$"> Options FollowSymLinks ExecCGI AddHandler fcgid-script .php FcgidWrapper "E:/BtSoft/WebSoft/php/7.1/php-cgi.exe" .php </Files> #endPHP #start301 #end301 #REFERER-START #REFERER-END #PROXY-START #PROXY-END <Directory "E:\wwwroot\demo.com\public"> Options FollowSymLinks ExecCGI AllowOverride All Require all granted DirectoryIndex index.php default.php index.html index.htm default.html default.htm </Directory> ErrorLog "logs/demo.com-error.log" CustomLog "logs/demo.com-access.log" common </VirtualHost> 推荐一个https相关的资料站 https://github.com/cheaphttps/https-start

优秀的个人博客,低调大师

Python 面向对象程序设计

类的设计 方法优先的原则, 在__init__方法中创建出需要的属性, 对于基类来说, 只进行默认值得初始化, 0, None等, 对于真正需要使用的子类, __init__方法则是进行我们需要的初始化, 不在基类中进行初始化就与Java中的构造方法不能继承是一样的了, 要在子类中初始化所有的属性, 还可以提供方便的代码提示(在PyCharm中) 属于类的属性称之为类成员变量, 对于类成员的初始化, 如果简单的初始化则直接赋值, 如果是复杂的初始化就采用函数方式, 此方法类似于Java中的静态代码块, 用于加载图片音乐 等静态资源 在第一点中提到了基类, 该基类不能直接拿来用, 但是在Python有没有Java中的接口或者抽象类, 在编译的时候就会报错, 在Python中要解决这个问题可以通过命名的方法人为的判断, 使用形容或者Base开头的类表示不要直接使用该类 对于常量, 定义一个专门的类来存放常量, 将常量作为静态的属性(大写), 或者直接定义在模块中

优秀的个人博客,低调大师

java程序解压/压缩.gz文件

压缩成.gz格式 import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.zip.GZIPOutputStream; public class CompressFileGZIP { private static void doCompressFile(String inFileName) { try { System.out.println("Creating the GZIP output stream."); String outFileName = inFileName + ".gz"; GZIPOutputStream out = null; try { out = new GZIPOutputStream(new FileOutputStream(outFileName)); } catch(FileNotFoundException e) { System.err.println("Could not create file: " + outFileName); System.exit(1); } System.out.println("Opening the input file."); FileInputStream in = null; try { in = new FileInputStream(inFileName); } catch (FileNotFoundException e) { System.err.println("File not found. " + inFileName); System.exit(1); } System.out.println("Transfering bytes from input file to GZIP Format."); byte[] buf = new byte[1024]; int len; while((len = in.read(buf)) > 0) { out.write(buf, 0, len); } in.close(); System.out.println("Completing the GZIP file"); out.finish(); out.close(); } catch (IOException e) { e.printStackTrace(); System.exit(1); } } /** * Sole entry point to the class and application. * @param args Array of String arguments. */ public static void main(String[] args) { String str="E:\\AUTORUN.INF"; doCompressFile(str); } } 解压.gz格式 import java.util.zip.GZIPInputStream; import java.io.FileOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; public class UncompressFileGZIP { /** * Uncompress the incoming file. * @param inFileName Name of the file to be uncompressed */ private static void doUncompressFile(String inFileName) { try { if (!getExtension(inFileName).equalsIgnoreCase("gz")) { System.err.println("File name must have extension of \".gz\""); System.exit(1); } System.out.println("Opening the compressed file."); GZIPInputStream in = null; try { in = new GZIPInputStream(new FileInputStream(inFileName)); } catch(FileNotFoundException e) { System.err.println("File not found. " + inFileName); System.exit(1); } System.out.println("Open the output file."); String outFileName = getFileName(inFileName); FileOutputStream out = null; try { out = new FileOutputStream(outFileName); } catch (FileNotFoundException e) { System.err.println("Could not write to file. " + outFileName); System.exit(1); } System.out.println("Transfering bytes from compressed file to the output file."); byte[] buf = new byte[1024]; int len; while((len = in.read(buf)) > 0) { out.write(buf, 0, len); } System.out.println("Closing the file and stream"); in.close(); out.close(); } catch (IOException e) { e.printStackTrace(); System.exit(1); } } /** * Used to extract and return the extension of a given file. * @param f Incoming file to get the extension of * @return <code>String</code> representing the extension of the incoming * file. */ public static String getExtension(String f) { String ext = ""; int i = f.lastIndexOf('.'); if (i > 0 && i < f.length() - 1) { ext = f.substring(i+1); } return ext; } /** * Used to extract the filename without its extension. * @param f Incoming file to get the filename * @return <code>String</code> representing the filename without its * extension. */ public static String getFileName(String f) { String fname = ""; int i = f.lastIndexOf('.'); if (i > 0 && i < f.length() - 1) { fname = f.substring(0,i); } return fname; } /** * Sole entry point to the class and application. * @param args Array of String arguments. */ public static void main(String[] args) { doUncompressFile("E:\\AUTORUN.INF.gz"); } } 本文出处:http://panshaobinsb.iteye.com/blog/1566231

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册