Android应用开发常用知识(4)

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或者activityandroid: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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寒江蓑笠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值