Android string 中product的使用
Android的资源文件string.xml会出现下面同名的字符串:
<string name="build_type" product="tv">"智能电视"</string>
<string name="build_type" product="tablet">"平板电脑"</string>
<string name="build_type" product="default">"智能手机"</string>
不同的product就会取不同的值。
注意不要把default放在第一个,否则会编译不过。
product的值在对应的device目录下的mk文件当中有定义:
PRODUCT_CHARACTERISTICS := tv
Android 横屏解锁引起Activity销毁重建
Activity设置为竖屏
android:screenOrientation="portrait"
桌面是可以横竖屏切换的,竖屏锁屏,横屏下解锁会引起Activity销毁,这个时候也要设置一下
android:configChanges="screenSize|keyboardHidden|orientation"
解决重复点击问题
private long mLashClick;
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
long now = SystemClock.uptimeMillis();
if(now - mLashClick > 500){
mLashClick = now;
//do something;
}
}
});
自定义Toolbar style解决Toolbar位置问题
<style name="AppTheme">
……
<item name="toolbarStyle">@style/MyToolbarStyle</item>
……
</style>
<style name="MyToolbarStyle" parent="Widget.AppCompat.Toolbar">
<item name="contentInsetStart">@dimen/toolbar_content_inset</item>
<item name="contentInsetEnd">@dimen/toolbar_content_inset</item>
</style>
Activity实现180旋转
android:screenOrientation="fullUser"
Android:includeFontPadding
TextView中用来设置文本框是否包含顶部和底部留白(左右两侧默认没有留白),将其设置为false,TextView就会取消2px的留白
Fragment切换时使用不同的OptionsMenu
在onCreate中
调用setHasOptionsMenu(true);
,在每个Fragment中
重写public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
来实现;
LinearLayout添加分隔线
可以放置一个ImageView组件,然后将其设为分隔线的颜色或图形。
android:showDividers
在 Android3.0及以上版本,LinearLayout支持直接显示分隔线。设置标签的 android:showDividers属性可以在LinearLayout的相应位置显示分隔线。如果有多个LinearLayout,显示效果和在 LinearLayout之间加分隔线是一样的。
android:showDividers属性可以设置如下4个值:
- none:不显示分隔线;
- beginning:在LinearLayout的开始处显示分隔线;
- end:在Linearlayout的结尾处显示分隔线;
- middle:在LinearLayout中的每两个组件间显示分隔线:
除了需要设置android:showDividers属性外,还要设置android:divider属性,该属性表示分隔线的图像,需要一个Drawable ID。
添加快捷方式
public void addShortCut(){
Intent addShortCut = new Intent("com.android.launcher.action.INSTALL_SHORTCUT");
//快捷方式的名称
addShortCut.putExtra(Intent.EXTRA_SHORTCUT_NAME, "Test");
// 不允许重复创建
addShortCut.putExtra("duplicate", false);
addShortCut.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(MainActivity.this,
R.mipmap.ic_launcher));
// 设置关联程序
//启动MainActivity
//设置action.MAIN和CATEGORY_LAUNCHER可以在卸载应用的时候同时删除桌面快捷方式
// Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
// launcherIntent.setClass(MainActivity.this, MainActivity.class);
// launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
//打开网页
Intent launcherIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.baidu.com"));
addShortCut.putExtra(Intent.EXTRA_SHORTCUT_INTENT, launcherIntent);
sendBroadcast(addShortCut);
}
删除快捷方式
private void removeShortcut() {
Intent intent = new Intent("com.android.launcher.action.UNINSTALL_SHORTCUT");
// 名字
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "Test");
// 设置关联程序
Intent launcherIntent = new Intent(MainActivity.this,
MainActivity.class).setAction(Intent.ACTION_MAIN);
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, launcherIntent);
sendBroadcast(intent);
}
onNewIntent的调用时机以及于四种启动模式的关系
使用setTouchDelegate来扩大View的触摸范围
升级系统app后重启系统,app未升级
我们平时开发过程中可能遇到这样的问题:安装更新系统app后,重新开机启动,发现更新没有了,app有变成原来的样子,结果的办法是升级一下版本号就可以了,不知道原生逻辑是不是这样子的,有时间研究一下。
FLAG_SHOW_WHEN_LOCKED
使得应用程序窗口优先于锁屏界面,当屏幕锁定时,窗口可以被看到。
final Window win = activity.getWindow();
final WindowManager.LayoutParams params = win.getAttributes();
params.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
去除Activity的各种切换动画
<style name="notAnimation">
<item name="android:activityOpenEnterAnimation">@null</item>
<item name="android:activityOpenExitAnimation">@null</item>
<item name="android:activityCloseEnterAnimation">@null</item>
<item name="android:activityCloseExitAnimation">@null</item>
<item name="android:taskOpenEnterAnimation">@null</item>
<item name="android:taskOpenExitAnimation">@null</item>
<item name="android:taskCloseEnterAnimation">@null</item>
<item name="android:taskCloseExitAnimation">@null</item>
<item name="android:taskToFrontEnterAnimation">@null</item>
<item name="android:taskToFrontExitAnimation">@null</item>
<item name="android:taskToBackEnterAnimation">@null</item>
<item name="android:taskToBackExitAnimation">@null</item>
</style>
打印当前堆栈
new Throwable().printStackTrace();
延迟执行某个动作到给定条件发生时执行
方法一:http://blog.csdn.net/heqiangflytosky/article/details/49660617
方法二:可以先判断当前条件是否满足,如果不满足,就把要执行的代码放入到一个列表中,当条件满足是判断该列表是否有需要执行的代码,如过有的话就执行。
下面的例子是将代码的执行放到onRusume调用后再执行:
private ArrayList<Runnable> mBindOnResumeCallbacks = new ArrayList<Runnable>();
private void doSomeThing(){
Runnable r = new Runnable() {
public void run() {
doSomeThing();
}
};
if (waitUntilResume(r)) {
return;
}
……
}
private boolean waitUntilResume(Runnable run) {
return waitUntilResume(run, false);
}
private boolean waitUntilResume(Runnable run, boolean deletePreviousRunnables) {
if (mPaused) {
Log.i(TAG, "Deferring update until onResume");
if (deletePreviousRunnables) {
while (mBindOnResumeCallbacks.remove(run)) {
}
}
mBindOnResumeCallbacks.add(run);
return true;
} else {
return false;
}
}
@Override
protected void onResume() {
mPaused = false;
if (mBindOnResumeCallbacks.size() > 0) {
for (int i = 0; i < mBindOnResumeCallbacks.size(); i++) {
mBindOnResumeCallbacks.get(i).run();
}
}
}
Intent.getSourceBounds()
通过Intent.getSourceBounds()方法可以获取到Shortcut在Launcher中的坐标信息。
在onCreate()里面获取view的width和height
在onCreate()获取view的width和height会得到0.view.getWidth()和view.getHeight()为0的根本原因是控件还没有完成绘制,你必须等待系统将绘制完View时,才能获得。下面有一些可行的解决方案。
- 监听Draw/Layout事件:ViewTreeObserver
ViewTreeObserver监听很多不同的界面绘制事件。一般来说OnGlobalLayoutListener就是可以让我们获得到view的width和height的地方。下面onGlobalLayout内的代码会在View完成Layout过程后调用。
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int height = view.getHeight();
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
但是要注意这个方法在每次有些view的Layout发生变化的时候被调用(比如某个View被设置为Invisible),所以在得到你想要的宽高后,记得移除 onGlobleLayoutListener
。
- View.post()
UI事件队列会按顺序处理事件。在setContentView()被调用后,事件队列中会包含一个要求重新layout的message,所以任何你post到队列中的东西都会在Layout发生变化后执行。
view.post(new Runnable() {
@Override
public void run() {
int height = view.getHeight();
}
});
-
重写View的onLayout方法
在onLayout()里面获取,需要注意的是onLayout()方法会调用很多次。 -
另外可以在
Activity.onPostCreate()
方法中获取,这个是Activity
彻底运行起来之后的回调方法。
Android intent-filter匹配自定义后缀文件
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:host="*" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*\\.test" />
</intent-filter>
这里 pathPattern 里面的“.” 用来匹配任意字符,“.*” 就是用来匹配任意字符0次或更多,“\”是用来转义用的,之所以有两个是因为这里需要两次转义,读取 Xml 时转义一次,在 pathPattern 中使用又转义一次。
android:manageSpaceActivity
如果你想在应用管理中自定义应用数据管理,这个属性会帮助到你。设置这个属性会在设置的应用管理界面中出现一个空间管理按钮,点击之后进入你自定义的空间管理界面。
android:process
在 manifest 中设置application
或者activity
的android:process
可以让应用或者组件运行在我们制定的进程中去。通过这个属性也可以让多个应用运行在同一个进程中,但前提条件是两个APP具有想同的user ID并且被同一个私钥签名。
编译Release版报错
遇到这种问题,在编译debug版本是好的,编译release版本是报错:
Warning: there were 664 unresolved references to classes or interfaces.
You may need to add missing library jars or update their versions.
If your code works fine without the missing classes, you can suppress
the warnings with '-dontwarn' options.
(http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedclass)
Warning: there were 2 unresolved references to library class members.
You probably need to update the library versions.
(http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedlibraryclassmember)
Warning: Exception while processing task java.io.IOException: Please correct the above warnings first.
:app:transformClassesAndResourcesWithProguardForRelease FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:transformClassesAndResourcesWithProguardForRelease'.
> Job failed, see logs for details
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
一般是混淆的问题,如果遇到上面这种错误,可以在 proguard-rules.pro 中加入 -ignorewarnings
。
使用 ids.xml
我们给一个 View
设置 id,最常用的方法就是在布局文件中使用 @+id/
来设置,但我们经常遇到这种使用场景,代码中动态地添加 View
,我们又想给它设置一个id,怎么办呢?
通常我们可以在 values 目录下面创建一个 ids.xml 资源文件,在里面列出 id 的名称:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="id" name="custom_view" />
<item type="id" name="root_view" />
<item type="string" name="str_test" />
</resources>
ids.xml 资源文件为应用的相关资源提供唯一的资源id,然后在代码中就可以引用了:
import com.X.X.R;
view.setId(R.id.root_view);
...
if (getId() == R.id.root_view)
...
另外,若在 ids.xml 中定义了ID,则在 layout 中可如下定义 @id/custom_view
,否则@+id/custom_view
。
使用HandlerThread创建常驻子线程
private HandlerThread mUpdateStatusThread;
{
mUpdateStatusThread = new HandlerThread("update_download_status_thread");
mUpdateStatusThread.start();
mUpdateStatusHandler = new UpdateStatusHandler(mUpdateStatusThread.getLooper(), this);
}
{
mUpdateStatusHandler.removeCallbacksAndMessages(null);
mUpdateStatusThread.quitSafely();
}
{
mUpdateStatusHandler.obtainMessage(UpdateStatusHandler.MSG_UPDATE_PROGRESS, downloadId)
.sendToTarget();
}
private static class UpdateStatusHandler extends Handler {
static final int MSG_UPDATE_PROGRESS = 0;
private WeakReference<DownloadObserver> mWeakReference;
UpdateStatusHandler(Looper looper) {
super(looper);
mWeakReference = new WeakReference<>(downloadObserver);
}
@Override
public void handleMessage(Message msg) {
....
switch (msg.what) {
case MSG_UPDATE_PROGRESS:
......
break;
}
}
}
解决点击 PopupWindow和ListPopupWindow外部区域底层View响应的问题
如果是 PopupWindow
可以通过 setFocusable(true)
来解决。
如果是 ListPopupWindow
则要通过反射解决:
try {
Field popField = listPopupWindow.getClass().getDeclaredField("mPopup");
popField.setAccessible(true);
PopupWindow pop = (PopupWindow) popField.get(listPopupWindow);
pop.setFocusable(true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
水平线性布局下,如何最左或者最右
如果用RelativeLayout就比较好解决,如果用LinearLayout可以使用多放置一个透明的空间,设置为透明,并把 android:layout_weight
设置为1,这样就可以把其他组件挤到左边或右边或者两边。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"/>
<View
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginTop="40dp"
android:layout_marginRight="10dp"/>
<View
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginTop="40dp"
android:layout_marginEnd="10dp"/>
</LinearLayout>
设置透明背景
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>
设置沉浸模式,隐藏状态栏
<item name="android:windowTranslucentStatus">true</item>