在离线状态下看文档利器,速度非常迅速。最早知道是 Mac 下的 Dash,但是后来转 Linux,就想着要一个同类型的工具,没想到真的发现了更加好用的 Zeal。但就离线看文档而言,Zeal 不仅轻量而且快速。
去除快速查看文档之外,还有另一个非常实用的功能就是 Code snippets,并且和一些 IDE,编辑器结合,能够通过少量的快捷键到达非常快速的输入。从另外一方面想,作为本地代码片段管理似乎也是不错的选择。
Dash 比较突出的几大功能:
Zeal 有如下几个功能:
详情可以查看官方文档。 推荐使用 PPA 安装,官方更新比较及时
$ sudo add-apt-repository ppa:zeal-developers/ppa
$ sudo apt-get update
$ sudo apt-get install zeal
遇到 Bug 或者任何问题都可以到 GitHub 提出 issue:https://github.com/zealdocs/zeal/issues
Zeal 安安稳稳的做好文档查看就已经很好了。
Linux 下默认配置地址在:~/.config/Zeal/Zeal.conf
。
离线文档地址:~/.local/share/Zeal/Zeal/docsets
在搜索过程中又发现了一个查看文档的网站 http://devdocs.io/ , 也同样可以使用 Chrome 插件达到离线查看文档的效果,但是看了一眼似乎没有 Android 的文档,但是其他似乎挺全的。并且整个网站还是开源的。
为了帮助视图层次内部和视图之间的过渡更加容易实现动画效果,Android 提供了 Transition 框架。这一套框架能够在视图之间提供一种或者多种动画过渡效果。过渡动画要解决的另一个主要问题就是对同一场景中的多个 View 做动画,弥补了之前Android 在动画方面的缺失。
这一套框架提供如下功能:
Group-level 动画 在同一视图层次中一种或者多种动画效果
Transition-based 动画 在初始场景和终止场景之间动画
Built-in 动画 内置普通效果动画,包括 fade out 和 movement
Resource 文件支持 从 layout 资源文件中加载视图以及内置动画资源
Lifecycle callbacks 随心所欲的控制动画的过程
Transition API 在 Android 5.0 及以上被引入,但是在 4.4 Kitkat 时就引入了 Scenes 和 Transitions 的概念。在 Android 4.0 API level 14 及以上,可以使用 android.support.transition 包中内容
Scene 保存视图状态及层次结构,包括所有的视图及其属性。 Transition 框架能够从场景到场景进行过渡动画。初始场景(Staring scene)经常是当前的视图层次,而结束场景(ending scene)通常由用户从 layout 创建或者用代码从一组视图中创建。
利用静态方法 Scene.getSceneForLayout()
// Create the scene root for the scenes in this app
mSceneRoot = (ViewGroup) findViewById(R.id.scene_root);
// Create the scenes
mAScene = Scene.getSceneForLayout(mSceneRoot, R.layout.a_scene, this);
mAnotherScene =
Scene.getSceneForLayout(mSceneRoot, R.layout.another_scene, this);
或者使用构造函数构造:
Scene mScene;
// Obtain the scene root element
mSceneRoot = (ViewGroup) mSomeLayoutElement;
// Obtain the view hierarchy to add as a child of
// the scene root when this scene is entered
mViewHierarchy = (ViewGroup) someOtherLayoutElement;
// Create a scene
mScene = new Scene(mSceneRoot, mViewHierarchy);
一般情况下 Android 系统会自动在场景间动画,自定义动画可省略,但是如果想自定义动画,可以在场景退出或者进入的时候自定义动画,需要注意以下两点:
可以使用 Scene.setExitAction(Runnable action)
或者 Scene.setEnterAction(Runnable action)
来自定义进入或者退出的动作。
Scene 类中几个重要的方法:
Scene(ViewGroup sceneRoot, View layout)
。 从 Layout 中创建 Scene,当调用 enter()
方法时将 sceneRoot 下子view 全部移除并将新 Layout 中内容填充。getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context)
在 Transition 框架中,动画在开始和结束场景间创建了一系列动画帧。
系统提供的内置 transition 有如下:
Class | Tag | Attributes | Effect |
---|---|---|---|
AutoTransition | - | 默认过渡动画,Fade out 渐隐, move 位移 和 resize 大小缩放,fade in 渐显 ,按顺序 | |
Fade | android:fadingMode=”[fade_in fade_out fade_in_out]” | fade_in_out (default) 渐隐之后跟随者 渐显 | |
ChangeBounds | - | 位移和缩放 |
也通过资源文件即可修改过渡效果,避免大幅度修改 Activity 中代码。并且通过资源文件方式创建有效地将复杂的动画和代码文件分离。
通过如下步骤添加过渡动画资源:
res/transition/
目录例如如下资源文件则指定了渐隐渐显动画, res/transition/fade_transition.xml
:
<fade xmlns:android="http://schemas.android.com/apk/res/android" />
利用如下代码片段从资源文件中创建 Transition:
Transition mFadeTransition =
TransitionInflater.from(this).
inflateTransition(R.transition.fade_transition);
可以在代码中动态地创建过渡效果,可以通过非常少的代码创建。通过直接调用 Transition 的子类构造函数直接创建,例如:
Transition mFadeTransition = new Fade();
直接调用 TransitionManager.go()
静态方法,并提供一个终止场景:
TransitionManager.go(mEndingScene, mFadeTransition);
如果不指定 transition ,则系统自动套用默认的转场动画。
转场动画默认对所有的Views进行动画,如果只希望某一些特定的 Views 动画,或者某一些不做动画。 在 transition 中,每一个视图都被称作一个 target,但是得注意,只有在Scene 中的views 才被称作 target。
可以使用 removeTarget()
来从 transition 中移除某一个 view,或者使用 addTarget()
来给 Transition 添加一个 view。
如下定义的 transitionSet 和 AutoTransition 表现一致:
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
android:transitionOrdering="sequential">
<fade android:fadingMode="fade_out" />
<changeBounds />
<fade android:fadingMode="fade_in" />
</transitionSet>
代码中可以使用 TransitionInflater.from()
来加载 TransitionSet ,因为 TransitionSet 继承自 Transition,因此可以像使用 Transition 一样使用 TransitionSet。
改变视图层次并不是唯一改变UI的方式,同样也可以通过添加、修改、移除子view来对当前的视图作出修改。或者当两个场景非常相似,为了避免维护两份近乎一致的视图层次,可以只维护一份,并做一些微小的调整。
此时可以使用 delayed transition 来在两个状态之间进行转换。Transition 系统自动选择当前的视图层次作为初始状态,并记录用户对视图的修改,然后应用为终止状态,并在之后进行动态地变化。
在单一视图中使用 delay transition :
自定义过渡动画(custom transition)可以实现区别于内置转场动画的效果。比如,你可以定义一个动画来将文字和输入框的前景颜色变成灰色来表示当前禁止输入。
继承 Transition 类,并实现如下方法:
public class CustomTransition extends Transition {
@Override
public void captureStartValues(TransitionValues values) {}
@Override
public void captureEndValues(TransitionValues values) {}
@Override
public Animator createAnimator(ViewGroup sceneRoot,
TransitionValues startValues,
TransitionValues endValues) {}
}
Transition 动画使用 property 动画系统,属性动画动态地修改视图的属性,因此得知道初始和终止的值。
系统会对初始场景中的每一个view调用 captureStartValues(transitionValues)
,参数 TransitionValues 对象包含了一个指向 view 的引用和一个保存view状态的 Map 实例。在自己的实现中,获取这些属性,并将这些属性传回给map。
为了避免key 值和已经拥有的key值矛盾,可以使用如下的 TransitionValues 键的形式:
package_name:transition_name:property_name
例如下面的例子:
public class CustomTransition extends Transition {
// Define a key for storing a property value in
// TransitionValues.values with the syntax
// package_name:transition_class:property_name to avoid collisions
private static final String PROPNAME_BACKGROUND =
"com.example.android.customtransition:CustomTransition:background";
@Override
public void captureStartValues(TransitionValues transitionValues) {
// Call the convenience method captureValues
captureValues(transitionValues);
}
// For the view in transitionValues.view, get the values you
// want and put them in transitionValues.values
private void captureValues(TransitionValues transitionValues) {
// Get a reference to the view
View view = transitionValues.view;
// Store its background property in the values map
transitionValues.values.put(PROPNAME_BACKGROUND, view.getBackground());
}
...
}
系统会给终止场景中的每一个target view自动调用 ` captureEndValues(TransitionValues) ,其他方面,
captureEndValues() 和
captureStartValues()` 表现一致。
在初始和终止视图层次间进行动画,提供一个 animator ,通过复写 createAnimator()
,当系统调用此方法时,他将 root view 和开始和结束 TransitionValues 传入。系统调用 createAnimator()
方法的次数由开始和终止场景之间的变化决定。
虽然教程上只罗列了一些 Transition ,但是看文档,还是能发现不少 Transition 的直接子类。
Transition 在 XML 定义时有如下属性:
TransitionSet 在 XML 中有如下属性:
以下转场动画中原生提供的包括 Fade,Slide,Explode,但场景之间存在共享元素时,有如下的转场动画 changeBound,changeClipBounds,changeImageTransform,ChangeTransform,ChangeScroll。
渐隐渐显动画
Fade 在 XML 中有如下属性:
fade_in
, fade_out
, fade_in_out
,默认为 fade_in_out
元素从四个方向滑动进入
Slide 属性:
屏幕中间上下移走
通过获取前后Scene 中 target view 的边界,并对这些 view 做动画,改变 View 的大小
获取前后 Scene 中 getClipBounds()
的边界,并做动画,有如下属性:
android:resizeClip
通过改变 clipBounds 来改变 view,而不是改变view 自身的大小通过获取开始和结束时 Scene 中 ImageView 的 matrix ,并对他们做动画。 和 ChangeBounds 一起使用,来对 ImageView 改变大小,形状,和 ScaleType 来使动画更加流畅。
获取 Scene 中的尺寸和旋转角度,并做动画,有如下属性:
android:reparent
追踪父view 的变化android:reparentWithOverlay
A parent change should use an overlay or affect the transform of the transitionining View.改变滑动位置
下面分享一个 transitionSet 的 XML 语法:
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
android:transitionOrdering="sequential">
<changeBounds/>
<fade android:fadingMode="fade_out" >
<targets>
<target android:targetId="@id/grayscaleContainer" />
</targets>
</fade>
</transitionSet>
以上就是文档中对 Transition 的解释,关于自定义 Transition 还可以具体展开细讲,但是因为 Transition API 要求的 API 版本比较高,基本 Android 5.0 及以上才可以很好的支持,所以目前使用并不广,但是相信不久以后就能看到越来越多的转场动画了。
Podcast 近两年又突然火起来,一度认为 Podcast 是最近才流行起来的媒体,后来才发现这种媒介早在上世纪 80 年代就诞生 。近两年被再一次提起可能 iOS 系统内置播客系统是个契机,一时间让 Podcast 进入大众的视听,而国内近些年也陆陆续续出现了很多播客平台,喜马拉雅,荔枝等等, 播客这种形式在播客,视频播客新奇之后似乎很难找到自己的定位,但是在日常生活中还是有很多情况适用播客,在开车等双手双眼需要时刻准备着的时候,播客系统可以可以代替收音机,而在长途跋涉需要闭目养神时,播客也可以成为音乐的代替。
但是经过这么多年的演进, Podcast 还是依赖于 RSS 2.0 标准,不论是 iTunes 还是 Play Music ,虽然 Google 已经用关闭 Google Reader 来表明对 RSS 的态度,却还是依然无法将 Podcast 从 RSS 剥离。其实这也很矛盾,就像之前看到的一则评论,Google 托管了最大的视频播客 YouTube,却连小小的音频文件都懒得托管。所以无奈才有了此篇文章。
有几种免费靠谱的托管方式,这里就不讲收费的方案了,因为免费的可以做到很好。个人使用完全没有问题。
其实苹果官网也给了一个 Podcast Hosting 的列表 可以查看。
iTunes 和 Google Play Music 都需要不同格式的 RSS,需要特别考虑。另外音频最好带封面 14001400 px 到 20482048 px 大小,这个是 iTunes Store 需要的。
iTunes 中关于 Podcast 的介绍 。 每一个 Podcast 叫做 Episode,所有独立的可下载的音频,视屏,PDF,ePub,都属于 Episode。 iTunes 支持的文件格式包括: M4A,MP3,MOV,MP4,M4V,PDF,ePub 等等。通过 Feed Validation Service 验证 Feed 有效性。以下例子可以在帮助文档 中查看到。
iTunes 中需要的 Feed 文件格式:
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
<channel>
<title>All About Everything</title>
<link>http://www.example.com/podcasts/everything/index.html</link>
<language>en-us</language>
<copyright>℗ & © 2014 John Doe & Family</copyright>
<itunes:subtitle>A show about everything</itunes:subtitle>
<itunes:author>John Doe</itunes:author>
<itunes:summary>All About Everything is a show about everything. Each week we dive into any subject known to man and talk about it as much as we can. Look for our podcast in the Podcasts app or in the iTunes Store</itunes:summary>
<description>All About Everything is a show about everything. Each week we dive into any subject known to man and talk about it as much as we can. Look for our podcast in the Podcasts app or in the iTunes Store</description>
<itunes:owner>
<itunes:name>John Doe</itunes:name>
<itunes:email>john.doe@example.com</itunes:email>
</itunes:owner>
<itunes:image href="http://example.com/podcasts/everything/AllAboutEverything.jpg"/>
<itunes:category text="Technology">
<itunes:category text="Gadgets"/>
</itunes:category>
<itunes:category text="TV & Film"/>
<itunes:category text="Arts">
<itunes:category text="Food"/>
</itunes:category>
<itunes:explicit>no</itunes:explicit>
<item>
<title>Shake Shake Shake Your Spices</title>
<itunes:author>John Doe</itunes:author>
<itunes:subtitle>A short primer on table spices</itunes:subtitle>
<itunes:summary><![CDATA[This week we talk about <a href="https://itunes/apple.com/us/book/antique-trader-salt-pepper/id429691295?mt=11">salt and pepper shakers</a>, comparing and contrasting pour rates, construction materials, and overall aesthetics. Come and join the party!]] ></itunes:summary>
<itunes:image href="http://example.com/podcasts/everything/AllAboutEverything/Episode1.jpg"/>
<enclosure length="8727310" type="audio/x-m4a" url="http://example.com/podcasts/everything/AllAboutEverythingEpisode3.m4a"/>
<guid>http://example.com/podcasts/archive/aae20140615.m4a</guid>
<pubDate>Tue, 08 Mar 2016 12:00:00 GMT</pubDate>
<itunes:duration>07:04</itunes:duration>
<itunes:explicit>no</itunes:explicit>
</item>
<item>
<title>Socket Wrench Shootout</title>
<itunes:author>Jane Doe</itunes:author>
<itunes:subtitle>Comparing socket wrenches is fun!</itunes:subtitle>
<itunes:summary>This week we talk about metric vs. Old English socket wrenches. Which one is better? Do you really need both? Get all of your answers here.</itunes:summary>
<itunes:image href="http://example.com/podcasts/everything/AllAboutEverything/Episode2.jpg"/>
<enclosure length="5650889" type="video/mp4" url="http://example.com/podcasts/everything/AllAboutEverythingEpisode2.mp4"/>
<guid>http://example.com/podcasts/archive/aae20140608.mp4</guid>
<pubDate>Wed, 09 Mar 2016 13:00:00 EST</pubDate>
<itunes:duration>04:34</itunes:duration>
<itunes:explicit>no</itunes:explicit>
</item>
<item>
<title>The Best Chili</title>
<itunes:author>Jane Doe</itunes:author>
<itunes:subtitle>Jane and Eric</itunes:subtitle>
<itunes:summary>This week we talk about the best Chili in the world. Which chili is better?</itunes:summary>
<itunes:image href="http://example.com/podcasts/everything/AllAboutEverything/Episode3.jpg"/>
<enclosure length="5650889" type="video/x-m4v" url="http://example.com/podcasts/everything/AllAboutEverythingEpisode2.m4v"/>
<guid>http://example.com/podcasts/archive/aae20140697.m4v</guid>
<pubDate>Thu, 10 Mar 2016 02:00:00 -0700</pubDate>
<itunes:duration>04:34</itunes:duration>
<itunes:explicit>no</itunes:explicit>
<itunes:isClosedCaptioned>Yes</itunes:isClosedCaptioned>
</item>
<item>
<title>Red,Whine, & Blue</title>
<itunes:author>Various</itunes:author>
<itunes:subtitle>Red + Blue != Purple</itunes:subtitle>
<itunes:summary>This week we talk about surviving in a Red state if you are a Blue person. Or vice versa.</itunes:summary>
<itunes:image href="http://example.com/podcasts/everything/AllAboutEverything/Episode4.jpg"/>
<enclosure length="498537" type="audio/mpeg" url="http://example.com/podcasts/everything/AllAboutEverythingEpisode4.mp3"/>
<guid>http://example.com/podcasts/archive/aae20140601.mp3</guid>
<pubDate>Fri, 11 Mar 2016 01:15:00 +3000</pubDate>
<itunes:duration>03:59</itunes:duration>
<itunes:explicit>no</itunes:explicit>
</item>
</channel>
</rss>
完整的字段及解释可以参考官方文档,里面有非常详细的字段解释。Play Music 要求的大多数内容和 iTunes 类似,只有一些字段要求有些变化,Google 要求图片为方形,最小为 600*600
,并且建议大小在 1200*1200
到 7000*7000
px 之间,支持 JPEG 和 PNG。
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0" version="2.0">
<channel>
<title>The Unknown Podcast</title>
<link>http://sample.com/podcasts/unknown/index.html</link>
<language>en-us</language>
<copyright>℗ 2025 Unknown Podcaster Corp</copyright>
<googleplay:author>Unannounced Podcaster</googleplay:author>
<googleplay:description>The Unknown Podcast will look at all the things that are unknown or unknowable. Find us on Google Play Music!</googleplay:description>
<description>The Unknown Podcast will look at all the things that are unknown or unknowable.</description>
<googleplay:email>unknown-podcast@sample.com</googleplay:email>
<googleplay:image href="http://sample.com/podcasts/unknown/UnknownLargeImage.jpg" />
<googleplay:category text="Technology"/>
<item>
<title>What's out there?</title>
<googleplay:author>Engima</googleplay:author>
<googleplay:description>We look at all the things that are out there that we'd like to know.</googleplay:description>
<googleplay:image href="http://sample.com/podcasts/unknown/Episode1.jpg" />
<enclosure url="http://sample.com/podcasts/UnknownPodcastEpisode1.mp3" length="2320111" type="audio/mpeg" />
<guid>http://sample.com/podcasts/UnknownPodcastEpisode1.mp3</guid>
<pubDate>Mon, 29 Jun 2015 19:00:00 GMT</pubDate>
</item>
<item>
<title>What can we know, really?</title>
<googleplay:author>The everyman</googleplay:author>
<googleplay:description>And then we follow up on last week's podcast to examine what can and cannot be known.</googleplay:description>
<googleplay:image href="http://sample.com/podcasts/unknown/Episode2.jpg" />
<enclosure url="http://sample.com/podcasts/UnknownPodcastEpisode2.m4a" length="6421543" type="audio/x-m4a" />
<guid>http://sample.com/podcasts/UnknownPodcastEpisode2.m4a</guid>
<pubDate>Mon, 6 Jul 2015 19:00:00 GMT</pubDate>
</item>
</channel>
</rss>
可以向以下两个网址提交申请认证
最后可以从这里访问到网站 https://einverne.github.io/podcast ,网站源代码在 https://github.com/einverne/podcast 。
Demo 的 Play Music 地址在 这里
Some of the Head First learning principles:
To bend your brain into submission
Identify the aspects of your application that vary and separate them from what stays the same.
The what varies and “encapsulate” it so it won’t affect the rest of your code.
Program to an interface really means “Program to a supertype”
开闭原则
Classes should be open for extension, but close for modification.
第一次听到开闭原则的时候可能会有些疑惑,但是这个原则其实是让架构容易扩展的同时不影响到原来的代码。比如观察者模式,我们可以轻松的在不修改被观察者代码的情况下,通过增加观察者来实现对系统的扩展。
开闭原则下的模式:
ssh to xiaomi router
smbpasswd -a root
then enter your password two times.
vi /etc/config/samba
Edit
option 'guest_ok' no
option 'force_user' 'root'
And
vi /var/etc/smb.conf
Edit
guest ok = yes
valid users = root
Then restart samba service:
/etc/init.d/samba restart
Android 对话框
实现对话框通常有三种方式:
以下重点考虑 Dialog 类的使用,其派生子类 DatePickerDialog,TimePickerDialog 以后扩展开讲。响应代码可以参考此次 提交。
AlertDialog
private void showNormalDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Title");
builder.setMessage("your message here.");
builder.setCancelable(true);
/**
* Typically, a dialog is dismissed when its job is finished
* and it is being removed from the screen.
* A dialog is canceled when the user wants to escape the dialog
* and presses the Back button.
* For example, you have a standard Yes/No dialog on the screen.
* If the user clicks No, then the dialog is dismissed
* and the value for No is returned to the caller.
* If instead of choosing Yes or No, the user clicks Back to escape the dialog
* rather than make a choice then the dialog is canceled
* and no value is returned to the caller.
*/
builder.setPositiveButton(
"Yes",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Toast.makeText(DialogTestActivity.this, "Yes", Toast.LENGTH_SHORT).show();
dialog.dismiss();
}
});
builder.setNegativeButton(
"No",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Toast.makeText(DialogTestActivity.this, "No", Toast.LENGTH_SHORT).show();
dialog.dismiss();
}
});
AlertDialog alert = builder.create();
alert.show();
}
private void showThreeOptionsDialog() {
Dialog dialog = new AlertDialog.Builder(this)
.setIcon(android.R.drawable.btn_star)
.setTitle("喜好调查")
.setMessage("你喜欢李连杰的电影吗?")
.setPositiveButton("很喜欢", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(DialogTestActivity.this, "我很喜欢他的电影。",
Toast.LENGTH_LONG).show();
}
})
.setNegativeButton("不喜欢", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(DialogTestActivity.this, "我不喜欢他的电影。", Toast.LENGTH_LONG).show();
}
})
.setNeutralButton("一般", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(DialogTestActivity.this, "谈不上喜欢不喜欢。", Toast.LENGTH_LONG).show();
}
}).create();
dialog.show();
}
private void showInputDialog() {
final EditText editText = new EditText(this);
Dialog dialog = new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_info)
.setTitle("Input your message")
.setView(editText)
.setPositiveButton("Sure", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String inputString = editText.getText().toString();
Toast.makeText(DialogTestActivity.this, inputString, Toast.LENGTH_SHORT).show();
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).create();
dialog.show();
}
private void showSingleChoiceDialog() {
Dialog dialog = new AlertDialog.Builder(this)
.setTitle("Single Choice")
.setSingleChoiceItems(new String[]{"item1", "item2"}, 0, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(DialogTestActivity.this, "" + which, Toast.LENGTH_SHORT).show();
dialog.dismiss();
}
}).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).create();
dialog.show();
}
private void showMultiChoiceDialog() {
Dialog dialog = new AlertDialog.Builder(this)
.setTitle("Multi Choice")
.setMultiChoiceItems(new String[]{"item0", "item1"}, new boolean[]{false, true}, new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
Toast.makeText(DialogTestActivity.this, "" + which + " " + isChecked, Toast.LENGTH_SHORT).show();
}
}).create();
dialog.show();
}
private void showCustomDialog() {
LayoutInflater inflater = getLayoutInflater();
View layout = inflater.inflate(R.layout.dialog_custom, null);
final EditText editText = (EditText) layout.findViewById(R.id.editText);
Dialog dialog = new AlertDialog.Builder(this)
.setTitle("Custom")
.setView(layout)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(DialogTestActivity.this, editText.getText().toString() + " ", Toast.LENGTH_SHORT).show();
}
}).create();
dialog.show();
}
可以在 build.gradle
文件中指定debug 下的 keystore 文件路径,一般放到项目跟目录下,并使用如下方式指定。 更多语法可以参考 Signing Configurations 部分 http://tools.android.com/tech-docs/new-build-system/user-guide
指定 debug variant 下 keystore 路径:
android {
signingConfigs {
debug {
storeFile file('your.keystore')
keyAlias 'androiddebugkey'
keyPassword 'android'
storePassword 'android'
}
}
}
推荐还是讲 debug 和 release 下的 keystore 分开。
查询 keystore 中条目
keytool -list -keystore your.keystore -storepass yourpassword
修改 keystore 中,使用上一步获取到的证书名字
keytool -changealias -alias 证书名字 -destalias androiddebugkey -keystore your.keystore -storepass yourpassword
修改密钥库密码
keytool -storepasswd -keystore your.keystore -storepass yourpassword
修改证书密码
keytool -keypasswd -alias androiddebugkey -keystore 证书名字 -storepass yourpassword
以前写过一篇文章 讲的是如何在 Linux 下使用 byzanz 来录制 GIF,并且能够达到很好的效果,并且文件大小非常合适网络分享。现在就介绍下在其他两大平台 Win/Mac 下录制 GIF 的工具。
录屏 GIF 工具名字叫做: LICEcap 。这也是一款我在使用很长时间之后感觉非常好用的工具。他的官网地址:
http://www.cockos.com/licecap/
他有如下优点:
更多其他的技巧和优点可查看他官网,目前为止他满足了我所有的需求。
使用:
输出文件:
在寻找的过程中还发现一款比较好用的工具,但只有在 Windows 平台上存在,这里也写上吧。
官方地址:https://screentogif.codeplex.com/
更多的介绍和使用说明可上官网查看。
在 Instagram 关闭 API 之前可以通过 IFTTT 获取别人的更新 Photos, 但是 Instagram 收紧了 API 政策。既拿不到别人更新的信息流,同样也自己Like 别人照片的信息也拿不到了,原来 IFTTT 有两个 Recipes:
然而这两个 Recipes 都被 IFTTT 删去了,我甚至在 StackOverflow 上问过这件事情,只是几个月过去了,也没有任何实质性的方案。
直到这些天,突然脑袋一道闪光,再此之前,我了解了方法可以导出 Instagram 到 RSS,然后看到了别人自动将 Imgur 中的图片上传到 Google Drive ,使用的是 RSS 导出图片,有人写了一脚本传入 URL,就可以提取 URL 中的图片链接。
正是基于这两个方案,我想到了使用 Instagram to RSS to IFTTT to Google Drive 的方案,然后经过尝试,不需要一行代码的情况下,我实现了自动转存的方案。省去了自己写脚本的时间,同样这个方案也自动适配的Instagram 的网页,并不会因为网页结构的变化而导致失败。只要 RSS 有效,那么就会一直生效。
要做到这个事情,就需要借助 RSS bridge 这个项目,这个项目也是当时我在寻找 InoReader RSS 的时候发现的,关于导出微博、知乎、微信的订阅到 RSS 可以以后在展开详谈。回到 RSS bridge ,这个项目本身就是利用爬虫将网站更新内容生成 RSS,本身支持的网站还是很多的,Flickr、GooglePlus、Twitter、Youtube、Pinterest 等等,当然包括 Instagram。
而我使用了 https://bridge.suumitsu.eu/ 这个网站提供的服务,这个网站架设了 RSS bridge 的服务,当然如果有条件的话自己架设也是很不错的选择,只要一直维护就可以。在网页上选择 Instagram 然后填入 Instagram 的用户 ID ,然后获取 Atom 的源即可。拿到这个 Feed URL,在下一步使用。
拿到 Feed URL 之后,到 IFTTT,使用 这个 新建一个 Recipe
分析一下刚刚拿到的 URL
https://bridge.suumitsu.eu/?action=display&bridge=Instagram&u=instagram&format=Atom
其中 u 参数后面跟随着的就是 Instagram 的用户 ID,改变 u 后面的参数为需要自动保存的 ID,然后 Save 即可。
INSTALL_FAILED_NO_MATCHING_ABIS
的解决办法,在 Android 模拟器上安装 apk 的时候出现
是由于使用了 native libraries ,该 native libraries 不支持当前的cpu的体系结构。
INSTALL_FAILED_NO_MATCHING_ABIS is when you are trying to install an app that has native libraries and it doesn't have a native library for your cpu architecture. For example if you compiled an app for armv7 and are trying to install it on an emulator that uses the Intel architecture instead it will not work.
现在安卓模拟器的CPU/ABI一般有三种类型,INTEL X86,ARM,MIPS,
如果选择用INTEL X86出现 INSTALL_FAILED_NO_MATCHING_ABIS
的错误,那就改用ARM的
参考:http://stackoverflow.com/questions/24572052/install-failed-no-matching-abis-when-install-apk
Android 6.0 中移除 了 Apache HTTP client
程序包org.apache.http.client.methods不存在
android {
useLibrary 'org.apache.http.legacy'
}