随笔 - 33, 文章 - 0, 评论 - 12, 引用 - 0
数据加载中……

2012年3月23日

Activity四种启动模式

Activity启动方式有四种,分别是:

standard
singleTop
singleTask
singleInstance

可以根据实际的需求为Activity设置对应的启动模式,从而可以避免创建大量重复的Activity等问题。

设置Activity的启动模式,只需要在AndroidManifest.xml里对应的<activity>标签设置android:launchMode属性,例如:

  1. <activity  
  2.     android:name=".A1"  
  3.     android:launchMode="standard" />  

下面是这四种模式的作用:

standard
默认模式,可以不用写配置。在这个模式下,都会默认创建一个新的实例。因此,在这种模式下,可以有多个相同的实例,也允许多个相同Activity叠加。

例如:
若我有一个Activity名为A1, 上面有一个按钮可跳转到A1。那么如果我点击按钮,便会新启一个Activity A1叠在刚才的A1之上,再点击,又会再新启一个在它之上……
点back键会依照栈顺序依次退出。

singleTop
可以有多个实例,但是不允许多个相同Activity叠加。即,如果Activity在栈顶的时候,启动相同的Activity,不会创建新的实例,而会调用其onNewIntent方法。

例如:
若我有两个Activity名为B1,B2,两个Activity内容功能完全相同,都有两个按钮可以跳到B1或者B2,唯一不同的是B1为standard,B2为singleTop。
若我意图打开的顺序为B1->B2->B2,则实际打开的顺序为B1->B2(后一次意图打开B2,实际只调用了前一个的onNewIntent方法)
若我意图打开的顺序为B1->B2->B1->B2,则实际打开的顺序与意图的一致,为B1->B2->B1->B2。


singleTask
只有一个实例。在同一个应用程序中启动他的时候,若Activity不存在,则会在当前task创建一个新的实例,若存在,则会把task中在其之上的其它Activity destory掉并调用它的onNewIntent方法。
如果是在别的应用程序中启动它,则会新建一个task,并在该task中启动这个Activity,singleTask允许别的Activity与其在一个task中共存,也就是说,如果我在这个singleTask的实例中再打开新的Activity,这个新的Activity还是会在singleTask的实例的task中。

例如:
若我的应用程序中有三个Activity,C1,C2,C3,三个Activity可互相启动,其中C2为singleTask模式,那么,无论我在这个程序中如何点击启动,如:C1->C2->C3->C2->C3->C1-C2,C1,C3可能存在多个实例,但是C2只会存在一个,并且这三个Activity都在同一个task里面。
但是C1->C2->C3->C2->C3->C1-C2,这样的操作过程实际应该是如下这样的,因为singleTask会把task中在其之上的其它Activity destory掉。
操作:C1->C2          C1->C2->C3          C1->C2->C3->C2            C1->C2->C3->C2->C3->C1             C1->C2->C3->C2->C3->C1-C2
实际:C1->C2          C1->C2->C3          C1->C2                              C1->C2->C3->C1                               C1->C2

若是别的应用程序打开C2,则会新启一个task。
如别的应用Other中有一个activity,taskId为200,从它打开C2,则C2的taskIdI不会为200,例如C2的taskId为201,那么再从C2打开C1、C3,则C2、C3的taskId仍为201。
注意:如果此时你点击home,然后再打开Other,发现这时显示的肯定会是Other应用中的内容,而不会是我们应用中的C1 C2 C3中的其中一个。


singleInstance
只有一个实例,并且这个实例独立运行在一个task中,这个task只有这个实例,不允许有别的Activity存在。

例如:
程序有三个ActivityD1,D2,D3,三个Activity可互相启动,其中D2为singleInstance模式。那么程序从D1开始运行,假设D1的taskId为200,那么从D1启动D2时,D2会新启动一个task,即D2与D1不在一个task中运行。假设D2的taskId为201,再从D2启动D3时,D3的taskId为200,也就是说它被压到了D1启动的任务栈中。

若是在别的应用程序打开D2,假设Other的taskId为200,打开D2,D2会新建一个task运行,假设它的taskId为201,那么如果这时再从D2启动D1或者D3,则又会再创建一个task,因此,若操作步骤为other->D2->D1,这过程就涉及到了3个task了。

posted @ 2015-06-23 11:04 建华 阅读(254) | 评论 (0)编辑 收藏

蓝牙发送文件

系统4.0.3以后的
      File file=new File("");
 Uri uri1 = Uri.fromFile(file);
 Intent intent = new Intent();    
intent.setAction(Intent.ACTION_SEND);   
 //intent.setType("audio/*"); 
  intent.setType("application/octet-stream");
ComponentName comp=new ComponentName("com.mediatek.bluetooth","com.mediatek.bluetooth.BluetoothShareGatewayActivity");
intent.setComponent(comp);
 intent.putExtra(Intent.EXTRA_STREAM, uri1);
startActivity(intent);
系统4.0.3以前的
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
//这个类型函数是自己工具类的方法,你可以自己设置文件类型,例如图片文件:image/*  
  //不想写类型直接*/*也是可以的
intent.setType("audio/*");
//这里setClassName就是指定蓝牙,不写这句就弹出选择用什么发送
  //有蓝牙啊,gmail啊,彩信之类的
intent.setClassName("com.android.bluetooth" , "com.android.bluetooth.opp.BluetoothOppLauncherActivity");
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File("")));
startActivity(intent);


  ArrayList<Uri> uris = new ArrayList<Uri>();
   uris.add(Uri.fromFile(new File("/sdcard/111.txt")));
   uris.add(Uri.fromFile(new File("/sdcard/222.txt")));
   
               Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND_MULTIPLE);
