虽然文档里没有明确说明,但假如这是常用功能,应该有简便的方法实现,而实际上要靠代码"退出"一个应用并非易事。以下总结了能够模拟退出效果的两个方案:
方案1:打开系统主屏来模拟应用退出的效果,这和用户按Home键没有什么区别。
代码如下 | 复制代码 |
Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); |
方案2:直接杀掉当前应用进程。这个方法太暴力了,我找到一段iOS开发文档,上面强烈不建议使用杀进程的方式来退出应用,原因也适用于Android系统:这样退出的效果容易让用户以为应用崩溃了。
代码如下 | 复制代码 |
int pid=android.os.Process.myPid(); android.os.Process.killProcess(pid); |
此外,有人建议调用System.exit(0)退出应用,实际测试发现这个方法常常只能关闭当前Activity,或是根本不起作用。
由此可以看出,Android系统的设计里本来就没有"退出应用"的机制,当用户按下Home键或在应用首页里按下Back键后,应用被置于后台,而何时要彻底杀掉应用进程则由系统决定。Android和iOS都已抛弃了"退出应用"这个概念,对手机用户来讲,他只需要知道"启动应用"——概念越少越简单。
但作为一个好的应用,应该有自己的退出功能。
"应用退出"一般有以下几种方式:
一、退出起始的Activity,这样后面的Activity系统会自己destory。(通常需要很长时间)
二、为每一个Activity覆写OnKeyDown()方法,当每次按返回键的时候,finish掉当前的Activity。(通常所有的Activity都会继承一个BaseActivity,这样,只需要写一遍就好)
三、利用List,每次调用新的Activity时,保存当前的Activity,当应用退出时,一次性finish所有的Activity。(较为理想的解决方案)
今天,我们就利用第三种方式来为我们的应用添加"退出"功能。
1.编写一个class继承Application
代码如下 | 复制代码 |
public class AppClose extends Application {
private List<Activity> mainActivity = new ArrayList<Activity>(); public List<Activity> MainActivity() { return mainActivity; } public void addActivity(Activity act) { mainActivity.add(act); } public void finishAll() { for (Activity act : mainActivity) { if (!act.isFinishing()) { act.finish(); } } mainActivity = null; } } |
2.在Activity 中的oncreate方法中添加
代码如下 | 复制代码 |
AppClose appState = (AppClose)this.getApplication(); appState.addActivity(this); // setContentView(R.layout.main); |
3.//设定点击事件
代码如下 | 复制代码 |
button.setonclick….(){
AppClose appState = (AppClose)getApplicationContext(); appState.finishAll(); }
|
4.在注册清单文件中
给application添加属性 android:name=".AppClose"
昨天在做一个安卓小应用程序,要实现调用系统相机程序实现拍照,然后把拍的照片返回给我的程序进行剪辑功能,我们主要是用到了Camera类,下面我总结了一些操作方法,下面分享给大家。
调用系统照相机拍照并剪辑
在Android开发过程中,很多时候我们都需要调用照相机拍照,尤其在发布微博的时候。
自己继承Camera类写一个拍照功能显然不是最好的方案,因为我们不能考虑的非常全面。
这个时候,调用系统的照相机无疑是一个很好的解决方法。
下面,我们就写一个调用系统照相机拍照并对照片进行剪辑。
代码如下 | 复制代码 |
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment.getExternalStorageDirectory()+"/","temp.jpg"))); startActivityForResult(intent, 1); |
上面的代码就是调用系统照相机拍照,并保存到sdcard目录下temp.jpg
但这个时候还不够,因为通常情况,照相机拍的照片尺寸都很大,显然不能用于上传,我们需要对照片进行剪辑。
代码如下 | 复制代码 |
public void startPhotoZoom(Uri uri) { Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri, IMAGE_UNSPECIFIED); intent.putExtra("crop", "true"); // aspectX aspectY 是宽高的比例 intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); // outputX, outputY 是裁剪图片宽高 intent.putExtra("outputX", 250); intent.putExtra("outputY", 250); intent.putExtra("return-data", true); startActivityForResult(intent, PHOTORESOULT); }
|
上面的代码实现了图片的剪辑,我们只需要传入相应的Uri即可,接下来我们传入Uri。
代码如下 | 复制代码 |
File picture = new File(Environment.getExternalStorageDirectory()+"/" + "temp.jpg"); startPhotoZoom(Uri.fromFile(picture)); |
当然,剪辑完了,我们肯定要拿到剪辑后的照片。
代码如下 | 复制代码 |
if (requestCode == PHOTORESOULT) { Bundle extras = data.getExtras(); if (extras != null) { Bitmap photo = extras.getParcelable("data"); ByteArrayOutputStream stream = new ByteArrayOutputStream(); if(photo!=null){ photo.compress(Bitmap.CompressFormat.JPEG, 75, stream);// (0 – 100)压缩文件 pic.setImageBitmap(photo); } } }
|
android调用系统照相机拍照并剪辑
这样,我们就通过调用系统照相机,实现拍照并剪辑图片的功能。
1.调用系统的照相机程序
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, TAKE_PHOTO_WITH_DATA);
2.在onActivityResult中处理返回的data
final Bitmap photo = data.getParcelableExtra("data");
如果不需要做剪切处理就可以直接使用图片了,比如输出到ImageView上
imageView.setImageBitmap(photo);
如果需要做剪切处理,就继续向下执行
3.做剪切处理
代码如下 | 复制代码 |
Intent intent = new Intent("com.android.camera.action.CROP"); intent.setType("image/*"); intent.putExtra("data", data); intent.putExtra("crop", "true"); intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); intent.putExtra("outputX", 128); intent.putExtra("outputY", 128); intent.putExtra("return-data", true); startActivityForResult(intent, PHOTO_PICKED_WITH_DATA); |
4.在onActivityResult中处理
与第二步相同。
完整代码:
代码如下 | 复制代码 |
public class SdCardUriTestActivity extends Activity { 布局文件略 |
实例
代码如下 | 复制代码 |
public String getLocalIpAddress() { public String getLocalMacAddress(Context context) { |
安卓4.0系统的手机,按上面的方法默认会先获取到ipv6的地址,有时候我们只想要ipv4的地址
代码如下 | 复制代码 |
/** * 用来获取手机拨号上网(包括CTWAP和CTNET)时由PDSN分配给手机终端的源IP地址。 * * @return * @author SHANHY */ public static String getPsdnIp() { try { for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) { NetworkInterface intf = en.nextElement(); for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) { InetAddress inetAddress = enumIpAddr.nextElement(); if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) { //if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet6Address) { return inetAddress.getHostAddress().toString(); } } } } catch (Exception e) { } return ""; } |
1.消息推送机制
服务器器端需要变被动为主动,通知客户一些开发商认为重要的信息,无论应用程序是否正在运行或者关闭。
我想到了一句话:don't call me,i will call you!
qq今天在右下角弹出了一个对话框:"奥巴马宣布本拉登挂了…",正是如此。
自作聪明,就会带点小聪明,有人喜欢就有人讨厌。
2.独立进程
无论程序是否正在运行,我们都要能通知到客户,我们需要一个独立进程的后台服务。
我们需要一个独立进程的后台服务。
在androidmanifest.xml中注册service时,有一个android:process属性,如果这个属性以"."开头,则为此服务开启一个
全局的独立进程,如果以":"开头则为此服务开启一个为此应用私有的独立进程。举个具体的例子吧,我们新建了一个
application,创建了主进程com.cnblogs.tianxia,那么:
代码如下:
<!–下面会创建一个全局的com.cnblogs.tianxia.message的独立进程–>
<service android:name=".service.messageservice" android:label="消息推送" android:process=".message" />
<!–或者–>
<!–下面会创建一个应用私有的com.cnblogs.tianxia:message的独立进程–>
<service android:name=".service.messageservice" android:label="消息推送" android:process=":message" />
我们没必要建立一个全局的,本文选择第二种方案,创建一个当前应用私有的独立进程。
3.通知用户和点击查看
public class messageservice extends service {
//获取消息线程
private messagethread messagethread = null;
//点击查看
private intent messageintent = null;
private pendingintent messagependingintent = null;
//通知栏消息
private int messagenotificationid = 1000;
private notification messagenotification = null;
private notificationmanager messagenotificatiomanager = null;
public ibinder onbind(intent intent) {
return null;
}
@override
public int onstartcommand(intent intent, int flags, int startid) {
//初始化
messagenotification = new notification();
messagenotification.icon = r.drawable.icon;
messagenotification.tickertext = "新消息";
messagenotification.defaults = notification.default_sound;
messagenotificatiomanager = (notificationmanager)getsystemservice(context.notification_service);
messageintent = new intent(this, messageactivity.class);
messagependingintent = pendingintent.getactivity(this,0,messageintent,0);
//开启线程
messagethread = new messagethread();
messagethread.isrunning = true;
messagethread.start();
return super.onstartcommand(intent, flags, startid);
}
/**
* 从服务器端获取消息
*
*/
class messagethread extends thread{
//运行状态,www.3ppt.com下一步骤有大用
public boolean isrunning = true;
public void run() {
while(isrunning){
try {
//休息10分钟
thread.sleep(600000);
//获取服务器消息
string servermessage = getservermessage();
if(servermessage!=null&&!"".equals(servermessage)){
//更新通知栏
messagenotification.setlatesteventinfo(messageservice.this,"新消息","奥巴马宣布,本拉
登兄弟挂了!"+servermessage,messagependingintent);
messagenotificatiomanager.notify(messagenotificationid, messagenotification);
//每次通知完,通知id递增一下,避免消息覆盖掉
messagenotificationid++;
}
} catch (interruptedexception e) {
e.printstacktrace();
}
}
}
}
/**
* 这里以此方法为服务器demo,仅作示例
* @return 返回服务器要推送的消息,否则如果为空的话,不推送
*/
public string getservermessage(){
return "yes!";
}
}
其中messageactivity是点击跳转的activity,负责处理查看详细信息。
我们在其他activity中调用一下:
代码如下:
boolean ismessagepush = true;//不开启就设置为false;
…
if(ismessagepush){
startservice(new intent(this, messageservice.class))
};
运行一下:
4.停止服务
1 stopservice(new intent(myactivity.this,messageservice.class));
2 setmessagepush(false);//设置配置文件或数据库中flag为false
运行一下,停止服务后,却出乎意料的并没有停下来,怎么回事?是不是代码写错了?
代码没有错,错在我们停止了服务,却没有停止进程,退出线程。
5.退出线程
实践证明,thread的stop()方法并不可靠。但是我们有其他的办法。
在代码面前,程序员就是上帝。
退出线程有两种方法。
第一种方法,强制退出。
//杀死该线程所在的进程,自然就退出了
system.exit(0);
第二种方法,设置isrunning为false。
//前面说到了isrunning这个标志,设置为false后,线程的执行就从while循环中跳出来了,然后自然结束掉了
messagethread.isrunning = false;
综合一下,我们在messageservice中重载ondestroy()方法如下:
代码如下:
@override
public void ondestroy() {
system.exit(0);
//或者,二选一,推荐使用system.exit(0),这样进程退出的更干净
//messagethread.isrunning = false;
super.ondestroy();
}
当控件本身layout_width设置为fill_parent的时候,layout_weight数值越小,所占空间越大,但尽可能大是有限度的,即fill_parent.
当控件本身layout_width设置为wrap_content的时候,layout_weight数值越小,所占空间也越小,但这个小是有限度的,即wrap_content.
例子
看了一下源码,虽说不太懂,但了解了下大概意思,按照自己的理解总结一下,直接写一下简化的代码吧(下面的代码是LinearLayout源文件中一部分的精简,变量名称含义可能不准确,为叙述方便暂作此解释):
代码如下 | 复制代码 |
//Either expand children with weight to take up available space or if (child == null || child.getVisibility() == View.GONE) { float childExtra = lp.weight; |
变量含义
widthSize: LinearLayout的宽度
mTotalLength: 所有子View的宽度的和(还没用考虑layout_weight)
totalWeight: 所有子View的layout_weight的和
mWeihtSUm: LinearLayout的android:weightSum属性
过程分析:
首先计算出额外空间(可以为负)如果额外空间不为0并且有子View的layout_weight不为0的话按layout_weight分配额外空间:
代码如下 | 复制代码 |
int delta = widthSize - mTotalLength; |
如果LinearLayout设置了weightSum则覆盖子View的layout_weight的和:
代码如下 | 复制代码 |
float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight; |
然后遍历LinearLayout的子元素,如果不为null且Visibility不为GONE的话,取得它的LayoutParams,如果它的layout_weight大于0,根据weightSum与它的weight计算出分配给它的额外空间
代码如下 | 复制代码 |
if (childExtra > 0) { int childWidth = child.getMeasuredWidth() + share; |
例子
代码如下 | 复制代码 |
|