intent.setType("video/*");
intent.setClassName("com.android.bluetooth" , "com.android.bluetooth.opp.BluetoothOppLauncherActivity");
//intent.setClassName("com.mediatek.bluetooth","com.mediatek.bluetooth.BluetoothShareGatewayActivity");
//intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File("/sdcard/111.txt")) );
//intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File("/sdcard/222.txt")));
intent.putExtra(Intent.EXTRA_STREAM, uris);
startActivity(intent);

posted @ 2013-02-20 08:45 建华 阅读(647) | 评论 (0)编辑 收藏

Android中关于dip和px以及转换的总结

我们在页面布局的时候,经常会设置容器的长度,但是到底该使用哪个作为长度的单位而懊恼。在Android中支持的描述大小区域的类型有以下几种:

px(pixels)——像素:不同的设备显示效果相同,一般我们HVGA代表320x480像素,这个用的比较多。

dip(device independent pixels)——设备独立像素:这个和设备硬件有关,一般我们为了支持WCGA、HVGA和QVGA推荐使用这个,不依赖于像素。等同于dp。

sp(scaled pixels—best for text size)——带比例的像素。

pt(points)——磅:1pt = 1/72英寸

in(inches)——英寸

mm(millimeters)——毫米

到底px和dip有什么区别呢?

dip != px

主要是针对不同设备而言的。在Density是160的设备上,比如用AVDManager创建的默认模拟器,dip和px是一样的但是如果同样的代码,换到不同Density的设备上,比如换到一个Density是240的设备上,dip和px体现出来的大小就不一样了。px不管在什么样的设备上都是那样长,但是dip会根据设备变化;WQVGA屏density=120;QVGA屏density=120;HVGA屏density=160;WVGA屏density=240;density值表示每英寸有多少个显示点,与分辨率是两个概念。

当屏幕density=240时使用hdpi标签的资源
当屏幕density=160时,使用mdpi标签的资源
当屏幕density=120时,使用ldpi标签的资源。

不加任何标签的资源是各种分辨率情况下共用的。布局时尽量使用单位dip,少使用px。

换算公式为:
pixs =dips * (densityDpi/160). 
dips=(pixs*160)/densityDpi

如何获得设备的屏幕分辨率和屏幕密度?
例如分辨率为480*800,密度为240的设备,方法如下


DisplayMetrics dm =getResources().getDisplayMetrics();
dm.densityDpi=240
dm.widthPixels=480
dm.heightPixels=800

posted @ 2013-02-01 10:08 建华 阅读(4992) | 评论 (2)编辑 收藏

在android模拟器中永久删除自带应用程序

首先启动android模拟器。
打开cmd命令行窗口。输入adb -s emulator-5554 shell
此时可以管理系统文件夹了,再输入ls
可以看到列出了文件夹和文件,输入cd system/app再输入ls
可以看到系统自带的应用程序apk文件,删除你想要删除的,例如Phone.apk,输入rm Phone.apk
此时会看到提示说rm failed for Phone.apk, Read-only file system那是因为这些是只读文件,我们没有权限删除它。所以接下来要做的是获取权限,首先查看权限,输入mount
可以看到/dev/block/mtdblock0 /system yaffs2 ro 0 0说明在system这个地方我们没有权限那么接下来我们就来获取权限,输入mount -o remount,rw -t yaffs2 /dev/block/mtdblock0 /system
没有提示错误,再次查看权限,输入mount
可以看到/dev/block/mtdblock0 /system yaffs2 rw 0 0
说明我们已经获取到权限了此时再输入rm Phone.apk就可以成功删除了

最后一点,就算你成功删除了,android模拟器每次启动时也会恢复回来。
那么如何永久删除呢,很简单,删除SdkSetup.apk,输入rm SdkSetup.apk
还没完,找到avd目录(一般在我的文档),进入xxxx.avd目录,删除cache.img和userdata-qemu.img
还有还有,找到%SDK_HOME%/platforms/android-X/images/system.img,复制到上面的目录中。
最后最后,再重启模拟器,大功告成!

posted @ 2012-12-26 18:17 建华 阅读(749) | 评论 (0)编辑 收藏

surfaceView 与View 的区别

如果你的游戏不吃CPU,用View就比较好,符合标准Android操作方式,由系统决定刷新surface的时机。

  但如果很不幸的,你做不到不让你的程序吃CPU,你就只好使用SurfaceView来强制刷新surface了,不然系统的UI进程很可能抢不过你那些吃CPU的线程。

  当然其实不止这两种方法来刷新Surface的,这两种只是纯Java应用比较常见的方法。

  SurfaceView和View最本质的区别在于,surfaceView是在一个新起的单独线程中可以重新绘制画面而View必须在UI的主线程中更新画面。

  那么在UI的主线程中更新画面 可能会引发问题,比如你更新画面的时间过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应按键,触屏等消息。

   当使用surfaceView 由于是在新的线程中更新画面所以不会阻塞你的UI主线程。但这也带来了另外一个问题,就是事件同步。比如你触屏了一下,你需要surfaceView中 thread处理,一般就需要有一个event queue的设计来保存touch event,这会稍稍复杂一点,因为涉及到线程同步。

  所以基于以上,根据游戏特点,一般分成两类。

  1 被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 因为这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。

  2 主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main UI thread。所以显然view不合适,需要surfaceView来控制。

posted @ 2012-03-23 16:33 建华 阅读(254) | 评论 (0)编辑 收藏