2012年5月5日
原文作者: xu33liang33 原文地址: http://my.eoe.cn/xuliangbo/archive/4271.html
参考:http://developer.android.com/distribute/googleplay/promote/linking.html
1 Intent intent = new Intent(Intent.ACTION_VIEW); 2 intent.setData(Uri.parse("market://details?id=com.example.android")); 3 startActivity(intent);
摘要: 第四篇:http://blog.csdn.net/mapdigit/article/details/7570371
App->Activity->Custom Dialog
这个Demo主要是实现自定义对话框。先通过Android Manifest.xml文件找到CustomDialogActivity:
Code highlighting produced by ... 阅读全文
摘要: 第三篇:http://blog.csdn.net/mapdigit/article/details/7555429App->Activity->Animation这个Demo主要讲的是两个Activity在跳转过程中的动画应用。通过Android Manifest.xml文件找到com.example.android.apis.app包下的 Animation类:
Code high... 阅读全文
摘要: 第二篇:http://blog.csdn.net/mapdigit/article/details/7555404创建好ApiDemos项目以后,首先在模拟器上运行该程序,可以看到主界面是一个列表。单击列表中一个栏目后还有若干级列表,最终是一个Activity,展示了其API的一个特性。API Demos全面展示了系统的功能,包括界面、控件、图像处理和媒体处理等。
然后逐个来分析代码:
首先我... 阅读全文
右键D:\Program Files (x86)\Android\android-sdk\SDK Manager.exe->以管理员身份运行。
第一篇:http://blog.csdn.net/mapdigit/article/details/7555392
在csdn上看到了这位大神写的博客,自己也试着学习一下,以前一直都想学习api demos,但是找了很多借口。
Android SDK中自带有很多例子,存放在android-sdksamples目录下,其中介绍了Android平台主要的API的使用,是一份不可多得的学习资料!以Android4.1.2为例,apis目录如下:
首先尝试将ApiDemos源码导入到Eclipse项目中,这个比较简单, 1.New ->Other 选择Android Sample Project (注:不同版本的Eclipse有不同的导入方法,不同Android版本有对应的ApiDemos示例) 。 选择版本,这里我选择4.1.2:
最后直接finish就可以了。
下面看看工程 运行工程可以查看效果图 :
本来一天一帖的,没想到昨天竟然断网了,又本来今天发两贴的,结果学完了但是没写完,效率太低了,现在发现写博客也不是一件很容易的事情,以后每天坚持。
摘要: 现在的大多数应用都会有一个欢迎引导页面,需求分析:程序安装后第一次启动:启动页-->功能引导页-->应用主页以后启动:启动页-->应用主页
实现原理:
用SharedPreferences实现。创建一个boolean的变量,默认值为true。当判断这个变量是true的时候,说明是第一次运行,就跳转到另一个引导页面。引导页面跳转到最后一张图片时,点击某按钮发生跳转事件,回到M... 阅读全文
摘要: 这个小程序的主要原理是通过HTTP协议发送XML数据并调用webservice,分析返回的数据来进行Android查询QQ是否在线。Web Service(WEB服务)能够快捷和方便地综合并结合各种系统、商务和任何应用平台。新出现的 Web Services 标准: SOAP、WSDL 和 UDDI 能够使任何系统和系... 阅读全文
摘要: eoe在线课堂传送门: http://edu.eoe.cn/course/view/cid/25.html资料下载:http://www.eoeandroid.com/forum.php?mod=viewthread&tid=238145&page=1&extra=#pid21590241、二维码介绍:二维码 (2-dimensional bar code),是用... 阅读全文
ViewStub 是一个不可见的,大小为0的View,最佳用途就是实现View的延迟加载,在需要的时候再加载View,可Java中常见的性能优化方法延迟加载一样。
当调用ViewStub的setVisibility函数设置为可见或则调用 inflate初始化该View的时候,ViewStub引用的资源开始初始化,然后引用的资源替代ViewStub自己的位置填充在ViewStub的 位置。因此在没有调用setVisibility(int) 或则 inflate()函数之前 ViewStub一种存在组件树层级结构中,但是由于ViewStub非常轻量级,这对性能影响非常小。 可以通过ViewStub的inflatedId属性来重新定义引用的layout id。 例如:
<ViewStub android:id="@+id/stub"
android:inflatedId="@+id/subTree"
android:layout="@layout/mySubTree"
android:layout_width="120dip"
android:layout_height="40dip" />
上面定义的ViewStub ,可以通过id “stub”来找到,在初始化资源“mySubTree”后,stub从父组件中删除,然后"mySubTree"替代stub的位置。初始资源"mySubTree"得到的组件可以通过inflatedId 指定的id "subTree"引用。 然后初始化后的资源被填充到一个120dip宽、40dip高的地方。
ViewStub stub = (ViewStub) findViewById(R.id.stub);
View inflated = stub.inflate(); 当调用inflate()函数的时候,ViewStub 被引用的资源替代,并且返回引用的view。 这样程序可以直接得到引用的view而不用再次调用函数 findViewById()来查找了。 activity_main.xml: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" >
<!-- 静态加载布局文件 -->
<include android:layout_width="wrap_content" android:layout_height="wrap_content" layout="@layout/my_sub_tree" />
<!-- 动态加载布局文件 -->
<ViewStub android:id="@+id/stub" android:layout_width="wrap_content" android:layout_height="wrap_content" android:inflatedId="@+id/subTree" android:layout="@layout/my_sub_tree" />
<Button android:id="@+id/button_show" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="动态加载布局" />
<Button android:id="@+id/button_hidden" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="动态隐藏布局" />
</LinearLayout> my_sub_tree.xml: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >
<RatingBar android:id="@+id/ratingBar" android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout> MainActivity.java: package com.example.android_viewstub;
import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewStub; import android.widget.Button; import android.widget.RatingBar;
/** * Demo描述: 利用ViewStub显示和隐藏布局 ViewStub的引入: 在开发的时候,有些布局是要根据条件而动态显示,达到一个布局两用的效果, * 运用View.VISIBLE和View.GONE去改变布局的可见性. 这样的做法显然是没什么多大的问题,优点逻辑清晰,控制灵活,但缺点就是耗费资源 * 在setContentView()或者用inflate加载布局文件时无论View是否 * 被设置为View.GONE和View.VISIBLE,都会创建对象,占用一定程度上的内存,所以在考虑优化程序的时候, * 尽量避免资源浪费,降低程序的资源占有量,提高响应速度,提升软件的用户体验 * * 推荐的做法是使用android.view.ViewStub. ViewStub是一个轻量级的View,它一个看不见的,不占布局位置,占用资源非常小的控件. * ViewStub是一个隐藏的,不占用内存空间的视图对象,它可以在运行时延迟加载布局资源文件当 ViewStub可见,或者调用 * inflate()函数时,才会加载这个布局资源文件 注意的问题: ViewStub只能用来Inflate一个布局文件,而不是某个具体的View * * 遇到的问题: 报错 ViewStub must have a non-null ViewGroup viewParent 原因: * 官方文档:viewstub不能反复inflate,只能inflate一次 * */ public class MainActivity extends Activity implements OnClickListener { private ViewStub mViewStub; private Button mShowButton; private Button mHiddenButton;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findView(); bindView(); }
private void findView() { mViewStub = (ViewStub) this.findViewById(R.id.stub); mShowButton = (Button) this.findViewById(R.id.button_show); mHiddenButton = (Button) this.findViewById(R.id.button_hidden); }
private void bindView() { mShowButton.setOnClickListener(this); mHiddenButton.setOnClickListener(this); }
@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; }
@Override public void onClick(View v) { switch (v.getId()) { case R.id.button_show: View inflated = mViewStub.inflate(); RatingBar ratingBar = (RatingBar) inflated .findViewById(R.id.ratingBar); ratingBar.setRating(4); // mViewStub.setVisibility(View.VISIBLE); break; case R.id.button_hidden: mViewStub.setVisibility(View.GONE); break; default: break; } }
}
当在Android的layout设计里面如果输入框过多,则在输入弹出软键盘的时候,下面的输入框会有一部分被软件盘挡住,从而不能获取焦点输入。 1 InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); 2 //得到InputMethodManager的实例 3 if (imm.isActive()) { 4 //如果开启 5 imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, InputMethodManager.HIDE_NOT_ALWAYS); 6 //关闭软键盘,开启方法相同,这个方法是切换开启与关闭状态的 7 }
也可以简单点:1 getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); xml方式:1 <activity android:name=".Activity.FilterActivity" android:label="@string/app_name" android:windowSoftInputMode="stateHidden" android:screenOrientation="portrait" android:configChanges="keyboardHidden|orientation" 2 /> 下面做个详细的介绍: 软输入法模式选项: public int softInputMode;
以下选项与输入法模式有关: 软输入区域是否可见。 public static final int SOFT_INPUT_MASK_STATE = 0x0f;
未指定状态。 public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0;
不要修改软输入法区域的状态。 public static final int SOFT_INPUT_STATE_UNCHANGED = 1;
隐藏输入法区域(当用户进入窗口时)。 public static final int SOFT_INPUT_STATE_HIDDEN = 2;
当窗口获得焦点时,隐藏输入法区域。 public static final int SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3;
显示输入法区域(当用户进入窗口时)。 public static final int SOFT_INPUT_STATE_VISIBLE = 4;
当窗口获得焦点时,显示输入法区域。 public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;
窗口应当主动调整,以适应软输入窗口。 public static final int SOFT_INPUT_MASK_ADJUST = 0xf0;
未指定状态,系统将根据窗口内容尝试选择一个输入法样式。 public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00;
当输入法显示时,允许窗口重新计算尺寸,使内容不被输入法所覆盖。 不可与SOFT_INPUT_ADJUSP_PAN混合使用;如果两个都没有设置,系统将根据窗口内容自动设置一个选项。 public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;
输入法显示时平移窗口。它不需要处理尺寸变化,框架能够移动窗口以确保输入焦点可见。 不可与SOFT_INPUT_ADJUST_RESIZE混合使用;如果两个都没有设置,系统将根据窗口内容自动设置一个选项。 public static final int SOFT_INPUT_ADJUST_PAN = 0x20;
当用户转至此窗口时,由系统自动设置,所以你不要设置它。 当窗口显示之后该标志自动清除。 public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100;
用eclipse进行android开发中经常遇到logcat无任何信息输出,这给我们调试程序带来很大的不便。解决办 法:window-->show view-->选择android下的devices,打开devices,点击右边的截屏图片。等到出现截图的时候,logcat就出来信息了!
PS:如果以上方法试过之后logcat还没有任何信息,则把logcat窗口关了,重新打开
设置注释模板的入口: Window->Preference->Java->Code Style->Code Template 然后展开Comments节点就是所有需设置注释的元素。
文件(Files)注释标签:
/**
* @Title: ${file_name}
* @Package ${package_name}
* @Description: ${todo}(用一句话描述该文件做什么)
* @author A18ccms A18ccms_gmail_com
* @date ${date} ${time}
* @version V1.0
*/
类型(Types)注释标签(类的注释):
/**
* @ClassName: ${type_name}
* @Description: ${todo}(这里用一句话描述这个类的作用)
* @author A18ccms a18ccms_gmail_com
* @date ${date} ${time}
*
* ${tags}
*/
字段(Fields)注释标签:
/**
* @Fields ${field} : ${todo}(用一句话描述这个变量表示什么)
*/
构造函数标签:
/**
* <p>Title: </p>
* <p>Description: </p>
* ${tags}
*/
方法(Constructor & Methods)标签:
/**
* @Title: ${enclosing_method}
* @Description: ${todo}(这里用一句话描述这个方法的作用)
* @param ${tags} 设定文件
* @return ${return_type} 返回类型
* @throws
*/
覆盖方法(Overriding Methods)标签:
/* (非 Javadoc)
* <p>Title: ${enclosing_method}</p>
* <p>Description: </p>
* ${tags}
* ${see_to_overridden}
*/
代表方法(Delegate Methods)标签:
/**
* ${tags}
* ${see_to_target}
*/
getter方法标签: /** * @return ${bare_field_name} */
setter方法标签: /** * @param ${param} 要设置的 ${bare_field_name} */
简单模板例子: 1 <?xml version="1.0" encoding="UTF-8"?><templates><template autoinsert="true" context="fieldcomment_context" deleted="false" description="字段的注释" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name="fieldcomment">/** 2 * @Fields ${field} : ${todo}(用一句话描述这个变量表示什么) 3 */ 4 </template><template autoinsert="true" context="gettercomment_context" deleted="false" description="getter 方法的注释" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name="gettercomment">/** 5 * @return ${bare_field_name} 6 */ 7 </template><template autoinsert="true" context="constructorcomment_context" deleted="false" description="创建的构造函数的注释" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name="constructorcomment">/** 8 * <p>Title:${file_name} </p> 9 * <p>Description: 构造函数</p> 10 * ${tags} 11 */ 12 </template><template autoinsert="true" context="filecomment_context" deleted="false" description="已创建的 Java 文件的注释" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.filecomment" name="filecomment">/** 13 * @Title: ${file_name} 14 * @Package ${package_name} 15 * @Description: ${todo}(用一句话描述该文件做什么) 16 * @author DAIGUANGJIU 17 * @date ${date} ${time} 18 * @version V1.0 19 */ 20 </template><template autoinsert="true" context="settercomment_context" deleted="false" description="setter 方法的注释" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.settercomment" name="settercomment">/** 21 * @param ${param} 要设置的 ${bare_field_name} 22 */</template><template autoinsert="true" context="typecomment_context" deleted="false" description="创建的类型的注释" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.typecomment" name="typecomment">/** 23 * @author ${user} 24 * 25 * ${tags} 26 */</template><template autoinsert="true" context="delegatecomment_context" deleted="false" description="代表方法的注释" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name="delegatecomment">/** 27 * ${tags} 28 * ${see_to_target} 29 */</template><template autoinsert="true" context="overridecomment_context" deleted="false" description="覆盖方法的注释" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name="overridecomment">/** (非 Javadoc) 30 * <p>Title: ${enclosing_method}</p> 31 * <p>Description: </p> 32 * ${tags} 33 * ${see_to_overridden} 34 */</template><template autoinsert="true" context="methodcomment_context" deleted="false" description="非覆盖方法的注释" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name="methodcomment">/** 35 * ${tags} 36 */</template></templa 37 <?xml version="1.0" encoding="UTF-8"?><templates><template autoinsert="true" context="fieldcomment_context" deleted="false" description="字段的注释" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name="fieldcomment">/** 38 * @Fields ${field} : ${todo}(用一句话描述这个变量表示什么) 39 */ 40 </template><template autoinsert="true" context="gettercomment_context" deleted="false" description="getter 方法的注释" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name="gettercomment">/** 41 * @return ${bare_field_name} 42 */ 43 </template><template autoinsert="true" context="constructorcomment_context" deleted="false" description="创建的构造函数的注释" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name="constructorcomment">/** 44 * <p>Title:${file_name} </p> 45 * <p>Description: 构造函数</p> 46 * ${tags} 47 */ 48 </template><template autoinsert="true" context="filecomment_context" deleted="false" description="已创建的 Java 文件的注释" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.filecomment" name="filecomment">/** 49 * @Title: ${file_name} 50 * @Package ${package_name} 51 * @Description: ${todo}(用一句话描述该文件做什么) 52 * @author DAIGUANGJIU 53 * @date ${date} ${time} 54 * @version V1.0 55 */ 56 </template><template autoinsert="true" context="settercomment_context" deleted="false" description="setter 方法的注释" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.settercomment" name="settercomment">/** 57 * @param ${param} 要设置的 ${bare_field_name} 58 */</template><template autoinsert="true" context="typecomment_context" deleted="false" description="创建的类型的注释" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.typecomment" name="typecomment">/** 59 * @author ${user} 60 * 61 * ${tags} 62 */</template><template autoinsert="true" context="delegatecomment_context" deleted="false" description="代表方法的注释" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name="delegatecomment">/** 63 * ${tags} 64 * ${see_to_target} 65 */</template><template autoinsert="true" context="overridecomment_context" deleted="false" description="覆盖方法的注释" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name="overridecomment">/** (非 Javadoc) 66 * <p>Title: ${enclosing_method}</p> 67 * <p>Description: </p> 68 * ${tags} 69 * ${see_to_overridden} 70 */</template><template autoinsert="true" context="methodcomment_context" deleted="false" description="非覆盖方法的注释" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name="methodcomment">/** 71 * ${tags} 72 */</template></template>
使用last_insert_rowid()函数,例如: 1 SQLiteDatabase db = helper.getWritableDatabase(); 2 db.execSQL("insert into person(name,phone,amount) values(?,?,?) ", 3 new Object[]{person.getName(),person.getPhone(),person.getAmount()}); 4 Cursor cursor = db.rawQuery("select last_insert_rowid() from person",null); 5 int strid; 6 if(cursor.moveToFirst()) 7 strid = cursor.getInt(0); 8 Log.i("testAuto", strid+"");
android程序中如果有很多activity,又没有在跳转过程中全都finish,很可能在最后退出程序时,当前的activity结束了,但是又 跳转到activity栈的下一个activity。例如从A-B-C,在跳转过程中没有finish掉B,那么从C退出程序时,就会跳到B的界面。
最理想的解决办法就是每次在调用startActivity(intent)之前finish当前的activity,但是如果在下一个activity 又要回到上一个activity,就需要new一个新的activity了。如果刚好这个activity需要加载很多图片和信息,例如一个 listactivity或者含有一个gallery,那么用户体验性就很差,每次按返回键都要重新加载。那么有没办法解决完全退出程序的方法,同时又能 保证用户体验性呢?
网上比较流行的方法是定义栈,写一个ExitApplication类,利用单例模式管理Activity,在每个在Activity的 onCreate()方法中调用ExitApplication.getInstance().addActivity(this)方法,在退出时调用 ExitApplication.getInstance().exit()方法,就可以完全退出应用程序了。 1 package com.gaolei.study; 2 3 import java.util.LinkedList; 4 import java.util.List; 5 6 import android.app.Activity; 7 import android.app.Application; 8 9 public class MyApplication extends Application { 10 11 private static MyApplication instance; 12 13 private List<Activity> activityList = new LinkedList<Activity>(); 14 15 public MyApplication() { 16 } 17 18 // 单例模式获取唯一的MyApplication实例 19 public static MyApplication getInstance() { 20 if (null == instance) { 21 instance = new MyApplication(); 22 } 23 return instance; 24 } 25 26 // 添加Activity到容器中 27 public void addActivity(Activity activity) { 28 activityList.add(activity); 29 } 30 31 // 遍历所有Activity并finish 32 public void exit() { 33 for (Activity activity : activityList) { 34 activity.finish(); 35 } 36 System.exit(0); 37 } 38 } 39 每个Activity类中onCreate()方法中调用 ExitApplication.getInstance().addActivity(Activity activity)方法。在某一个Activity界面退出应用程序时,只要调用 ExitApplication.getInstance().exit()方法,就可以在完全退出应用程序。 当然也可以写一个BaseActivity继承Activity, 重写onCreate()方法,然后所有activity都继承它。
工具下载:需用到 dex2jar 和 XJad 这2个工具 该方法是使用dex2jar.jar包,将classes.dex文件解包成jar,在通过XJad(或者其他class反编译工具)进行java反编译。
步骤: 1.把.apk文件改名为.zip,然后解压缩,得到其中的classes.dex文件,它就是java文件编译再通过dx工具打包成的,所以现在我们就用上述提到的2个工具来逆方向导出java源文件
2.把classes.dex拷贝到dex2jar.bat所在目录, 在命令行模式下定位到dex2jar.bat所在目录,运行 dex2jar.bat classes.dex ,生成classes.dex.dex2jar.jar
3.运行XJad工具(菜单栏 文件->反编译Jar文件),即可看到源代码 该方法的好处在于,通过XJad反编译后,大家可直接开到java源文件,缺点在于只能反编译出开发时的java文件,而开发时使用的lib包不能反编译出来。
1. 在drawable 下新建 shape.xml 文件 Xml代码 : 1 <?xml version="1.0" encoding="UTF-8"?> 2 <shape xmlns:android="http://schemas.android.com/apk/res/android" 3 android:shape="rectangle" > 4 5 <!-- 填充的颜色 --> 6 <solid android:color="#FFFFFF" /> 7 <!-- 设置矩形的四个角为弧形 --> 8 <!-- android:radius 弧形的半径 --> 9 <corners android:radius="7dip" /> 10 11 </shape> android:radius为角的弧度,值越大角越圆。 我们还可以把四个角设定成不同的角度,方法为: 1 <corners 2 android:bottomLeftRadius="20dp" 3 android:bottomRightRadius="0dp" 4 android:topLeftRadius="1dp" 5 android:topRightRadius="20dp" /> 2.1设置成0dp无效,2.1以上版本可以,如果无效的话那就只能设成1dp了。
2.设置引用
android:background="@drawable/shape" EditText 其它属性
android:hint="请输入用户名" <!-- 设置提示文本 --> android:drawableLeft="@drawable/ic_launcher" <!-- 设置文本框左边小图标 -->
例子:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" 5 android:orientation="vertical" > 6 7 <EditText 8 android:layout_width="fill_parent" 9 android:layout_height="wrap_content" 10 android:background="@drawable/shape" 11 android:drawableLeft="@drawable/ic_launcher" 12 android:drawablePadding="5dp" 13 android:hint="Hello Android" 14 android:padding="5dp" /> 15 16 </LinearLayout>
1. 取消系统的自动折叠 Window->Preferences-> Java->Editor->Folding: Enable folding
2. 取消按"."后自动激活提示功能。这样会有些提高速度 Window->Preferences-> Java->Editor->Content Assist: Enable auto activation
3. 关闭不常用的工程 一些不常用的工程打开的时候,也会影响你正在使用工程的操作速度。
4. 设置启动参数 起动的时候 加上参数:eclipse.exe -vmargs -Xverify:none -XX:+UseParallelGC -XX:PermSize=20M -Xms64M - Xmx200M 如果你的内存是1G的。可以将最后一个参数Xmx200M改为 Xmx512M 这个在你的起动快捷键的属性里设置。
6. 取消Plugin 进入Preferences把Plug-in Development>Target Platform> plug-in里跟自己无关或者暂且不用的plug -in去掉勾选,我这里共400多个中去掉了100多个。
7. 设置Edit Mode MyEclipse5.0.1GA_E3.2 之前的:Window->Preferences->-->myeclipse->files & Editors下把跟编辑有关的所有 的Edit Modes 设为 Disable Design Mode
8. 设置视图 打开Customize Perspective里自己没用到的选项自己去掉勾选。 5. 取消MyEclipse在启动时自动验证项目配置文件 默认情况下MyEclipse在启动的时候会自动验证每个项目的配置文件,这是 一个非常耗时的过程,可以在Preferences窗口依次选择MyEclipse - Validation,然后在右侧的Validator列表中只保留 Manual 项就可以了。如果需要验证的时候只需要选中文件,然后右键选择 MyEclipse - Run Validation就可以了。 9. 去除不需要加载的模块 一个系统20%的功能往往能够满足80%的需求,MyEclipse也不例外,我们在大多数时候只需要20%的 系统功能,所以可以将一些不使用的模块禁止加载启动。通过Windows - Preferences打开配置窗口,依次选择左侧的General - Startup and Shutdown,这个时候在右侧就显示出了Eclipse启动时加载的模块,可以根据自己的实际情况去除一些模块。
比如:现在是2004-03-26 13:31:40 过去是:2004-01-02 11:30:24 我现在要获得两个日期差,差的形式为:XX天XX小时XX分XX秒 方法一: DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { Date d1 = df.parse("2004-03-26 13:31:40"); Date d2 = df.parse("2004-01-02 11:30:24"); long diff = d1.getTime() - d2.getTime(); long days = diff / (1000 * 60 * 60 * 24); } catch (Exception e) { } 方法二: SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); java.util.Date now = df.parse("2004-03-26 13:31:40"); java.util.Date date=df.parse("2004-01-02 11:30:24"); long l=now.getTime()-date.getTime(); long day=l/(24*60*60*1000); long hour=(l/(60*60*1000)-day*24); long min=((l/(60*1000))-day*24*60-hour*60); long s=(l/1000-day*24*60*60-hour*60*60-min*60); System.out.println(""+day+"天"+hour+"小时"+min+"分"+s+"秒"); 方法三: SimpleDateFormat dfs = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); java.util.Date begin=dfs.parse("2004-01-02 11:30:24"); java.util.Date end = dfs.parse("2004-03-26 13:31:40"); long between=(end.getTime()-begin.getTime())/1000;//除以1000是为了转换成秒 long day1=between/(24*3600); long hour1=between%(24*3600)/3600; long minute1=between%3600/60; long second1=between%60/60; System.out.println(""+day1+"天"+hour1+"小时"+minute1+"分"+second1+"秒"); ==================================================== java 比较时间大小 String s1="2008-01-25 09:12:09"; String s2="2008-01-29 09:12:11"; java.text.DateFormat df=new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); java.util.Calendar c1=java.util.Calendar.getInstance(); java.util.Calendar c2=java.util.Calendar.getInstance(); try { c1.setTime(df.parse(s1)); c2.setTime(df.parse(s2)); }catch(java.text.ParseException e){ System.err.println("格式不正确"); } int result=c1.compareTo(c2); if(result==0) System.out.println("c1相等c2"); else if(result<0) System.out.println("c1小于c2"); else System.out.println("c1大于c2");
在Android开发中,大部分控件都有visibility这个属性,其属性有3个分别为“visible ”、“invisible”、“gone”。主要用来设置控制控件的显示和隐藏。有些人可能会疑惑Invisible和gone是有什么区别的???那么,我们带着这个疑问看下面:
其在XML文件和Java代码中设置如下: 可见(visible) XML文件:android:visibility="visible" Java代码:view.setVisibility(View.VISIBLE);
不可见(invisible) XML文件:android:visibility="invisible" Java代码:view.setVisibility(View.INVISIBLE);
隐藏(GONE) XML文件:android:visibility="gone" Java代码:view.setVisibility(View.GONE); 为了区别三者,我建了一个Dome进行演示,先上Dome的代码,演示后就知道它们的区别: main.xml: 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" 5 android:orientation="vertical" > 6 <LinearLayout 7 android:layout_width="fill_parent" 8 android:layout_height="wrap_content" 9 android:orientation="horizontal" 10 android:layout_marginBottom="20dip" > 11 <TextView 12 android:layout_width="wrap_content" 13 android:layout_height="wrap_content" 14 android:layout_weight="1" 15 android:background="#FF0000" 16 android:text="TextView1" /> 17 <TextView 18 android:id="@+id/textView2" 19 android:layout_width="wrap_content" 20 android:layout_height="wrap_content" 21 android:layout_weight="1" 22 android:background="#0000FF" 23 android:text="TextView2" /> 24 </LinearLayout> 25 <Button 26 android:id="@+id/btn1" 27 android:layout_width="fill_parent" 28 android:layout_height="wrap_content" 29 android:text="TextView2为VISIBLE" /> 30 <Button 31 android:id="@+id/btn2" 32 android:layout_width="fill_parent" 33 android:layout_height="wrap_content" 34 android:text="TextView2为INVISIBLE" /> 35 <Button 36 android:id="@+id/btn3" 37 android:layout_width="fill_parent" 38 android:layout_height="wrap_content" 39 android:text="TextView2为GONE" /> 40 </LinearLayout> MyButtonDemo.class: 1 package com.gaolei.demo; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.view.View; 6 import android.view.View.OnClickListener; 7 import android.widget.Button; 8 import android.widget.TextView; 9 10 public class MainActivity extends Activity implements OnClickListener { 11 private TextView textView2; 12 private Button btn1; 13 private Button btn2; 14 private Button btn3; 15 16 @Override 17 public void onCreate(Bundle savedInstanceState) { 18 super.onCreate(savedInstanceState); 19 setContentView(R.layout.main); 20 21 textView2 = (TextView) this.findViewById(R.id.textView2); 22 23 findView(); 24 bindView(); 25 26 } 27 28 private void findView() { 29 btn1 = (Button) this.findViewById(R.id.btn1); 30 btn2 = (Button) this.findViewById(R.id.btn2); 31 btn3 = (Button) this.findViewById(R.id.btn3); 32 } 33 34 private void bindView() { 35 btn1.setOnClickListener(this); 36 btn2.setOnClickListener(this); 37 btn3.setOnClickListener(this); 38 } 39 40 public void onClick(View v) { 41 switch (v.getId()) { 42 case R.id.btn1: 43 // 设置TextView2可见 44 textView2.setVisibility(View.VISIBLE); 45 break; 46 case R.id.btn2: 47 // 设置TextView2不可见 48 textView2.setVisibility(View.INVISIBLE); 49 break; 50 case R.id.btn3: 51 // 设置TextView2隐藏 52 textView2.setVisibility(View.GONE); 53 break; 54 55 default: 56 break; 57 } 58 } 59 } visible:invisible:gone:由上面的演示可知 VISIBLE:设置控件可见 INVISIBLE:设置控件不可见 GONE:设置控件隐藏
而INVISIBLE和GONE的主要区别是:当控件visibility属性为INVISIBLE时,界面保留了view控件所占有的空间;而控件属性为GONE时,界面则不保留view控件所占有的空间。
在开发android 时不能查看源码必是很不爽的一件事,看过网上一些文章后(都是2.0以前的版本,跟我的2.2最新版本的配置是不一样的)不过还是给了我启示,通过配置终于可以在eclipse中查看源码了! 先下载源码,最新为2.21. 源码地址:http://rgruet.free.fr/public/2.找SDK目录安装的SDK到我的目录E:\E:\android-sdk-windows\ 找到目录 结构如下:E:\android-sdk-windows\ -platforms +android-2 +android-3 +android-.... +android-8(数字代表api版本)最高的android-8对应的是SDK2.2ok就是这个了!!在android-8文件中新建sources然后把源码解压到这个文件下3.改配置文件找到android-8目录下的文件source.properties修改如下 ### Android Tool: Source of this archive.#Wed Oct 13 14:00:16 CST 2010Pkg.Desc=Android SDK Platform 2.2_r1Pkg.UserSrc=trueArchive.Arch=ANYPlatform.Version=2.2Pkg.DescUrl=sourcesArchive.Os=WINDOWSPkg.SourceUrl=sourcesPkg.Revision=2AndroidVersion.ApiLevel=8OK重启myecplise然后按ctril+关键字、类名 看是不是可以点进去了,可以看到源码了吧!!很cool吧!注意不同的源码和sdk对应关系!!!作者:蓝之风 出处:http://www.cnblogs.com/vaiyanzi/
方法1: 将源码包移到非workspace目录下,然后new -> other-> Android -> Android Project from Exist Code
方法2: 查看项目目录中是否有隐藏文件.project,还有目录结构也还要有一个隐藏文件.classpath, 如果没有的解决办法。可以把其它项目的.project, .classpath文件拷贝过来,修改相应的地方则可。 1).project文件只需要修改<name>AboxTVExchange</name>这个项目名称则可 2) .classpath文件通常不用改,内容如下: <?xml version="1.0" encoding="UTF-8"?> <classpath> <classpathentry kind="src" path="src"/> <classpathentry kind="src" path="gen"/> <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> <classpathentry kind="output" path="bin"/> </classpath> kind= "... "是指这个目录在project中的类型。kind= "src "为源文件目录, 这个目录下的文件会被编译器编译. kind= "output "是java文件编译输出 目录,src目录下的文件会编译到这个目录下。 当修改项目属性-> java build path时这个文件会被自动修改
1.项目右键 ->android tools->Fix Project
2.如果不可以,检查Project->Properties->Java Compiler
确认Compiler compliance level被设置为1.6,并且Enable project specific settings.
去除ListView滑到顶部和底部时边缘的黑色阴影:
android:fadingEdge="none"
----------------------------------------------------
去除拖动时默认的黑色背景:
android:cacheColorHint="#00000000"
或
listView.setCacheColorHint(Color.TRANSPARENT);
----------------------------------------------------
去除选中时的黄色底色:
android:listSelector="#00000000"
或 listView.setSelector(new ColorDrawable(Color.TRANSPARENT)); --------------------------------------------------- 去除行与行之间的黑线: android:divider=" #00000000 " 或 listView.setDivider(null); --------------------------------------------------- ListView刷新后自动滚到最底部: listView.setSelection( listView .getAdapter().getCount()-1);
Android的Toast是一个很常用的消息提示组件,开发的时候一般是用 Toast.makeText(context, text, duration).show();
来显示一条toast。这种方法有一个问题,如果一条旧消息没有消失以前,又产生了一条新消息,这时候新消息必须等待旧消息消失才能出现。然而实际情况中,我们通常更期望的表现是旧消息马上中止,新消息立刻出现。(不及时的通知不是好通知) 那么怎样才能达到这种效果呢? 1 Toast toast ; 2 if(toast == null){ 3 toast = Toast.makeText(this,"",Toast.LENGTH_SHORT) ; 4 } 5 toast.setText("这样木有延时呢!!!") ; 6 toast.show() ;
例如: activity_main.xml:
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" > 5 6 <Button 7 android:id="@+id/btn1" 8 android:layout_width="wrap_content" 9 android:layout_height="wrap_content" 10 android:text="按钮1" /> 11 12 <Button 13 android:id="@+id/btn2" 14 android:layout_width="wrap_content" 15 android:layout_height="wrap_content" 16 android:text="按纽2" /> 17 18 </LinearLayout> MainActivity.java:
1 package com.gaolei.study; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.view.View; 6 import android.view.View.OnClickListener; 7 import android.widget.Button; 8 import android.widget.Toast; 9 10 import com.notting.work.R; 11 12 public class MainActivity extends Activity { 13 private Button button1; 14 private Button button2; 15 private Toast toast; 16 17 @Override 18 public void onCreate(Bundle savedInstanceState) { 19 super.onCreate(savedInstanceState); 20 setContentView(R.layout.activity_main); 21 22 button1 = (Button) this.findViewById(R.id.btn1); 23 button2 = (Button) this.findViewById(R.id.btn2); 24 25 button1.setOnClickListener(new OnClickListener() { 26 27 public void onClick(View v) { 28 // if (toast == null) { 29 // toast = Toast.makeText(MainActivity.this, "", 30 // Toast.LENGTH_SHORT); 31 // } 32 // toast.setText("2012"); 33 // toast.show(); 34 35 toast = Toast.makeText(MainActivity.this, "2012", Toast.LENGTH_SHORT); 36 toast.show(); 37 } 38 }); 39 40 button2.setOnClickListener(new OnClickListener() { 41 42 public void onClick(View v) { 43 // if (toast == null) { 44 // toast = Toast.makeText(MainActivity.this, "", 45 // Toast.LENGTH_SHORT); 46 // } 47 // toast.setText("2013"); 48 // toast.show(); 49 50 toast = Toast.makeText(MainActivity.this, "2013", Toast.LENGTH_SHORT); 51 toast.show(); 52 } 53 }); 54 } 55 }
前言:略!获取源码的原因千千万~~~ 1. 安装GIT工具。 GIT是林纳斯·托瓦兹大神为了管理器Linux内核开发而创立的分布式版本控制软件。 下载地址:http://code.google.com/p/msysgit/ 一路next将安装进行到底。 2. 在磁盘剩余空间较大的磁盘下新建一个文件夹,用于存放源码。 我在F盘下:新建了androidsourcecode文件夹。 3. 访问Android源码网站,获取你所需要的源码“下载链接”。 网站地址:https://github.com/android 查找需要的源码,比如Music的源码。 位于platform/packages/apps/Music.git 下,点击进入。 注意:有些源码虽然名字在网站上显示,但是被移除了,比如闹钟程序,老版本的AlarmClock就被 删除了,新版本的为DeskClock。自己可以进入相应的目录下看一下,我就不截图了。曾经在这上面吃过亏,就提出来供大家注意一下。 进入后会在页面顶部看到下载方法: To clone one of these trees, install git, and run: git clone https://github.com/android + project path.
To clone the entire platform, install repo, and run: mkdir mydroid cd mydroid repo init -u https://github.com/android/platform/manifest.git repo sync
再往下有Music源码的URL: https://github.com/android /platform/packages/apps/Music.git 拷贝一下。 4. 使用GIT下载。 在第二步新建的文件夹下右键单击,弹出菜单后点击“Git Bash”,进入GIT命令行窗口。 输入 git clone ,然后粘贴第3步拷贝的URL 。 说明:粘贴方法为: 右键单击命令行窗口顶部,弹出菜单,点击编辑,再点粘贴就行了: 点击键盘Enter(回车),就开始下载。
上面有进度百分比,慢慢等就行了 下载完后就可以使用Eclipse打开了。 别忘了下载完后输入exit推出GIT
卸载ADT的方法,方法如下(我的Eclipse版本为3.5): 1、选择 Help > Install New Software; 2、在"Details" 面板中, 点击"What is already installed?" 链接; 3、在Eclipse Installation Details 对话框中,选择"Android DDMS"和"Android Development Tools" ,然后点击Uninstall; 4、在下一个窗口中,确认要删除的ADT,然后点击Finish进行删除; 5、重启Eclipse.
安装ADT插件的地址是https://dl-ssl.google.com/android/eclipse/ ,选择 Help > Install New Software即可看见选项。另外也可以在官方地址下载离线安装包,在这个界面里面安装。不建议直接解压缩粘贴进eclipse目录。
Failed to fectch URl https://dl-ssl.google.com/android/repository/addons_list.xml, reason: Connection to https://dl-ssl.google.com refused 解决办法来源于:code.google.com - 用notepad打开C:\WINDOWS\system32\drivers\etc中的hosts文件
- 在最后一行添加74.125.237.1 dl-ssl.google.com
- 成功解决问题。
|
做了几个android企业应用项目后,总结了项目的基本开发步骤,希望能够交流。 一 应用规划: ※确定功能。 ※必须的界面及界面跳转的流程。 ※需要的数据及数据的来源及格式。 ※是否需要服务端支持。 ※是否需要本地数据库支持。 ※是否需要特殊权限。 ※是否需要后台服务。 三 界面设计: ※主界面确定。 ※模块界面、列表、查看、编辑界面。 ※菜单、按钮、对话框、提示信息。 ※界面总体颜色。 四 数据操作和存储: ※数据来源。 ※数据类型。 ※存储方式。 六 页面跳转: ※每个页面间的跳转。 ※菜单、按钮、事件等。 关键字: android app, android develop, android summary 从2010.04启动该项目到现在完成主要功能模块,分享一下开发历程和注意事项。 开发环境: ubuntu7.10 + eclipse 3.5 + sdk 下面是开发总结: 1. 基于源码级的SDK以及SDK升级注意事项 o 熟悉其如何做资源国际化 o 熟悉其如何支持不同屏幕大小,不同density介质 o 熟悉其主要的API以及支持的最低版本和不被再支持的API o 了解其分层架构 o 升级SDK 确保该平台支持相关的cglib版本(否则要升级ubuntu) 简单容行的方式是remove ~/.android下的相关东西,remove先前的相关版本,再升级 部分Resources(如strings中有%s的)可能需要修改才能适应新的版本 新的sdk里可能不包括老的如2.01版本 2. Emulator & Mobile o 用adb shell 操作emulator http://www.javaeye.com/topic/260042 o push / pull file in emulator Eclipse->window->Show View->File Explorer-> pull a file from the device(or push a file onto the device) o 用 real mobile连接usb来直接测试(mobile 必须设置为develop/debug mode) http://dimitar.me/how-to-connect-your-android-phone-to-ubuntu-to-do-developmenttestinginstallations-or-tethering/ o emulator更能用于性能测试,功能测试。而mobile更适合触摸操作测试和一些View的真实展现测试 o 屏幕大小适应测试(枚举大,中,小),屏幕方向(枚举横,竖屏),任务切换测试 o 内存适应只能在mobile上做测试 3. 系统配置项 o SharedPreferences存储位置及如何在emulator上手动修改 找到存储位置: \data\data\your package dir\shared_prefs\your xml files 按照上面的pull/push the file o SQLite(sqlite3) 默认存储位置:\data\data\your package dir\databases\your database name o Other File I/O assert下文件读取 文件权限以及读写 o 解读AndroidManifest.xml application/process标识 最开始启动的activity activity栈的形式(指定taskAffinity&launchMode="singleTask"),而且转向一个新的activity是用intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)的形式 需要的权限部分 支持的最低版本 4. 基于View,Context,Manager的开发 o 系统View & Layout(Layout也是View) . 用View本身来做其他Layout间的一个分隔 . 常用的View&Layout: ListView,ScrollView,RelativeLayout,TableLayout . 设计常用的style/theme用到的Drawable: http://idunnolol.com/android/drawables.html . 常用的图片操作 . 指定颜色的渲染(setColorFilter) . 剪裁 o 自定义View & Layout . Java代码 public class TouchListView extends ListView { public TouchListView(Context context, AttributeSet attrs, int defStyle) { } } public class Toolbar extends LinearLayout { public Toolbar(final Context context) { super(context); } public Toolbar(final Context con, AttributeSet attrs) { } } activity跳转 sendBroadcast(实时数据交换可借助Thread+ BroadcastReceiver) o WindowManager 、PackageManager 等的使用 2. 网络IO o java.net o android.net o org.apache.http 如果没有让他在AsyncTask中操作,则他的TimeOut设置必须少于5秒(为ANR等待时间) java.net.UnknownHostException 如果发生在emulator,可参考: http://www.javaeye.com/topic/521023 如果发生在mobile,则一般是DNS解析问题,要么允许用户再重试操作,要么把Host的域名改为public ip address 3. 绘图部分 o 在View上绘图 只在原来View上加边框等 Java代码 @Override protected void dispatchDraw(Canvas canvas) {} @Override protected void onDraw(Canvas canvas) { Bitmap result = Bitmap.createBitmap(48,48, Config.ARGB_8888); Canvas canvas = new Canvas(result); ... canvas.drawBitmap(result, rect, rect, paint); 2. 动画 o 帧动画 控制侦速率在25FPS以让其更流畅 o 渐变动画 平移 缩放 旋转 透明 3. ANR o 构建消息以及消息循环处理Handler o 使用AsyncTask 4. Exception & UncaughtException o 使用UncaughtExceptionHandler 5. 引入第三方jar以及与其他app共享数据 o 通过add user library方式添加第三方jar o Content Provider的使用 6. 性能优化/调优 o 基于View的优化http://dl.javaeye.com/topics/download/774b3e9e-1c48-33bd-bc9d-5c27da998181 o 代码级的规范 o Method级的调优 Method Profiling(如果直接usb连接mobile,需要root权限作此项) o GC分析 使用Allocation Tracker /Files/gaolei-xj/Android_app项目开发步骤总结.pdf
原理概述: 手机电池电量的获取在应用程序的开发中也很常用,Android系统中手机电池电量发生变化的消息是通过Intent广播来实现的,常用的Intent的Action有 Intent.ACTION_BATTERY_CHANGED(电池电量发生改变时)、Intent.ACTION_BATTERY_LOW(电池电量达到下限时)、和Intent.ACTION_BATTERY_OKAY(电池电量从低恢复到高时)。 当需要在程序中获取电池电量的信息时,需要为应用程序注册BroadcastReceiver组件,当特定的Action事件发生时,系统将会发出相应的广播,应用程序就可以通过BroadcastReceiver来接受广播,并进行相应的处理。 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" 5 android:orientation="vertical" > 6 7 <Button 8 android:id="@+id/button" 9 android:layout_width="fill_parent" 10 android:layout_height="wrap_content" 11 android:text="取得电池电量" /> 12 13 </LinearLayout>
1 package org.gl.demo; 2 3 import android.app.Activity; 4 import android.content.Intent; 5 import android.content.IntentFilter; 6 import android.os.Bundle; 7 import android.view.View; 8 import android.view.View.OnClickListener; 9 import android.widget.Button; 10 11 public class MainActivity extends Activity { 12 private Button button = null; 13 14 @Override 15 public void onCreate(Bundle savedInstanceState) { 16 super.onCreate(savedInstanceState); 17 setContentView(R.layout.main); 18 19 button = (Button) findViewById(R.id.button); 20 button.setOnClickListener(new BatteryClickListener()); 21 } 22 23 private class BatteryClickListener implements OnClickListener { 24 25 @Override 26 public void onClick(View v) { 27 BatteryBroadcastReceiver receiver = new BatteryBroadcastReceiver(); 28 IntentFilter filter = new IntentFilter( 29 Intent.ACTION_BATTERY_CHANGED); 30 MainActivity.this.registerReceiver(receiver, filter); 31 32 } 33 34 } 35 } 1 package org.gl.demo; 2 3 import android.app.AlertDialog; 4 import android.app.Dialog; 5 import android.content.BroadcastReceiver; 6 import android.content.Context; 7 import android.content.DialogInterface; 8 import android.content.Intent; 9 10 public class BatteryBroadcastReceiver extends BroadcastReceiver { 11 12 @Override 13 public void onReceive(Context context, Intent intent) { 14 if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) { 15 // 获得当前电量 16 int current = intent.getIntExtra("level", 0); 17 // 获取总电量 18 int total = intent.getIntExtra("scale", 0); 19 Dialog dialog = new AlertDialog.Builder(context) 20 .setTitle("电池电量") 21 .setMessage( 22 "电池电量为:" + String.valueOf(current * 100 / total) 23 + "%") 24 .setNegativeButton("关闭", 25 new DialogInterface.OnClickListener() { 26 27 @Override 28 public void onClick(DialogInterface dialog, 29 int which) { 30 31 } 32 }).create(); 33 dialog.show(); 34 } 35 36 } 37 38 } 39
自己最近在找工作,一直在修改简历。 1、要仔细检查已成文的个人简历,绝对不能出现错别字、语法和标点符号方面的低级错误。最好让文笔好的朋友帮你审查一遍,因为别人比你自己更容易检查出错误 2、个人简历最好用A4标准复印纸打印, 字体最好采用常用的宋体或楷体,尽量不要用花里呼哨的艺术字体和彩色字, 排版要简洁明快,切忌标新立异,排的象广告一样。当然,如果你应聘的是排版工作则是例外。 3、要记住你的个人简历必须突出重点,它不是你的个人自传,与你申请的工作无关的事情要尽量不写,而对你申请的工作有意义的经历和经验绝不能漏掉。 4、要保证你的简历会使招聘者在30秒之内,即可判断出你的价值,并且决定是否聘用你。 5、你的个人简历越短越好,因为招聘人没有时间或者不愿意花太多的时间阅读一篇冗长空洞的个人简历。最好在一页纸之内完成,一般不要超过两页。 6、要切记不要仅仅寄你的个人简历给你应聘的公司,附上一封简短的应聘信,会使公司增加对你的好感。否则,你成功的几率将大大降低。 7、要尽量提供个人简历中提到的业绩和能力的证明资料,并作为附件附在个人简历的后面。一定要记住是复印件,千万不要寄原件给招聘单位,以防丢失。 8、一定要用积极的语言,切忌用缺乏自信和消极的语言写你的个人简历。 最好的方法是在你心情好的时候编写你的个人简历。 9、不能凭空编造你的经历,说谎永远是卑鄙的,没有哪个公司会喜欢说谎的员工,但也没有必要写出所有你真实的经历。对你求职不利的经历你可忽略不写。 10、要组织好个人简历的结构,不能在一个个人简历中出现重复的内容。让人感到你的个人简历条理清楚,结构严谨是很重要的。 11、最好用第三人称写你的个人简历,不要在个人简历中出现“我”的字样。 12、你的个人经历顺序应该从现在开始倒过去叙诉,这样可使招聘单位在最短的时间内了解你最近的经历。 13、在结构严谨的前提下,要使你的个人简历富有创造性,使阅读者能产生很强的阅读兴趣。 14、遣词造句要精雕细磨,惜墨如金。尽量用简练又简练的语言。
我的观点:其实简历上面是可以适当的吹下牛,尤其在你的工作经验方面,公司主要看的就是 你的工作经验,做的项目。看你能不能给公司带来利益。简历只是一个面试的机会,有了机会我们才能把握。此贴献给找正在工作的童鞋!!!!
1.java.net.SocketTimeoutException这个异常比较常见,socket超时。一般有2个地方会抛出这个,一个是connect的时候,这个超时参数由connect(SocketAddress endpoint, int timeout)中的后者来决定,还有就是setSoTimeout(int timeout),这个是设定读取的超时时间。他们设置成0均表示无限大。 ----------------------------------------------------------------------------------------------------- 2.java.net.BindException:Address already in use:JVM_Bind
该异常发生在服务器端进行new ServerSocket(port)或者socket.bind(SocketAddress bindpoint)操作时。 原因:与port一样的一个端口已经被启用,并进行监听。 此时用netstat -an 命令,可以看到一个Listening状态的端口。 只需要找到一个没有被占用的端口就能解决这个问题。 ------------------------------------------------------------------------------------------------------ 3.java.net.ConnectException:Connection refused:connect
该异常发生在客户端进行new Socket(ip, port)或者socket.connect(address, timeout)操作时。 原因:指定ip地址的机器不能找到(也就是说从当前机器不存在到指定ip路由), 或者是该ip存在,但找不到指定的端口进行监听。应该首先检查客户端的ip和port 是否写错了,假如能ping通(服务器端把ping禁掉则需要另外的方法),则看在服务器端的 监听指定端口的程序是否启动。 -------------------------------------------------------------------------------------------------------- 4.java.net.SocketException:Socket is closed 该异常在客户端和服务器端均可能发生。异常的原因是己方主动关闭了连接后 (调用了Socket的close方法)再对网络连接进行读写操作。 ------------------------------------------------------------------------------ 5.java.net.SocketException: Connection reset或者Connect reset by peer:Socket write error 该异常在客户端和服务器端均有可能发生,引起该异常的原因有两个,第一个就是假如一端的Socket被关闭(或主动关闭或者因为异常退出而引起的关闭), 另一端仍发送数据,发送的第一个数据包引发该异常(Connect reset by peer)。另一个是一端退出,但退出时并未关闭该连接,另一端假如在从连接中读数据则抛出该异常(Connection reset)。简单的说就是在连接断开后的读和写操作引起的。 对于服务器,一般的原因可以认为: a) 服务器的并发连接数超过了其承载量,服务器会将其中一些连接主动Down掉. b) 在数据传输的过程中,浏览器或者接收客户端关闭了,而服务端还在向客户端发送数据。 ---------------------------------------------------------------------------- 6.java.net.SocketException: Broken pipe 该异常在客户端和服务器均有可能发生。在抛出SocketExcepton:Connect reset by peer:Socket write error后,假如再继续写数据则抛出该异常。前两个异常的解决方法是首先确保程序退出前关闭所有的网络连接,其次是要检测对方的关闭连接操作,发现对方 关闭连接后自己也要关闭该连接。 对于4和5这两种情况的异常,需要特别注意连接的维护。在短连接情况下还好,如果是长连接情况,对于连接状态的维护不当,则非常容易出现异常。基本上对长连接需要做的就是: a) 检测对方的主动断连(对方调用了Socket的close方法)。因为对方主动断连,另一方如果在进行读操作,则此时的返回值是-1。所以一旦检测到对方断连,则主动关闭己方的连接(调用Socket的close方法)。 b) 检测对方的宕机、异常退出及网络不通,一般做法都是心跳检测。双方周期性的发送数据给对方,同时也从对方接收“心跳数据”,如果连续几个周期都没有收到对 方心跳,则可以判断对方或者宕机或者异常退出或者网络不通,此时也需要主动关闭己方连接;如果是客户端可在延迟一定时间后重新发起连接。虽然Socket 有一个keep alive选项来维护连接,如果用该选项,一般需要两个小时才能发现对方的宕机、异常退出及网络不通。 ---------------------------------------------------------------------------------------------- 7.java.net.SocketException: Too many open files 原因: 操作系统的中打开文件的最大句柄数受限所致,常常发生在很多个并发用户访问服务器的时候。 因为为了执行每个用户的应用服务器都要加载很多文件(new一个socket就需要一个文件句柄),这就会导致打开文件的句柄的缺乏。 解决方式: a) 尽量把类打成jar包,因为一个jar包只消耗一个文件句柄,如果不打包,一个类就消耗一个文件句柄。 b) java的GC不能关闭网络连接打开的文件句柄,如果没有执行close()则文件句柄将一直存在,而不能被关闭。 也可以考虑设置socket的最大打开 数来控制这个问题。对操作系统做相关的设置,增加最大文件句柄数量。ulimit -a可以查看系统目前资源限制,ulimit -n 10240则可以修改,这个修改只对当前窗口有效。
摘要: Ctrl+1 快速修复(最经典的快捷键,就不用多说了)Ctrl+D: 删除当前行 Ctrl+Alt+↓ 复制当前行到下一行(复制增加)Ctrl+Alt+↑ 复制当前行到上一行(复制增加)Alt+↓ 当前行和下面一行交互位置(特别实用,可以省去先剪切,再粘贴了)Alt+↑ 当前行和上面一行交互位置(同上)Alt+← 前一个编辑的页... 阅读全文
简短说明(Quick explanation): 通过创建BroadcastReceiver来侦测系统中有关电池Intent(ACTION_BATTERY_CHANGED)的变化,一旦有接收到相关事件,将会读取当前电量情况,并通过TextViews显示在当前屏幕。 1 public class MyButteryDemo extends Activity { 2 private Button button = null; 3 4 @Override 5 public void onCreate(Bundle savedInstanceState) { 6 super.onCreate(savedInstanceState); 7 setContentView(R.layout.main); 8 9 button = (Button) findViewById(R.id.btn); 10 button.setOnClickListener(new OnClickListenerImpl()); 11 } 12 13 private class OnClickListenerImpl implements OnClickListener { 14 15 @Override 16 public void onClick(View arg0) { 17 ButteryBroadcastReceiver receiver = new ButteryBroadcastReceiver(); 18 IntentFilter filter = new IntentFilter( 19 Intent.ACTION_BATTERY_CHANGED); 20 MyButteryDemo.this.registerReceiver(receiver, filter); 21 } 22 23 } 24 } 1 public class ButteryBroadcastReceiver extends BroadcastReceiver { 2 3 @Override 4 public void onReceive(Context context, Intent intent) { 5 6 if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) { 7 int level = intent.getIntExtra("level", 0); 8 int scale = intent.getIntExtra("scale", 100); 9 Dialog dialog = new AlertDialog.Builder(context) 10 .setTitle("电池电量") 11 .setMessage( 12 "电池电量为:" + String.valueOf(level * 100 / scale) 13 + "%").setNegativeButton("关闭", new DialogInterface.OnClickListener() { 14 15 @Override 16 public void onClick(DialogInterface dialog, int which) { 17 // TODO Auto-generated method stub 18 19 } 20 }).create(); 21 dialog.show(); 22 } 23 } 24 25 }
开机启动Receiver
1 public void onReceive(Context context, Intent intent) {
2 String action = intent.getAction();
3 if(Intent.ACTION_BOOT_COMPLETED.equals(action)) {
4 Intent serviceIntent = new Intent();
5 serviceIntent.setClass(context, BcsService.class);
6 context.startService(serviceIntent);
7 }
8 }
开机和网络连接时启动Receiver 1 @Override 2 public void onReceive(Context context, Intent intent) { 3 String action = intent.getAction(); 4 if(Intent.ACTION_BOOT_COMPLETED.equals(action) || 5 ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { 6 Intent serviceIntent = new Intent(); 7 serviceIntent.setClass(context, BcsService.class); 8 context.startService(serviceIntent); 9 } 10 }
1 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 2 // sd card 可用 3 }else { 4 // 当前不可用 5 }
1 public static String getSdDirectory() { 2 return Environment.getExternalStorageDirectory().getPath(); 3 }
现在有3个按钮,如何让这3个按钮以水平方向分别左对齐、居中对齐和右对齐。 使用FrameLayout和android:layout_gravity属性可以很容易实现这个布局。 1 <?xml version="1.0" encoding="utf-8"?> 2 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" 5 android:orientation="horizontal" > 6 <Button 7 android:layout_width="wrap_content" 8 android:layout_height="wrap_content" 9 android:layout_gravity="left" 10 android:text="按钮1"/> 11 <Button 12 android:layout_width="wrap_content" 13 android:layout_height="wrap_content" 14 android:layout_gravity="center_horizontal" 15 android:text="按钮1"/> 16 <Button 17 android:layout_width="wrap_content" 18 android:layout_height="wrap_content" 19 android:layout_gravity="right" 20 android:text="按钮1"/> 21 </FrameLayout> 怎样实现5个按钮成梅花状排列,并整体水平居中。 1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="wrap_content" 4 android:layout_height="wrap_content" 5 android:layout_gravity="center_horizontal" > 6 7 <!-- 左上角的按钮 --> 8 <Button 9 android:id="@+id/button1" 10 android:layout_width="wrap_content" 11 android:layout_height="wrap_content" 12 android:text="按钮1" /> 13 14 <!-- 中心的按钮 --> 15 <Button 16 android:id="@+id/button2" 17 android:layout_width="wrap_content" 18 android:layout_height="wrap_content" 19 android:layout_below="@id/button1" 20 android:layout_toRightOf="@id/button1" 21 android:text="按钮2" /> 22 23 <!-- 左下角的按钮 --> 24 <Button 25 android:layout_width="wrap_content" 26 android:layout_height="wrap_content" 27 android:layout_toLeftOf="@id/button2" 28 android:layout_below="@id/button2" 29 android:text="按钮3" /> 30 31 <!-- 右上角的按钮 --> 32 <Button 33 android:layout_width="wrap_content" 34 android:layout_height="wrap_content" 35 android:layout_above="@id/button2" 36 android:layout_toRightOf="@id/button2" 37 android:text="按钮4" /> 38 39 <!-- 右下角的按钮 --> 40 <Button 41 android:layout_width="wrap_content" 42 android:layout_height="wrap_content" 43 android:layout_toRightOf="@id/button2" 44 android:layout_below="@id/button2" 45 android:text="按钮5" /> 46 47 </RelativeLayout> 48 如何重用布局文件? 可以使用<include>标签引用其他的布局文件,并用android:id属性覆盖被引用布局文件中顶层节点的android:id属性值。代码如下: <!--引用mylayout.xml文件--> <include android:id="@+id/layout1" layout="@layout/mylayout"> android:layout_gravity属性和android:gravity有什么区别? android:layout_gravity属性指定了当前View在父View中的位置,而android:gravity属性指定了View中内容(文本、图像或其他View)的位置。 android:padding属性和android:layout_margin属性的区别是什么? android:padding属性用于设置View中的内容距View边缘的距离,而android:layout_margin属性用于设置View距离其他View或父容器边缘的距离。 请写出显示一个Toast信息框的Java代码。 Toast toast = Toast.makeText(this,"我的信息", Toast.LENGTH_LONG); toast.show();
摘要: 出色的用户体验有三个特征:速度快、响应及时以及无缝。下面的信息帮助你的应用如何能够在Android上实现这些特征。一、速度快你不能假设手机与桌面系统和服务器一样提速,更多的是你要关注你的代码是否高效。编写高效的Android代码,应遵循两个原则:不要做不必要的事不要分配不必要的内存以下是一些达到此目标的小技巧(有一些技巧是与oo的原则冲突,斟酌使用场景):1、避免建立对象例如,int数组比Inte... 阅读全文
1 <meta-data android:name="string"
2
3 android:resource="resource specification"
4
5 android:value="string" />
这是该元素的基本结构.可以包含在
<activity> <activity-alias> <service> <receiver>四个元素中。 这个名字值是额外的任意的可以提供给父组件的数据。一个组件元素能够包含任意数量的meta-data子元素。它们所有的值都会被收集在Bundle对象中并且使其可以作为组件的 PackageItemInfo.metaData 字段。 一般的值可以通过value属性来指定,但是如果要指定一个资源id作为一个值,那么就要用resource属性来代替。例如:下面的代码就是指定存储在@string/kangaroo 资源中的zoo名字。 <meta-data android:name="zoo" android:value="@string/kangaroo" /> 另一方面,利用resource属性将指定zoo的资源id号,并不是存储在资源中的资源值。 <meta-data android:name="zoo" android:resource="@string/kangaroo" /> 当要给组件提供多个复杂的数据时,在这里并不推荐使用多重meta-data元素,推荐你存储这些数据在一个资源文件中并且利用resource属性来通知它的id给组件。 ------------------------------------------------------------------ android:name
元数据项的名字,为了保证这个名字是唯一的,采用java风格的命名规范。例如:
com.example.project.activity.fred android:resource资源的一个引用,指定给这个项的值是该资源的id。该id可以通过方法Bundle.getInt()来从meta-data中找到。
android:value
指定给这一项的值。可以作为值来指定的数据类型并且组件用来找回那些值的Bundle方法列在了下面的表中。 -------------------------------------------------------------
Type Bundle method
String value, using double backslashes (//) to getString() escape characters — such as"//n" and "//uxxxxx" for a Unicode character.
Integer value, such as "100" getInt()
Boolean value, either "true" or "false" getBoolean()
Color value, in the form "#rgb", "#argb", getString() "#rrggbb", or "#aarrggbb"
Float value, such as "1.23" getFloat() ----------------------------------------------------------------
获得a meta-data 的值:
<meta-data android:name="foo" android:value="@string/app_name"/>
1 ActivityInfo ai = activity.getPackageManager().getActivityInfo(componentName, PackageManager.GET_META_DATA); 2 String foo = ai.metaData.getString("foo"); 3 Toast.makeText(this, "meta:"+foo, 1).show();
因为android软件开发分工目前还没有细化,程序员往往需要负责软件界面的开发,虽然软件的界面图片已经由美工设计好了,但如果使用layout技术把软件做成如图片所示的界面确实很困难,而且也比较耗时。Android通过WebView实现了JS代码与Java代码互相通信的功能,使的android软件的界面开发也可以采用HTML网页技术,这样,广大网页美工可以参与进android软件的界面开发工作,从而让程序员从中解脱出来。
在项目的assets目录放入index.html文件 1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 5 <title>Insert title here</title> 6 <style type="text/css"> 7 A { 8 COLOR: #FFFFFF; TEXT-DECORATION: none 9 } 10 </style> 11 <script type="text/javascript"> 12 function show(jsondata){ 13 var jsonobjs = eval(jsondata); 14 var table = document.getElementById("personTable"); 15 for(var y=0; y<jsonobjs.length; y++){ 16 var tr = table.insertRow(table.rows.length); //添加一行 17 //添加三列 18 var td1 = tr.insertCell(0); 19 var td2 = tr.insertCell(1); 20 td2.align = "center"; 21 var td3 = tr.insertCell(2); 22 //设置列内容和属性 23 td1.innerHTML = jsonobjs[y].id; 24 td2.innerHTML = "<a href='javascript:itcast.call(\"5554\")'>"+ jsonobjs[y].name + "</a>"; 25 td3.innerHTML = jsonobjs[y].phone; 26 } 27 } 28 </script> 29 </head> 30 <body bgcolor="#000000" text="#FFFFFF" style="margin:0 0 0 0" onload="javascript:itcast.personlist()"> 31 <table border="0" width="100%" id="personTable" cellspacing="0"> 32 <tr> 33 <td width="15%">编号</td><td align="center">姓名</td><td width="15%">电话</td> 34 </tr> 35 </table> 36 <a href="javascript:window.location.reload()">刷新</a> 37 </body> 38 </html>
1 public class HtmlActivity extends Activity { 2 private WebView webView; 3 private Handler handler = new Handler(); 4 5 @Override 6 public void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 setContentView(R.layout.main); 9 10 webView = (WebView)this.findViewById(R.id.webView); 11 webView.getSettings().setJavaScriptEnabled(true); 12 webView.getSettings().setSaveFormData(false); 13 webView.getSettings().setSavePassword(false); 14 webView.getSettings().setSupportZoom(false); 15 webView.addJavascriptInterface(new ItcastJavaScript(), “itcast”);//addJavascriptInterface方法中要绑定的Java对象 16 webView.setWebChromeClient(new ItcastWebClient()); 17 webView.loadUrl("file:///android_asset/index.html"); 18 } 19 20 private final class ItcastJavaScript{ 21 public void personlist(){ 22 webview.loadUrl("javascript:contactlist('"+ getPersonJson() + "')"); 23 } 24 25 public void call(final String phone){ 26 startActivity(new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+ phone))); 27 } 28 public static String getPersonJson() {//生成json字符串 29 try { 30 JSONObject jsonObject = new JSONObject(); 31 jsonObject.put("id", 56); 32 jsonObject.put("name", "老张"); 33 jsonObject.put("phone", "5556"); 34 JSONObject jsonObject2 = new JSONObject(); 35 jsonObject2.put("id", 89); 36 jsonObject2.put("name", "老方"); 37 jsonObject2.put("phone", "5558"); 38 JSONArray jsonArray = new JSONArray(); 39 jsonArray.put(jsonObject); 40 jsonArray.put(jsonObject2); 41 return jsonArray.toString(); 42 } catch (JSONException e) { 43 e.printStackTrace(); 44 } 45 return ""; 46 } 47 } 48 private final class ItcastWebClient extends WebChromeClient{ 49 @Override 50 public boolean onJsAlert(WebView view, String url, String message, JsResult result) { 51 new AlertDialog.Builder(HtmlActivity.this) 52 .setTitle("提示信息") 53 .setMessage(message) 54 .setPositiveButton("确定", new DialogInterface.OnClickListener(){ 55 public void onClick(DialogInterface dialoginterface, int i){} 56 }).show(); 57 return true; 58 } 59 } 60 }
Android提供了2种动画:
1> Tween动画,通过对 View 的内容进行一系列的图形变换 (包括平移、缩放、旋转、改变透明度)来实现动画效果。动画效果的定义可以采用XML来做也可以采用编码来做。Tween动画有4种类型:AlphaAnimation、ScaleAnimation、TranslateAnimation、RotateAnimation。
2> Frame动画,即顺序播放事先做好的图像,跟电影类似。开发步骤:
(1)把准备好的图片放进项目res/ drawable下。
(2)在项目的res目录下创建文件夹anim,然后在anim文件夹下面定义动画XML文件,文件名称可以自定义。当然也可以采用编码方式定义动画效果(使用AnimationDrawable类)。
(3)为View控件绑定动画效果。调用代表动画的AnimationDrawable的start()方法开始动画。
本例要实现对ImageView对象进行渐变尺寸缩放动画效果
1> 在项目的res目录下创建文件夹anim,然后在anim文件夹下面定义动画XML文件,文件名称可以自定义,如:scale.xml,内容如下:
1 <?xml version="1.0" encoding="utf-8"?>
2 <set xmlns:android="http://schemas.android.com/apk/res/android">
3 <scale android:interpolator="@android:anim/accelerate_decelerate_interpolator"
4 android:fromXScale="0.0"
5 android:toXScale="5"
6 android:fromYScale="0.0"
7 android:toYScale="5"
8 android:pivotX="50%"
9 android:pivotY="50%"
10 android:fillAfter="false"
11 android:duration="5000"
12 />
13 </set>
动画的进度使用interpolator控制,android提供了几个Interpolator 子类,实现了不同的速度曲线,如LinearInterpolator实现了匀速效果、Accelerateinterpolator实现了加速效果、DecelerateInterpolator实现了减速效果等。还可以定义自己的Interpolator子类,实现抛物线、自由落体等物理效果。
fromXScale(浮点型) 属性为动画起始时X坐标上的缩放尺寸
fromYScale(浮点型) 属性为动画起始时Y坐标上的缩放尺寸
toXScale(浮点型) 属性为动画结束时X坐标上的缩放尺寸
toYScale(浮点型) 属性为动画结束时Y坐标上的缩放尺寸
说明: 以上四种属性值
0.0表示收缩到没有
1.0表示正常无缩放
值小于1.0表示收缩
值大于1.0表示放大
pivotX(浮点型) 属性为动画相对于物件的X坐标的开始位置
pivotY(浮点型) 属性为动画相对于物件的Y坐标的开始位置
说明:
以上两个属性值 从0%-100%中取值
50%为物件的X或Y方向坐标上的中点位置
duration(长整型)属性为动画持续时间 。说明: 时间以毫秒为单位
fillAfter(布尔型)属性当设置为true,该动画转化在动画结束后被应用
2> 在layout文件添加<ImageView>节点:
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:orientation="horizontal"
4 android:layout_width="fill_parent"
5 android:layout_height="fill_parent"
6 >
7 <ImageView
8 android:layout_width="wrap_content"
9 android:layout_height="wrap_content"
10 android:src="@drawable/icon"
11 android:id="@+id/imageView"
12 />
13 </LinearLayout>
说明:除了可以对<ImageView>实现动画效果,其实也可以对其他View实现动画效果,如:<TextView>
3>在Activity里对ImageView使用前面定义好的动画效果:
1 public class AnimationActivity extends Activity {
2 @Override
3 public void onCreate(Bundle savedInstanceState) {
4 super.onCreate(savedInstanceState);
5 setContentView(R.layout.main);
6 ImageView imageView = (ImageView)this.findViewById(R.id.imageView);
7 //加载动画XML文件,生成动画指令
8 Animation animation = AnimationUtils.loadAnimation(this, R.anim.scale);
9 //开始执行动画
10 imageView.startAnimation(animation);
11 }
12 }
13
备注:上面采用的是xml文件定义动画效果,作为代替,也可以采用编码方式实现。下面采用编码方式实现上述例子同样的效果:
1 public class AnimationActivity extends Activity {
2 @Override
3 public void onCreate(Bundle savedInstanceState) {
4 super.onCreate(savedInstanceState);
5 setContentView(R.layout.main);
6 ImageView imageView = (ImageView)this.findViewById(R.id.imageView);
7 ScaleAnimation animation = new ScaleAnimation(0.0f, 5f, 0.0f, 5f,
8 Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
9 animation.setDuration(5000); //设置持续时间5秒
10 imageView.startAnimation(animation);
11 }
12 }
===================== Frame动画例子 ===============================
(1)把准备好的图片放进项目res/ drawable下。
图片有:girl_1.gif, girl_2.gif, girl_3.gif
(2)在项目的res目录下创建文件夹anim,然后在anim文件夹下面定义动画XML文件,文件名称可以自定义,如:frame.xml。
1 <?xml version="1.0" encoding="utf-8"?>
2 <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
3 android:oneshot="false">
4 <item android:drawable="@drawable/girl_1" android:duration="200" />
5 <item android:drawable="@drawable/girl_2" android:duration="200" />
6 <item android:drawable="@drawable/girl_3" android:duration="200" />
7 </animation-list>
上面的XML就定义了一个Frame动画,其包含3帧动画,3帧动画中分别应用了drawable中的3张图片:girl_1.gif, girl_2.gif, girl_3.gif,每帧动画持续200毫秒。android:oneshot属性如果为true,表示动画只播放一次停止在最后一帧上,如果设置为false表示动画循环播放。
(3)为View控件绑定动画效果,调用代表动画的AnimationDrawable的start()方法开始动画。
1 public class FrameActivity extends Activity {
2 private AnimationDrawable animationDrawable;
3 @Override
4 public void onCreate(Bundle savedInstanceState) {
5 super.onCreate(savedInstanceState);
6 setContentView(R.layout.main);
7 ImageView imageView = (ImageView)this.findViewById(R.id.imageView);
8 imageView.setBackgroundResource(R.anim.frame);
9 animationDrawable = (AnimationDrawable) imageView.getBackground();
10 }
11 @Override
12 public boolean onTouchEvent(MotionEvent event) {
13 if (event.getAction() == MotionEvent.ACTION_DOWN) {//按下
14 animationDrawable.start();
15 return true;
16 }
17 return super.onTouchEvent(event);
18 }
19 }
有一点需要强调的是:启动Frame动画的代码animationDrawable.start();不能应用在OnCreate()方法中,因为在OnCreate()中 AnimationDrawable还没有完全的与ImageView绑定。在OnCreate()中启动动画,只能看到第一张图片。这里在拖曳事件中实现的。
android中的样式和CSS样式作用相似,都是用于为界面元素定义显示风格,它是一个包含一个或者多个view控件属性的集合。如:需要定义字体的颜色和大小。
在CSS中是这样定义的:
1 <style>
2 .itcast{COLOR:#0000CC;font-size:18px;}
3 </style>
可以像这样使用上面的css样式:
1 <div class="itcast">传智播客</div>
在Android中可以这样定义样式:
在res/values/styles.xml文件中添加以下内容
1 <?xml version="1.0" encoding="utf-8"?>
2 <resources>
3 <style name=“itcast”> <!-- 为样式定义一个全局唯一的名字-->
4 <item name="android:textSize">18px</item> <!-- name属性为样式要用在的View控件持有的属性 -->
5 <item name="android:textColor">#0000CC</item>
6 </style>
7 </resources>
在layout文件中可以像下面这样使用上面的android样式:
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" .>
3 <TextView style="@style/itcast"
4 .. />
5 </LinearLayout>
<style>元素中有一个parent属性。这个属性可以让当前样式继承一个父样式,当前样式可以继承到父样式的值。当然,如果父样式的值不符合你的需求,你也可以对它进行修改,如下:
1 <?xml version="1.0" encoding="utf-8"?>
2 <resources>
3 <style name="itcast">
4 <item name="android:textSize">18px</item> <!-- name属性为样式要用在的View控件持有的属性 -->
5 <item name="android:textColor">#0000CC</item>
6 </style>
7 <style name="subitcast" parent="@style/itcast">
8 <item name="android:textColor">#FF0000</item>
9 </style>
10 </resources>
android中主题也是用于为应用定义显示风格,它的定义和样式的定义相同,如下:
1 <?xml version="1.0" encoding="utf-8"?>
2 <resources>
3 <style name=“itcastTheme">
4 <item name=“android:windowNoTitle”>true</item> <!-- 没标题 -->
5 <item name=“android:windowFullscreen”>?android:windowNoTitle</item> <!--全屏显示-->
6 </style>
7 </resources>
上面“?android:windowNoTitle”中的问号用于引用在当前主题中定义过的资源的值。
下面代码显示在AndroidManifest.xml中如何为应用设置上面定义的主题:
1 <application android:icon="@drawable/icon" android:label="@string/app_name"
2 android:theme="@style/itcastTheme">
3
4 </application>
除了可以在AndroidManifest.xml中设置主题,同样也可以在代码中设置主题,如下: setTheme(R.style.itcastTheme); 尽管在定义上,样式和主题基本相同,但是它们使用的地方不同。 样式用在单独的View,如:EditText、TextView等; 主题通过AndroidManifest.xml中的<application>和<activity>用在整个应用或者某个 Activity,主题对整个应用或某个Activity存在全局性影响。 如果一个应用使用了主题,同时应用下的view也使用了样式,那么当主题与样式属性发生冲突时,样式的优先级高于主题。 另外android系统也定义了一些主题,例如:<activity android:theme=“@android:style/Theme.Dialog”>,该主题可以让Activity看起来像一个对话框,如果需要查阅这些主题,可以在文档的reference-->android-->R.style 中查看。
摘要: 什么是HTTP协议
1.超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。
2.HTTP是一个客户端和服务器端请求和应答的标准,客户端是终端用户,服务器端是网站。
3.HTTP是客户端浏览器或其他程序与Web服务器之间的应用层通信协议。
HTTP工作原理
1.客户端与服务器建立连接;
2.建立连接后,客户端香... 阅读全文
main.xml:
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="fill_parent"
4 android:layout_height="fill_parent"
5 android:orientation="vertical" >
6
7 <TextView
8 android:layout_width="fill_parent"
9 android:layout_height="wrap_content"
10 android:text="@string/hello" />
11
12 <Button
13 android:id="@+id/locationButtonId"
14 android:layout_width="fill_parent"
15 android:layout_height="wrap_content"
16 android:text="@string/location" />
17
18 <Button
19 android:id="@+id/bestProviderButtonId"
20 android:layout_width="fill_parent"
21 android:layout_height="wrap_content"
22 android:text="@string/bestProvider" />
23
24 </LinearLayout>
strings.xml: 1 <?xml version="1.0" encoding="utf-8"?>
2 <resources>
3
4 <string name="hello">Hello World, MainActivity!</string>
5 <string name="app_name">05_location02</string>
6 <string name="location">测试当前设备的provider</string>
7 <string name="bestProvider">最好的Provider</string>
8
9 </resources>
AndroidManifest.xml:
1 <?xml version="1.0" encoding="utf-8"?>
2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3 package="gaolei.location02"
4 android:versionCode="1"
5 android:versionName="1.0" >
6
7 <uses-sdk android:minSdkVersion="8" />
8
9 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
10 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
11
12 <application
13 android:icon="@drawable/ic_launcher"
14 android:label="@string/app_name" >
15 <activity
16 android:name=".MainActivity"
17 android:label="@string/app_name" >
18 <intent-filter>
19 <action android:name="android.intent.action.MAIN" />
20
21 <category android:name="android.intent.category.LAUNCHER" />
22 </intent-filter>
23 </activity>
24 </application>
25
26 </manifest> MainActivity.java: 1 package gaolei.location02; 2 3 import java.util.Iterator; 4 import java.util.List; 5 6 import android.app.Activity; 7 import android.content.Context; 8 import android.location.Criteria; 9 import android.location.LocationManager; 10 import android.os.Bundle; 11 import android.view.View; 12 import android.view.View.OnClickListener; 13 import android.widget.Button; 14 15 public class MainActivity extends Activity { 16 private Button locationButton; 17 private Button bestProviderButton; 18 private LocationManager locationManager; 19 20 @Override 21 public void onCreate(Bundle savedInstanceState) { 22 super.onCreate(savedInstanceState); 23 setContentView(R.layout.main); 24 25 locationButton = (Button) findViewById(R.id.locationButtonId); 26 bestProviderButton = (Button) findViewById(R.id.bestProviderButtonId); 27 28 locationManager = (LocationManager) MainActivity.this 29 .getSystemService(Context.LOCATION_SERVICE); 30 locationButton.setOnClickListener(new ProvidersButtonListener()); 31 bestProviderButton.setOnClickListener(new BestProviderButtonListener()); 32 } 33 34 private class ProvidersButtonListener implements OnClickListener { 35 36 @Override 37 public void onClick(View v) { 38 List<String> providers = locationManager.getAllProviders(); 39 for (Iterator iterator = providers.iterator(); iterator.hasNext();) { 40 String provider = (String) iterator.next(); 41 System.out.println(provider); 42 } 43 44 } 45 46 } 47 48 private class BestProviderButtonListener implements OnClickListener { 49 50 @Override 51 public void onClick(View v) { 52 // 声明一个Criteria对象 53 Criteria criteria = new Criteria(); 54 // 设置查询条件 55 criteria.setAccuracy(Criteria.ACCURACY_FINE); 56 criteria.setPowerRequirement(Criteria.POWER_LOW); 57 criteria.setAltitudeRequired(false); 58 criteria.setSpeedRequired(false); 59 criteria.setCostAllowed(false); 60 String provider = locationManager.getBestProvider(criteria, false); 61 System.out.println("best provider ----->" + provider); 62 63 } 64 65 } 66 }
User Location能做什么?
1.获取用户的位置
2.追踪用户的移动
User Location的关键API
1.Location Manager:用于管理Android的用户定位服务;
2.Location Providers:提供多种定位方式供开发者选择;
定位方式的分类
1.GPS定位:
使用GPS卫星进行定位,需要在
AndroidMannifest.xml当中声明如下权限:
android.permission.ACCESS_FINE_LOCATION
2.NETWORK定位:
使用信号接收塔和Wi-Fi介入点进行定位,需要在
AndroidManifest.xml当中声明如下权限:
android.permission.ACCESS_FINE_LOCATION
或
android.permission.ACCESS_COARSE_LOCATION
获取用户的当前位置
1.在AndroidManifest.xml当中声明相应的权限;
2.获取LocationManager对象;
3.选择LocationProvider;
4.绑定LocationListener对象;
Main.xml:
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="fill_parent"
4 android:layout_height="fill_parent"
5 android:orientation="vertical" >
6
7 <TextView
8 android:layout_width="fill_parent"
9 android:layout_height="wrap_content"
10 android:text="@string/hello" />
11
12 <Button
13 android:id="@+id/locationButtonId"
14 android:layout_width="fill_parent"
15 android:layout_height="wrap_content"
16 android:text="@string/location" />
strings.xml:
1 <?xml version="1.0" encoding="utf-8"?>
2 <resources>
3
4 <string name="hello">Hello World, MainActivity!</string>
5 <string name="app_name">04_location01</string>
6 <string name="location">绑定监听器</string>
7
8 </resources>
AndroidManifest,xml: 1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="gaolei.location01" 4 android:versionCode="1" 5 android:versionName="1.0" > 6 7 <uses-sdk android:minSdkVersion="8" /> 8 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> 9 <application 10 android:icon="@drawable/ic_launcher" 11 android:label="@string/app_name" > 12 <activity 13 android:name=".MainActivity" 14 android:label="@string/app_name" > 15 <intent-filter> 16 <action android:name="android.intent.action.MAIN" /> 17 18 <category android:name="android.intent.category.LAUNCHER" /> 19 </intent-filter> 20 </activity> 21 </application> 22 23 </manifest> MainActivity: 1 package gaolei.location01; 2 3 import android.app.Activity; 4 import android.content.Context; 5 import android.location.Location; 6 import android.location.LocationListener; 7 import android.location.LocationManager; 8 import android.os.Bundle; 9 import android.view.View; 10 import android.view.View.OnClickListener; 11 import android.widget.Button; 12 13 public class MainActivity extends Activity { 14 private Button button = null; 15 16 @Override 17 public void onCreate(Bundle savedInstanceState) { 18 super.onCreate(savedInstanceState); 19 setContentView(R.layout.main); 20 21 button = (Button) findViewById(R.id.locationButtonId); 22 23 button.setOnClickListener(new ButtonListener()); 24 } 25 26 private class ButtonListener implements OnClickListener { 27 28 @Override 29 public void onClick(View v) { 30 // 得到locationManager对象 31 LocationManager locationManager = (LocationManager) MainActivity.this 32 .getSystemService(Context.LOCATION_SERVICE); 33 locationManager.requestLocationUpdates( 34 LocationManager.GPS_PROVIDER, 0, 0, 35 new TestLocationListener()); 36 37 } 38 } 39 40 private class TestLocationListener implements LocationListener { 41 42 @Override 43 public void onLocationChanged(Location location) { 44 // TODO Auto-generated method stub 45 System.out.println(location.getLatitude()); 46 System.out.println(location.getLongitude()); 47 48 } 49 50 @Override 51 public void onProviderDisabled(String provider) { 52 // TODO Auto-generated method stub 53 54 } 55 56 @Override 57 public void onProviderEnabled(String provider) { 58 // TODO Auto-generated method stub 59 60 } 61 62 @Override 63 public void onStatusChanged(String provider, int status, Bundle extras) { 64 // TODO Auto-generated method stub 65 66 } 67 68 } 69 }
1.传感器的采样率 1 SENSOR_DELAY_NORMAL(200000微秒) 2 SENSOR_DELAY_UI(60000微秒) 3 SENSOR_DELAY_GAME(20000微秒) 4 SENSOR_DELAY_FASTEST(0)微秒 设置传感器的原则: 尽量使用比较低的传感器采样率,这样系统的负荷比较小,同时可以省电 2.传感器的属性 1)传感器的名称 2)传感器制造商 3)传感器gonglv 4)传感器的resulotion; MainActivity: 1 package org.gaolei.sensor03; 2 3 import android.app.Activity; 4 import android.content.Context; 5 import android.hardware.Sensor; 6 import android.hardware.SensorEvent; 7 import android.hardware.SensorEventListener; 8 import android.hardware.SensorManager; 9 import android.os.Bundle; 10 11 public class MainActivity extends Activity { 12 private SensorManager sensorManager; 13 14 @Override 15 public void onCreate(Bundle savedInstanceState) { 16 super.onCreate(savedInstanceState); 17 setContentView(R.layout.main); 18 19 sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); 20 Sensor lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); 21 22 sensorManager.registerListener(new SensorEventListener() { 23 24 @Override 25 public void onSensorChanged(SensorEvent event) { 26 String sensorName = event.sensor.getName(); 27 String sensorVendor = event.sensor.getVendor(); 28 float resolution = event.sensor.getResolution(); 29 float power = event.sensor.getPower(); 30 double timestamp = event.timestamp; 31 32 System.out.println("sensor name--->" + sensorName); 33 System.out.println("sensor vendor--->" + sensorVendor); 34 System.out.println("sensor resolution--->" + resolution); 35 System.out.println("sensor power--->" + power); 36 System.out.println("sensor timestamp--->" + timestamp); 37 38 } 39 40 @Override 41 public void onAccuracyChanged(Sensor sensor, int accuracy) { 42 } 43 }, lightSensor, SensorManager.SENSOR_DELAY_GAME); 44 } 45 }
注册传感器 public boolean registerListener(SensorEventListener, Sensor sensor, int rate) MainActivity: package org.gaolei.sensor02; import android.app.Activity; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; public class MainActivity extends Activity { // 声明一个SensorManager对象 private SensorManager sensorManager; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 获取SensorManager对象 sensorManager = (SensorManager) getSystemService(Context.SEARCH_SERVICE); // 获取光线传感器对象 Sensor lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); // 注册传感器 sensorManager.registerListener(new SensorEventListener() { @Override public void onSensorChanged(SensorEvent event) { float acc = event.accuracy; float lux = event.values[0]; System.out.println("acc---->" + acc); System.out.println("lux---->" + lux); } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } }, lightSensor, SensorManager.SENSOR_DELAY_NORMAL); } }
摘要: 1.什么是WIFI
Wi-Fi 原先是无线保真的缩写,Wi-Fi 的英文全称为wireless fidelity,读音为waifai(拼音读法,均为一声),英文音标/ˈwaɪfaɪ/, wireless [英][ˈwaɪəlɪs] fidelity[英] [fiˈ... 阅读全文
传感器的种类1.动作传感器 加速度传感器、重力传感器和陀螺仪传感器等 2.位置传感器 方向传感器和磁力传感器 3.环境传感器 温度传感器、压力传感器和亮度传感器等 使用传感器的方法 1.获取SensorManager对象; 2.执行SensorManager对象的getDefaultSensor()方法获取Sensor对象; 3.获取Sensor对象的各种属性; main.xml:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" 5 android:orientation="vertical" > 6 7 <Button 8 android:id="@+id/sensorButton" 9 android:layout_width="fill_parent" 10 android:layout_height="wrap_content" 11 android:text="@string/sensorButton" /> 12 13 </LinearLayout> strings.xml:
1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 4 <string name="hello">Hello World, MainActivity!</string> 5 <string name="app_name">05_01_sensor01</string> 6 <string name="sensorButton">获取当前设备所支持的传感器</string> 7 8 </resources> MainActivity.java:
1 package org.gaolei.sensor01; 2 3 import java.util.List; 4 5 import android.app.Activity; 6 import android.content.Context; 7 import android.hardware.Sensor; 8 import android.hardware.SensorManager; 9 import android.os.Bundle; 10 import android.view.View; 11 import android.widget.Button; 12 13 public class MainActivity extends Activity { 14 private Button sensorButton; 15 16 // SensorManager用于管理手机当中所有的传感器对象 17 private SensorManager sensorManager; 18 19 @Override 20 public void onCreate(Bundle savedInstanceState) { 21 super.onCreate(savedInstanceState); 22 setContentView(R.layout.main); 23 24 // 得到SensorManager对象 25 sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); 26 27 sensorButton = (Button) findViewById(R.id.sensorButton); 28 sensorButton.setOnClickListener(new OnClicklistener()); 29 } 30 31 private final class OnClicklistener implements View.OnClickListener { 32 33 @Override 34 public void onClick(View v) { 35 36 // 通过调用getSensorList方法,得到当前手机当中所有的传感器 37 List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL); 38 39 for (Sensor sensor : sensors) { 40 // System.out.println(sensor.getMaximumRange()); 41 // System.out.println(sensor.getMinDelay()); 42 System.out.println(sensor.getName()); 43 // System.out.println(sensor.getPower()); 44 // System.out.println(sensor.getResolution()); 45 // System.out.println(sensor.getType()); 46 // System.out.println(sensor.getVendor()); 47 // System.out.println(sensor.getVersion()); 48 49 // 通过调用getDefaultSensor方法。获取某一类型的默认传感器 50 // Sensor sensor = 51 // sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); 52 } 53 54 } 55 56 } 57 }
在Android中上传文件可以采用HTTP方式,也可以采用Socket方式,但是HTTP方式不能上传大文件,这里介绍一种通过Socket方式来进行断点续传的方式,服务端会记录下文件的上传进度,当某一次上传过程意外终止后,下一次可以继续上传,这里用到的其实还是J2SE里的知识。 这个上传程序的原理是:客户端第一次上传时向服务端发送“Content-Length=35;filename=WinRAR_3.90_SC.exe;sourceid=“这种格式的字符串,服务端收到后会查找该文件是否有上传记录,如果有就返回已经上传的位置,否则返回新生成的sourceid以及position为0,类似”sourceid=2324838389;position=0“这样的字符串,客户端收到返回后的字符串后再从指定的位置开始上传文件。
摘要: 使用多线程断点续传下载器在下载的时候多个线程并发可以占用服务器端更多资源, 从而加快下载速度,在下载过程中记录每个线程已拷贝数据的数量,如果下载中断,比如无信号断线、电量不足等情况下,这就需要使用到断点续传功能,下次启动 时从记录位置继续下载,可避免重复部分的下载。这里采用数据库来记录下载的进度。
断点续传
1.... 阅读全文
基本原理:利用HttpsURLConnection获取要下载文件的长度、头部等相关信息,并设置响应的头部信息。并且通过HttpsURLConnection获取输入流,将文件分成指定的块,每一块单独开辟一个线程完成数据的读取、写入。通过输入流读取下载文件的信息,然后将读取的信息用RandomAccessFile随机写入到本地文件中。同时,每个线程写入的数据都文件指针也就是写入数据的长度,需要保存在一个临时文件中。这样当本次下载没有完成的时候,下次下载的时候就从这个文件中读取上一次下载的文件长度,然后继续接着上一次的位置开始下载。并且将本次下载的长度写入到这个文件中。 1 package com.gaolei.download; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.RandomAccessFile; 7 import java.net.URL; 8 9 import javax.net.ssl.HttpsURLConnection; 10 11 public class MulThreadDownload { 12 13 public static void main(String[] args) throws Exception { 14 String path = "http://192.168.0.1/videonews/QQWubiSetup.exe"; 15 new MulThreadDownload().download(path, 3); 16 } 17 18 /** 19 * 下载文件 20 * 21 * @param path网络文件路径 22 * @throws Exception 23 */ 24 private void download(String path, int threadsize) throws Exception { 25 URL url = new URL(path); 26 HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); 27 conn.setConnectTimeout(5000); 28 conn.setRequestMethod("GET"); 29 if (conn.getResponseCode() == 200) { 30 int length = conn.getContentLength(); // 获取网络文件的长度 31 File file = new File(getFilename(path)); 32 RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");// 在本地生成一个长度相等的文件 33 accessFile.setLength(length); 34 accessFile.close(); 35 36 // 计算每条线程负责下载的数据量 37 int block = length % threadsize == 0 ? length / threadsize : length 38 / threadsize + 1; 39 for (int threadid = 0; threadid < threadsize; threadid++) { 40 new DownloadThread(threadid, block, url, file).start(); 41 } 42 } else { 43 System.out.println("下载失败!"); 44 } 45 46 } 47 48 private class DownloadThread extends Thread { 49 50 private int threadid; 51 private int block; 52 private URL url; 53 private File file; 54 55 public DownloadThread(int threadid, int block, URL url, File file) { 56 this.threadid = threadid; 57 this.block = block; 58 this.url = url; 59 this.file = file; 60 } 61 62 @Override 63 public void run() { 64 int start = threadid * block; // 计算该线程从网络文件的什么位置开始下载 65 int end = (threadid + 1) * block - 1; // 下载到网络文件的什么位置结束 66 67 try { 68 RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");// 在本地生成一个长度相等的文件 69 accessFile.seek(start); 70 HttpsURLConnection conn = (HttpsURLConnection) url 71 .openConnection(); 72 conn.setConnectTimeout(5000); 73 conn.setRequestMethod("GET"); 74 conn.setRequestProperty("Range", "bytes=" + start + "-" + end); 75 if (conn.getResponseCode() == 206) { 76 InputStream inStream = conn.getInputStream(); 77 byte[] buffer = new byte[1024]; 78 int len = 0; 79 while ((len = inStream.read(buffer)) != -1) { 80 accessFile.write(buffer, 0, len); 81 } 82 accessFile.close(); 83 inStream.close(); 84 } 85 System.out.println("第" + (threadid + 1) + "条线程已经下载完成!"); 86 } catch (IOException e) { 87 e.printStackTrace(); 88 } 89 90 } 91 92 } 93 94 private String getFilename(String path) { 95 return path.substring(path.lastIndexOf("/") + 1); 96 } 97 } 98
使用SQLiteDatabase的beginTransaction()方法可以开启一个事务,程序执行到endTransaction() 方法时会检查事务的标志是否为成功,如果为成功则提交事务,否则回滚事务。当应用需要提交事务,必须在程序执行到endTransaction()方法之前使用setTransactionSuccessful() 方法设置事务的标志为成功,如果不调用setTransactionSuccessful() 方法,默认会回滚事务。
使用例子如下: 1 SQLiteDatabase db = .; 2 db.beginTransaction();//开始事务 3 try { 4 db.execSQL("insert into person(name, age) values(?,?)", new Object[]{"gaolei", 22}); 5 db.execSQL("update person set name=? where personid=?", new Object[]{"zhangsan", 1}); 6 db.setTransactionSuccessful();//调用此方法会在执行到endTransaction() 时提交当前事务,如果不调用此方法会回滚事务 7 } finally { 8 db.endTransaction();//由事务的标志决定是提交事务,还是回滚事务 9 } 10 db.close();
上面两条SQL语句在同一个事务中执行。
使用嵌入式关系型SQLite数据库存储数据 除了可以使用文件或SharedPreferences存储数据,还可以选择使用SQLite数据库存储数据。 在Android平台上,集成了一个嵌入式关系型数据库—SQLite,SQLite3支持 NULL、INTEGER、REAL(浮点数字)、TEXT(字符串文本)和BLOB(二进制对象)数据类型,虽然它支持的类型虽然只有五种,但实际上sqlite3也接受varchar(n)、char(n)、decimal(p,s) 等数据类型,只不过在运算或保存时会转成对应的五种数据类型。 SQLite最大的特点是你可以保存任何类型的数据到任何字段中,无论这列声明的数据类型是什么。例如:可以在Integer字段中存放字符串,或者在布尔型字段中存放浮点数,或者在字符型字段中存放日期型值。 但有一种情况例外:定义为INTEGER PRIMARY KEY的字段只能存储64位整数, 当向这种字段中保存除整数以外的数据时,将会产生错误。 另外, SQLite 在解析CREATE TABLE 语句时,会忽略 CREATE TABLE 语句中跟在字段名后面的数据类型信息,如下面语句会忽略 name字段的类型信息: CREATE TABLE person (personid integer primary key autoincrement, name varchar(20))
SQLite可以解析大部分标准SQL语句,如: 查询语句:select * from 表名 where 条件子句 group by 分组字句 having ... order by 排序子句 如:select * from person select * from person order by id desc select name from person group by name having count(*)>1 分页SQL与mysql类似,下面SQL语句获取5条记录,跳过前面3条记录 select * from Account limit 5 offset 3 或者 select * from Account limit 3,5 插入语句:insert into 表名(字段列表) values(值列表)。如: insert into person(name, age) values(‘传智’,3) 更新语句:update 表名 set 字段名=值 where 条件子句。如:update person set name=‘传智‘ where id=10 删除语句:delete from 表名 where 条件子句。如:delete from person where id=10
Android提供了一个名为SQLiteDatabase的类,该类封装了一些操作数据库的API,使用该类可以完成对数据进行添加(Create)、查询(Retrieve)、更新(Update)和删除(Delete)操作(这些操作简称为CRUD)。对SQLiteDatabase的学习,我们应该重点掌握execSQL()和rawQuery()方法。 execSQL()方法可以执行insert、delete、update和CREATE TABLE之类有更改行为的SQL语句; rawQuery()方法可以执行select语句。 execSQL()方法的使用例子: SQLiteDatabase db = ....; db.execSQL("insert into person(name, age) values('传智播客', 4)"); db.close(); 执行上面SQL语句会往person表中添加进一条记录,在实际应用中, 语句中的“传智播客”这些参数值应该由用户输入界面提供,如果把用户输入的内容原样组拼到上面的insert语句, 当用户输入的内容含有单引号时,组拼出来的SQL语句就会存在语法错误。要解决这个问题需要对单引号进行转义,也就是把单引号转换成两个单引号。有些时候用户往往还会输入像“ & ”这些特殊SQL符号,为保证组拼好的SQL语句语法正确,必须对SQL语句中的这些特殊SQL符号都进行转义,显然,对每条SQL语句都做这样的处理工作是比较烦琐的。 SQLiteDatabase类提供了一个重载后的execSQL(String sql, Object[] bindArgs)方法,使用这个方法可以解决前面提到的问题,因为这个方法支持使用占位符参数(?)。使用例子如下: SQLiteDatabase db = ....; db.execSQL("insert into person(name, age) values(?,?)", new Object[]{"传智播客", 4}); db.close(); execSQL(String sql, Object[] bindArgs)方法的第一个参数为SQL语句,第二个参数为SQL语句中占位符参数的值,参数值在数组中的顺序要和占位符的位置对应。
SQLiteDatabase的rawQuery() 用于执行select语句,使用例子如下: SQLiteDatabase db = ....; Cursor cursor = db.rawQuery(“select * from person”, null); while (cursor.moveToNext()) { int personid = cursor.getInt(0); //获取第一列的值,第一列的索引从0开始 String name = cursor.getString(1);//获取第二列的值 int age = cursor.getInt(2);//获取第三列的值 } cursor.close(); db.close(); rawQuery()方法的第一个参数为select语句;第二个参数为select语句中占位符参数的值,如果select语句没有使用占位符,该参数可以设置为null。带占位符参数的select语句使用例子如下: Cursor cursor = db.rawQuery("select * from person where name like ? and age=?", new String[]{"%传智%", "4"});
Cursor是结果集游标,用于对结果集进行随机访问,如果大家熟悉jdbc, 其实Cursor与JDBC中的ResultSet作用很相似。使用moveToNext()方法可以将游标从当前行移动到下一行,如果已经移过了结果集的最后一行,返回结果为false,否则为true。另外Cursor 还有常用的moveToPrevious()方法(用于将游标从当前行移动到上一行,如果已经移过了结果集的第一行,返回值为false,否则为true )、moveToFirst()方法(用于将游标移动到结果集的第一行,如果结果集为空,返回值为false,否则为true )和moveToLast()方法(用于将游标移动到结果集的最后一行,如果结果集为空,返回值为false,否则为true ) 。
除了前面给大家介绍的execSQL()和rawQuery()方法, SQLiteDatabase还专门提供了对应于添加、删除、更新、查询的操作方法: insert()、delete()、update()和query() 。这些方法实际上是给那些不太了解SQL语法的菜鸟使用的,对于熟悉SQL语法的程序员而言,直接使用execSQL()和rawQuery()方法执行SQL语句就能完成数据的添加、删除、更新、查询操作。 Insert()方法用于添加数据,各个字段的数据使用ContentValues进行存放。 ContentValues类似于MAP,相对于MAP,它提供了存取数据对应的put(String key, Xxx value)和getAsXxx(String key)方法, key为字段名称,value为字段值,Xxx指的是各种常用的数据类型,如:String、Integer等。 SQLiteDatabase db = databaseHelper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("name", "传智播客"); values.put("age", 4); long rowid = db.insert(“person”, null, values);//返回新添记录的行号,与主键id无关 不管第三个参数是否包含数据,执行Insert()方法必然会添加一条记录,如果第三个参数为空,会添加一条除主键之外其他字段值为Null的记录。Insert()方法内部实际上通过构造insert语句完成数据的添加,Insert()方法的第二个参数用于指定空值字段的名称,相信大家对此参数会感到疑惑,此参数的作用是干嘛的?是这样的:如果第三个参数values 为Null或者元素个数为0, Insert()方法必然要添加一条除了主键之外其它字段为Null值的记录,为了满足这条insert语句的语法, insert语句必须给定一个字段名,如:insert into person(name) values(NULL),倘若不给定字段名 , insert语句就成了这样: insert into person() values(),显然这不满足标准SQL的语法。对于字段名,建议使用主键之外的字段,如果使用了INTEGER类型的主键字段,执行类似insert into person(personid) values(NULL)的insert语句后,该主键字段值也不会为NULL。如果第三个参数values 不为Null并且元素的个数大于0 ,可以把第二个参数设置为null。
delete()方法的使用: SQLiteDatabase db = databaseHelper.getWritableDatabase(); db.delete("person", "personid<?", new String[]{"2"}); db.close(); 上面代码用于从person表中删除personid小于2的记录。
update()方法的使用: SQLiteDatabase db = databaseHelper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(“name”, “传智播客”);//key为字段名,value为值 db.update("person", values, "personid=?", new String[]{"1"}); db.close(); 上面代码用于把person表中personid等于1的记录的name字段的值改为“传智播客”。
query()方法实际上是把select语句拆分成了若干个组成部分,然后作为方法的输入参数: SQLiteDatabase db = databaseHelper.getWritableDatabase(); Cursor cursor = db.query("person", new String[]{"personid,name,age"}, "name like ?", new String[]{"%传智%"}, null, null, "personid desc", "1,2"); while (cursor.moveToNext()) { int personid = cursor.getInt(0); //获取第一列的值,第一列的索引从0开始 String name = cursor.getString(1);//获取第二列的值 int age = cursor.getInt(2);//获取第三列的值 } cursor.close(); db.close(); 上面代码用于从person表中查找name字段含有“传智”的记录,匹配的记录按personid降序排序,对排序后的结果略过第一条记录,只获取2条记录。 query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit)方法各参数的含义: table:表名。相当于select语句from关键字后面的部分。如果是多表联合查询,可以用逗号将两个表名分开。 columns:要查询出来的列名。相当于select语句select关键字后面的部分。 selection:查询条件子句,相当于select语句where关键字后面的部分,在条件子句允许使用占位符“?” selectionArgs:对应于selection语句中占位符的值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常。 groupBy:相当于select语句group by关键字后面的部分 having:相当于select语句having关键字后面的部分 orderBy:相当于select语句order by关键字后面的部分,如:personid desc, age asc; limit:指定偏移量和获取的记录数,相当于select语句limit关键字后面的部分。 如果应用使用到了SQLite数据库,在用户初次使用软件时,需要创建应用使用到的数据库表结构及添加一些初始化记录,另外在软件升级的时候,也需要对数据表结构进行更新。在Android系统,为我们提供了一个名为SQLiteOpenHelper的类,该类用于对数据库版本进行管理,该类是一个抽象类,必须继承它才能使用。 为了实现对数据库版本进行管理,SQLiteOpenHelper类有两种重要的方法,分别是onCreate(SQLiteDatabase db)和onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
当调用SQLiteOpenHelper的getWritableDatabase()或者getReadableDatabase()方法获取用于操作数据库的SQLiteDatabase实例的时候,如果数据库不存在,Android系统会自动生成一个数据库,接着调用onCreate()方法,onCreate()方法在初次生成数据库时才会被调用,在onCreate()方法里可以生成数据库表结构及添加一些应用使用到的初始化数据。onUpgrade()方法在数据库的版本发生变化时会被调用,数据库的版本是由程序员控制的,假设数据库现在的版本是1,由于业务的需要,修改了数据库表的结构,这时候就需要升级软件,升级软件时希望更新用户手机里的数据库表结构,为了实现这一目的,可以把原来的数据库版本设置为2(有同学问设置为3行不行?当然可以,如果你愿意,设置为100也行),并且在onUpgrade()方法里面实现表结构的更新。当软件的版本升级次数比较多,这时在onUpgrade()方法里面可以根据原版号和目标版本号进行判断,然后作出相应的表结构及数据更新。
getWritableDatabase()和getReadableDatabase()方法都可以获取一个用于操作数据库的SQLiteDatabase实例。但getWritableDatabase() 方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若使用的是getWritableDatabase() 方法就会出错。getReadableDatabase()方法先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。
使用SQLiteOpenHelper对数据库进行版本管理 public class DatabaseHelper extends SQLiteOpenHelper { //类没有实例化,是不能用作父类构造器的参数,必须声明为静态 private static final String name = "itcast"; //数据库名称 private static final int version = 1; //数据库版本 public DatabaseHelper(Context context) { //第三个参数CursorFactory指定在执行查询时获得一个游标实例的工厂类,设置为null,代表使用系统默认的工厂类 super(context, name, null, version); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE IF NOT EXISTS person (personid integer primary key autoincrement, name varchar(20), age INTEGER)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS person"); onCreate(db); } } 上面onUpgrade()方法在数据库版本每次发生变化时都会把用户手机上的数据库表删除,然后再重新创建。一般在实际项目中是不能这样做的,正确的做法是在更新数据库表结构时,还要考虑用户存放于数据库中的数据不会丢失。
public class DatabaseHelper extends SQLiteOpenHelper { private static final String name = "itcast"; //数据库名称 private static final int version = 1; //数据库版本 ......略 } public class HelloActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { ...... Button button =(Button) this.findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener(){ public void onClick(View v) { DatabaseHelper databaseHelper = new DatabaseHelper(HelloActivity.this); SQLiteDatabase db = databaseHelper.getWritableDatabase(); db.execSQL("insert into person(name, age) values(?,?)", new Object[]{"传智播客", 4}); db.close(); }}); } } 第一次调用getWritableDatabase()或getReadableDatabase()方法后,SQLiteOpenHelper会缓存当前的SQLiteDatabase实例,SQLiteDatabase实例正常情况下会维持数据库的打开状态,所以在你不再需要SQLiteDatabase实例时,请及时调用close()方法释放资源。一旦SQLiteDatabase实例被缓存,多次调用getWritableDatabase()或getReadableDatabase()方法得到的都是同一实例。
很多时候我们开发的软件需要向用户提供软件参数设置功能,例如我们常用的QQ,用户可以设置是否允许陌生人添加自己为好友。对于软件配置参数的保存,如果是window软件通常我们会采用ini文件进行保存,如果是j2se应用,我们会采用properties属性文件进行保存。如果是Android应用,我们最适合采用什么方式保存软件配置参数呢?Android平台给我们提供了一个SharedPreferences类,它是一个轻量级的存储类,特别适合用于保存软件配置参数。使用SharedPreferences保存数据,其背后是用xml文件存放数据,文件存放在/data/data/<package name>/shared_prefs目录下: SharedPreferences sharedPreferences = getSharedPreferences("gaolei", Context.MODE_PRIVATE); Editor editor = sharedPreferences.edit();//获取编辑器 editor.putString("name", "高磊"); editor.putInt("age", 4); editor.commit();//提交修改
生成的gaolei.xml文件内容如下: 1 <?xml version='1.0' encoding='utf-8' standalone='yes' ?> 2 <map> 3 <string name="name">高磊</string> 4 <int name="age" value="4" /> 5 </map> 因为SharedPreferences背后是使用xml文件保存数据,getSharedPreferences(name,mode)方法的第一个参数用于指定该文件的名称,名称不用带后缀,后缀会由Android自动加上。方法的第二个参数指定文件的操作模式,共有四种操作模式,这四种模式前面介绍使用文件方式保存数据时已经讲解过。如果希望SharedPreferences背后使用的xml文件能被其他应用读和写,可以指定Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE权限。 另外Activity还提供了另一个getPreferences(mode)方法操作SharedPreferences,这个方法默认使用当前类不带包名的类名作为文件的名称。 访问SharedPreferences中的数据 访问SharedPreferences中的数据代码如下: SharedPreferences sharedPreferences = getSharedPreferences("gaolei", Context.MODE_PRIVATE); //getString()第二个参数为缺省值,如果preference中不存在该key,将返回缺省值 String name = sharedPreferences.getString("name", ""); int age = sharedPreferences.getInt("age", 1); 如果访问其他应用中的Preference,前提条件是:该preference创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE权限。如:有个<package name>为cn.itcast.action的应用使用下面语句创建了preference。 getSharedPreferences("gaolei", Context.MODE_WORLD_READABLE); 其他应用要访问上面应用的preference,首先需要创建上面应用的Context,然后通过Context 访问preference ,访问preference时会在应用所在包下的shared_prefs目录找到preference : Context otherAppsContext = createPackageContext("com.gaolei.action", Context.CONTEXT_IGNORE_SECURITY); SharedPreferences sharedPreferences = otherAppsContext.getSharedPreferences("gaolei", Context.MODE_WORLD_READABLE); String name = sharedPreferences.getString("name", ""); int age = sharedPreferences.getInt("age", 0); 如果不通过创建Context访问其他应用的preference,可以以读取xml文件方式直接访问其他应用preference对应的xml文件,如: File xmlFile = new File(“/data/data/<package name>/shared_prefs/gaolei.xml”);//<package name>应替换成应用的包名
摘要: Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> 除了可以使用 SAX和DOM解析XML文件,大家也可以使用Android内置的Pull解析器解析XML文件。 Pull解析器的运行方式与 SAX 解析器... 阅读全文
使用Activity的openFileOutput()方法保存文件,文件是存放在手机空间上,一般手机的存储空间不是很大,存放些小文件还行,如果要存放像视频这样的大文件,是不可行的。对于像视频这样的大文件,我们可以把它存放在SDCard。 SDCard是干什么的?你可以把它看作是移动硬盘或U盘。 在模拟器中使用SDCard,你需要先创建一张SDCard卡(当然不是真的SDCard,只是镜像文件)。创建SDCard可以在Eclipse创建模拟器时随同创建,也可以使用DOS命令进行创建,如下: 在Dos窗口中进入android SDK安装路径的tools目录,输入以下命令创建一张容量为2G的SDCard,文件后缀可以随便取,建议使用.img: mksdcard 2048M D:\AndroidTool\sdcard.img 要往SDCard存放文件,程序必须先判断手机是否装有SDCard,并且可以进行读写。 注意:访问SDCard必须在AndroidManifest.xml中加入访问SDCard的权限 if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ File sdCardDir = Environment.getExternalStorageDirectory();//获取SDCard目录 File saveFile = new File(sdCardDir, “gaolei.txt”); FileOutputStream outStream = new FileOutputStream(saveFile); outStream.write("abc".getBytes()); outStream.close(); } Environment.getExternalStorageState()方法用于获取SDCard的状态,如果手机装有SDCard,并且可以进行读写,
那么方法返回的状态等于Environment.MEDIA_MOUNTED。 Environment.getExternalStorageDirectory()方法用于获取SDCard的目录,当然要获取SDCard的目录,你也可以这样写: File sdCardDir = new File("/mnt/sdcard"); //获取SDCard目录 File saveFile = new File(sdCardDir, "gaolei.txt"); //上面两句代码可以合成一句: File saveFile = new File("/mnt/sdcard/gaolei.txt"); FileOutputStream outStream = new FileOutputStream(saveFile); outStream.write("abc".getBytes()); outStream.close();
摘要: 数据存储与访问
很多时候我们开发的软件需要对处理后的数据进行访问,以供再次访问。
Android为数据存储提供了如下几种方式:
文件
SharedPreferences(参数)
SQLite函数库
内容提供者(Content provider)
网络
界面:
main.xml
Code highlighting pro... 阅读全文
JUnit 是一个可用于执行软件单元测试的程序,它使用一组用 Java 编写的测试用例实现这种测试。JUnit 的一般用法是创建一组单元测试,对软件进行更改时,这组单元测试可以自动运行。这样,开发人员可以确保对他们正在创建的软件所做的改动不会破坏软件以前实 现的功能。JUnit 甚至还提供了一种被称作测试驱动开发 (TDD) 的开发方法,该方法主张甚至在编写某个软件之前先编写测试它的单元测试。JUnit 还提供了一个测试运行器,能够运行单元测试并报告测试是否成功。
阅读有关 JUnit 的资料时可能遇到的一些常用术语包括:
- 测试方法: Java 类中的一个方法,它包含一个单元测试。
- 测试类: 包含一个或多个测试方法的 Java 类。
- 断言: 您在测试方法中包括的一条语句,用于检查测试结果是否如预期的那样。
- 测试固件 (Test Fixture): 用于设置多个测试的状态的类;通常在设置例程“代价高昂”或执行时间过长时使用。
- 测试套件: 一起运行的一组测试类。
1 <?xml version="1.0" encoding="utf-8"?>
2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3 package="com.gaolei.juint"
4 android:versionCode="1"
5 android:versionName="1.0" >
6
7 <uses-sdk android:minSdkVersion="15" />
8
9 <application
10 android:icon="@drawable/ic_launcher"
11 android:label="@string/app_name" >
12 <activity
13 android:name=".JunitestActivity"
14 android:label="@string/app_name" >
15 <intent-filter>
16 <action android:name="android.intent.action.MAIN" />
17
18 <category android:name="android.intent.category.LAUNCHER" />
19 </intent-filter>
20 </activity>
21
22 <uses-library android:name="android.test.runner"/>
23 </application>
24 <instrumentation android:name="android.test.InstrumentationTestRunner"
25 android:targetPackage="com.gaolei.juint" android:label="Tests for My Apps">
26 </instrumentation>
27
28 </manifest>
1 package com.gaolei.test;
2
3 import junit.framework.Assert;
4
5 import com.gaolei.service.PersonService;
6
7 import android.test.AndroidTestCase;
8
9 public class PersonServiceTest extends AndroidTestCase {
10
11 public void testSave() throws Exception {
12 PersonService personService = new PersonService();
13 personService.save(null);
14 }
15
16 public void testAdd() throws Exception {
17 PersonService personService = new PersonService();
18 int actual = personService.add(1, 2);
19 Assert.assertEquals(3, actual);
20 }
21 }
22
1 package com.gaolei.test;
2
3 import junit.framework.Assert;
4
5 import com.gaolei.service.PersonService;
6
7 import android.test.AndroidTestCase;
8
9 public class PersonServiceTest extends AndroidTestCase {
10
11 public void testSave() throws Exception {
12 PersonService personService = new PersonService();
13 personService.save(null);
14 }
15
16 public void testAdd() throws Exception {
17 PersonService personService = new PersonService();
18 int actual = personService.add(1, 2);
19 Assert.assertEquals(3, actual);
20 }
21 }
22
布局介绍
Android布局是应用界面开发的重要一环,在Android中,共有四种布局方式,
分别是:FrameLayout( 帧布局 )、LinearLayout (线性布局)、TableLayout(表格布局)、RelativeLayout(相对布局)。
1.LinearLayout
线性布局LinearLayout 在单一方向上对齐所有的子视图-竖向或者横向,这依赖于你怎么定义方向orientation 属性。所有子视图依次堆积,所以一个竖向列表每行只有一个子视图,不管它们有多宽,而一个横向列表将只有一行高(最高子视图的高度,加上填充)。一个线性布局LinearLayout 会考虑子视图之间的边缘空白margins以及每个子视图的引力属性(靠右,居中,或者靠左)。
2.RelativeLayout
相对布局RelativeLayout允许子视图指定它们和父视图或彼此之间的相对位置(通过ID指定)。因此你可以按正确的顺序对齐两个元素,或者让一个视图在另外一个下面,居于屏幕中间,左边的中间,等等。元素通过给定顺序来绘制,因此如果这第一个元素在屏幕中间,其他以它对齐的元素都会对齐到屏幕中间。同样,因为这个顺序,如果使用XML来指定这个布局,你将引用的元素(为了定位其它视图对象)必须被列在XML文件中,在你通过引用ID从其他视图中引用它之前。
其中一些特性直接由元素支持,另外一些由它的LayoutParams成员变量支持(为所有这个屏幕中的元素子类化RelativeLayout,因为所有元素都是RelativeLayout父对象的子元素)。已定义的相对布局RelativeLayout参数是:width,height,below,alignTop,toLeft,padding[Bottom|Left|Right|Top],以及 margin[Bottom|Left|Right|Top]。注意其中一些参数明确支持相对布局位置-它们的数值必须是你的相对位置元素的ID。
1 <?xml version="1.0" encoding="utf-8"?>
2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="fill_parent"
4 android:layout_height="wrap_content"
5 android:background="@drawable/blue"
6 android:padding="10px" >
7
8 <TextView android:id="@+id/label"
9 android:layout_width="fill_parent"
10 android:layout_height="wrap_content"
11 android:text="Type here:" />
12
13 <EditText android:id="@+id/entry"
14 android:layout_width="fill_parent"
15 android:layout_height="wrap_content"
16 android:background="@android:drawable/editbox_background"
17 android:layout_below="@id/label" />
18
19 <Button android:id="@+id/ok"
20 android:layout_width="wrap_content"
21 android:layout_height="wrap_content"
22 android:layout_below="@id/entry"
23 android:layout_alignParentRight="true"
24 android:layout_marginLeft="10px"
25 android:text="OK" />
26
27 <Button android:layout_width="wrap_content"
28 android:layout_height="wrap_content"
29 android:layout_toLeftOf="@id/ok"
30 android:layout_alignTop="@id/ok"
31 android:text="Cancel" />
32 </RelativeLayout>
33
3.TableLayout
表格布局TableLayout把它的子视图定位到行和列中。表格布局容器不显示行,列和单元的边界线。表的列和最多行单元数一样多。一个表可以有空单元,但是单元不能像HTML里面那样跨列。
TableRow 对象是一个TableLayout的子视图(每个TableRow定义了表中的一个单独行)。每行有0或多个单元,可用任何其他视图定义。因此,行单元可能由各个视图对象组成,如ImageView或TextView对象。一个单元也可以是一个ViewGroup对象(比如,你可以嵌入另一个表布局作为一个单元)。
1 <?xml version="1.0" encoding="utf-8"?>
2 <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="fill_parent"
4 android:layout_height="fill_parent"
5 android:stretchColumns="1">
6 <TableRow>
7 <TextView
8 android:text="@string/table_layout_4_open"
9 android:padding="3dip" />
10 <TextView
11 android:text="@string/table_layout_4_open_shortcut"
12 android:gravity="right"
13 android:padding="3dip" />
14 </TableRow>
15
16 <TableRow>
17 <TextView
18 android:text="@string/table_layout_4_save"
19 android:padding="3dip" />
20 <TextView
21 android:text="@string/table_layout_4_save_shortcut"
22 android:gravity="right"
23 android:padding="3dip" />
24 </TableRow>
25 </TableLayout>
4.FrameLayout
FrameLayout是最简单的一个布局对象。它被定制为你屏幕上的一个空白备用区域,之后你可以在其中填充一个单一对象 — 比如,一张你要发布的图片。所有的子元素将会固定在屏幕的左上角;你不能为FrameLayout中的一个子元素指定一个位置。后一个子元素将会直接在前一个子元素之上进行覆盖填充,把它们部份或全部挡住(除非后一个子元素是透明的)。
main.xml
1 <?xml version="1.0" encoding="utf-8"?>
2 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="fill_parent"
4 android:layout_height="fill_parent">
5
6 <ImageView
7 android:layout_width="fill_parent"
8 android:layout_height="wrap_content"
9 android:src="@drawable/movie"
10 android:contentDescription="@string/movie"/>
11 <ImageView
12 android:layout_width="wrap_content"
13 android:layout_height="wrap_content"
14 android:src="@drawable/paly"
15 android:layout_gravity="center"
16 android:contentDescription="@string/play"/>
17 </FrameLayout>
string.xml 1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 4 <string name="hello">Hello World, FrameLayoutActivity!</string> 5 <string name="app_name">FrameLayout布局</string> 6 <string name="movie">复仇者联盟</string> 7 <string name="play">播放按钮</string> 8 9 </resources>
launch [lɔ:ntʃ, lɑ:ntʃ]- vt. 发射(导弹、火箭等);发起,发动;使…下水;启动
- vi. 开始;下水;起飞
- n. 发射;发行,投放市场;下水;汽艇
automatic [,ɔ:tə'mætik]- adj. 自动的;无意识的;必然的
- n. 自动机械;自动手枪
emulator ['emjuleitə] device [di'vais] APK AndroidPackage Android安装包(apk) SDK Software Development Kit, 软件开发工具包 activity [æk'tivəti] dependencies [di'pendənsiz] manifest ['mænifest]- vt. 证明,表明;显示
- vi. 显示,出现
- n. 载货单,货单;旅客名单
- adj. 显然的,明显的;明白的
layout ['leiaut] vertical ['və:tikəl] - adj. 垂直的,直立的;[解剖] 头顶的,顶点的
- n. 垂直线,垂直面
wrap [ræp]- vt. 包;缠绕;隐藏;掩护
- vi. 包起来;缠绕;穿外衣
- n. 外套;围巾
Dex Dalvik Executable Android Dalvik执行程序 AVD Android Virtual Device Android虚拟设备 intent [in'tent]- n. 意图;目的;含义
- adj. 专心的;急切的;坚决的
verbose [və:'bəus] assert [ə'sə:t]DDMS - Dalvik Debug Monitor Service Dalvik虚拟机调试监控服务
layout linear ['liniə] horizontal ['hɔri'zɔntəl]- adj. 水平的;地平线的;同一阶层的
- n. 水平线,水平面;水平位置
margin ['mɑ:dʒin] - n. 边缘;利润,余裕;页边的空白
- vt. 加边于;加旁注于
gravity ['ɡræviti]align [ə'lain]- vt. 使结盟;使成一行;匹配
- vi. 排列;排成一行
relative ['relətiv]- adj. 相对的;有关系的;成比例的
- n. 亲戚;相关物;[语] 关系词;亲缘植物
drawable ['drɔ:əbl]
一、查看应用输出的错误信息 Window->Show View ->Other->Android ->LogCat
在Android程序中可以使用 android.util.Log 类来输出日志信息,该类提供了下列几个静态方法
Log.v(String tag, String msg); Log.d(String tag, String msg); Log.i(String tag, String msg); Log.w(String tag, String msg); Log.e(String tag, String msg);
分别对应 verbose, debug, info, warn, error 另外还可以通过SDK提供的工具来看,命令是 adb logcat ,该命令执行后会以tail方式实时显示出所有的日志信息。
二、如何部署应用到真实手机 1)安装手机的驱动到pc上 2)用一条USB连接线把手机连接到PC的USB接口上 Window->Show View ->Other->Android ->Devices 3> 运行为android application,出现android device chooser界面,选择真实手机(如果没有启动模拟器的话,不会出现)。查看安装信息,在devices中双击设备。 4> 软件发布,供用户安装。把软件打包为apk文件。Export—>android application—>创建密钥—>安装文件放置位置—>完成。 5> 放入sd卡,在真机中用apk正常安装,安装时会提示(电话呼叫器)。 连上手机之前,打开devices视图,再连接手机,手机会出现在视图中。如果手机没出现,可能驱动没安装成功。 连接手机可以通过屏幕监视工具asm.jar进行操作。
摘要: "打电话"是每个手机必备的功能,虽然在Android平台上可以通过程序,进行各种让人目眩神迷的应用,但拨打电话这项最基本的功能,依然是每个Android工程师的必修课程。 在这个范例中,设计一个让用户输入电话号码的EditText,通过一个Button来实现拨打电话的练习。&n... 阅读全文
Android的系统架构和其操作系统一样,采用了分层的架构。从架构图看,android分为四个层,从高层到低层分别是应用程序层、应用程序框架层、系统运行库层和linux核心层。
1.应用程序
Android会同一系列核心应用程序包一起发布,该应用程序包包括email客户端,SMS短消息程序,日历,地图,浏览器,联系人管理程序等。所有的应用程序都是使用JAVA语言编写的。
2.应用程序框架
开发人员也可以完全访问核心应用程序所使用的API框架。该应用程序的架构设计简化了组件的重用;任何一个应用程序都可以发布它的功能块并且任何其它的 应用程序都可以使用其所发布的功能块(不过得遵循框架的安全性限制)。同样,该应用程序重用机制也使用户可以方便的替换程序组件。
隐藏在每个应用后面的是一系列的服务和系统, 其中包括;
* 丰富而又可扩展的视图(Views),可以用来构建应用程序, 它包括列表(lists),网格(grids),文本框(text boxes),按钮(buttons), 甚至可嵌入的web浏览器。
* 内容提供器(Content Providers)使得应用程序可以访问另一个应用程序的数据(如联系人数据库), 或者共享它们自己的数据
* 资源管理器(Resource Manager)提供 非代码资源的访问,如本地字符串,图形,和布局文件( layout files )。
* 通知管理器 (Notification Manager) 使得应用程序可以在状态栏中显示自定义的提示信息。
* 活动管理器( Activity Manager) 用来管理应用程序生命周期并提供常用的导航回退功能。
有关更多的细节和怎样从头写一个应用程序,请参考 如何编写一个 Android 应用程序. 3.系统运行库
1)程序库
Android 包含一些C/C++库,这些库能被Android系统中不同的组件使用。它们通过 Android 应用程序框架为开发者提供服务。以下是一些核心库:
* 系统 C 库 - 一个从 BSD 继承来的标准 C 系统函数库( libc ), 它是专门为基于 embedded linux 的设备定制的。
* 媒体库 - 基于 PacketVideo OpenCORE;该库支持多种常用的音频、视频格式回放和录制,同时支持静态图像文件。编码格式包括MPEG4, H.264, MP3, AAC, AMR, JPG, PNG 。
* Surface Manager - 对显示子系统的管理,并且为多个应用程序提 供了2D和3D图层的无缝融合。
* LibWebCore - 一个最新的web浏览器引擎用,支持Android浏览器和一个可嵌入的web视图。
* SGL - 底层的2D图形引擎
* 3D libraries - 基于OpenGL ES 1.0 APIs实现;该库可以使用硬件 3D加速(如果可用)或者使用高度优化的3D软加速。
* FreeType -位图(bitmap)和矢量(vector)字体显示。
* SQLite - 一个对于所有应用程序可用,功能强劲的轻型关系型数据库引擎。
2)Android 运行库
Android 包括了一个核心库,该核心库提供了JAVA编程语言核心库的大多数功能。
每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的Dalvik虚拟机实例。Dalvik被设计成一个设备可以同时高效地运行多个 虚拟系统。Dalvik虚拟机执行(.dex)的Dalvik可执行文件,该格式文件针对小内存使用做了优化。同时虚拟机是基于寄存器的,所有的类都经由JAVA编 译器编译,然后通过SDK中 的 "dx" 工具转化成.dex格式由虚拟机执行。
Dalvik虚拟机依赖于linux内核的一些功能,比如线程机制和底层内存管理机制。
4.Linux 内核
Android 的核心系统服务依赖于 Linux 2.6 内核,如安全性,内存管理,进程管理, 网络协议栈和驱动模型。 Linux 内核也同时作为硬件和软件栈之间的抽象层。
1. 请描述下Activity的生命周期。 2. 如果后台的Activity由于某原因被系统回收了,如何在被系统回收之前保存当前状态? 3. 如何将一个Activity设置成窗口的样式。(Edited by Sodino) 4. 如何退出Activity?如何安全退出已调用多个Activity的Application? 5. 请介绍下Android中常用的五种布局。 6. 请介绍下Android的数据存储方式。(Edited by Sodino) 7. 请介绍下ContentProvider是如何实现数据共享的。(Edited by Sodino) 8. 如何启用Service,如何停用Service。(Edited by Sodino) 9. 注册广播有几种方式,这些方式有何优缺点?请谈谈Android引入广播机制的用意。 10. 请解释下在单线程模型中Message、Handler、Message Queue、Looper之间的关系。 11. AIDL的全称是什么?如何工作?能处理哪些类型的数据? 12. 请解释下Android程序运行时权限与文件系统权限的区别。(Edited by Sodino) 13. 系统上安装了多种浏览器,能否指定某浏览器访问指定页面?请说明原由。 14. 有一个一维整型数组int[]data保存的是一张宽为width,高为height的图片像素值信息。请写一个算法,将该图片所有的白色不透明(0xffffffff)像素点的透明度调整为50%。 15. 你如何评价Android系统?优缺点。
1. 请描述下Activity的生命周期
http://weizhulin.blog.51cto.com/1556324/311495
详细介绍一下这几个方法中系统在做什么以及我们应该做什么:
onCreate: 在这里创建界面 ,做一些数据的初始化工作 onStart: 到这一步变成用户可见不可交互 的 onResume: 变成和用户可交互 的,(在activity 栈系统通过栈的方式管理这些个 Activity的最上面,运行完弹出栈,则回到上一个Activity) onPause: 到这一步是可见但不可交互 的,系统会停止动画 等消耗CPU 的事情 从上文的描述已经知道,应该在这里保存你的一些数据,因为这个时候 你的程序的优先级降低,有可能被系统收回。在这里保存的数据,应该在 onResume里读出来,注意:这个方法里做的事情时间要短,因为下一 个activity不会等到这个方法完成才启动 onstop: 变得不可见 ,被下一个activity覆盖了 onDestroy: 这是activity被干掉前最后一个被调用方法了,可能是外面类调用finish方 法或者是系统为了节省空间将它暂时性的干掉,可以用isFinishing()来判 断它,如果你有一个Progress Dialog在线程中转动,请在onDestroy里 把他cancel掉,不然等线程结束的时候,调用Dialog的cancel方法会抛 异常的。 onPause,onstop, onDestroy,三种状态 下 activity都有可能被系统干掉 为了保证程序的正确性,你要在onPause()里写上持久层操作的代码,将用户编辑的内容都保存到存储介质上(一般都是数据库)。实际工作中因为生命周期的变化而带来的问题也很多,比如你的应用程序起了新的线程在跑,这时候中断了,你还要去维护那个线程,是暂停还是杀掉还是数据回滚,是吧?因为Activity可能被杀掉,所以线程中使用的变量和一些界面元素就千万要注意了,一般我都是采用Android的消息机制 [Handler,Message]来处理多线程和界面交互的问题。这个我后面会讲一些,最近因为这些东西头已经很大了,等我理清思绪再跟大家分享。 2. 如果后台的Activity由于某原因被系统回收了,如何在被系统回收之前保存当前状态? 当你的程序中某一个Activity A 在运行时中,主动或被动地运行另一个新的Activity B
这个时候A会执行
Java代码
- public
- void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putLong("id", 1234567890);
- }
- public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState);outState.putLong("id", 1234567890);}
B 完成以后又会来找A, 这个时候就有两种情况,一种是A被回收,一种是没有被回收,被回 收的A就要重新调用onCreate()方法,不同于直接启动的是这回onCreate()里是带上参数 savedInstanceState,没被收回的就还是onResume就好了。
savedInstanceState是一个Bundle对象,你基本上可以把他理解为系统帮你维护的一个Map对象。在onCreate()里你可能会用到它,如果正常启动onCreate就不会有它,所以用的时候要判断一下是否为空。 Java代码 if(savedInstanceState != null){ long id = savedInstanceState.getLong("id"); }
if(savedInstanceState != null){ long id = savedInstanceState.getLong("id");} 就像官方的Notepad教程里的情况,你正在编辑某一个note,突然被中断,那么就把这个note的id记住,再起来的时候就可以根据这个id去把那个note取出来,程序就完整一些。这也是看你的应用需不需要保存什么,比如你的界面就是读取一个列表,那就不需要特殊记住什么,哦,没准你需要记住滚动条的位置...
3. 如何将一个Activity设置成窗口的样式
简单你只需要设置 一下Activity的主题就可以了在AndroidManifest.xml 中定义 Activity的 地方一句话: Xml代码
- android :theme="@android:style/Theme.Dialog"
- android:theme="@android:style/Theme.Dialog"
这就使你的应用程序变成对话框的形式弹出来了,或者
Xml代码
- android:theme="@android:style/Theme.Translucent"
- android:theme="@android:style/Theme.Translucent"
就变成半透明的,[友情提示-.-]类似的这种activity的属性可以在android.R.styleable 类的AndroidManifestActivity 方法中看到,AndroidManifest.xml中所有元素的属性的介绍都可以参考这个类android.R.styleable 上面说的是属性名称,具体有什么值是在android.R.style中可以看到,比如这个"@android:style/Theme.Dialog" 就对应于android.R.style.Theme_Dialog ,('_'换成'.' <--注意:这个是文章内容不是笑脸)就可以用在描述文件中了,找找类定义和描述文件中的对应关系就都明白了。 4. 如何退出Activity 对于单一Activity的应用来说,退出很简单,直接finish()即可。
当然,也可以用killProcess()和System.exit()这样的方法。
现提供几个方法,供参考:
1、抛异常强制退出:
该方法通过抛异常,使程序Force Close。
验证可以,但是,需要解决的问题是,如何使程序结束掉,而不弹出Force Close的窗口。
2、记录打开的Activity:
每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。
3、发送特定广播:
在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。
4、递归退出
在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。
除了第一个,都是想办法把每一个Activity都结束掉,间接达到目的。
但是这样做同样不完美。
你会发现,如果自己的应用程序对每一个Activity都设置了nosensor,在两个Activity结束的间隙,sensor可能有效了。
但至少,我们的目的达到了,而且没有影响用户使用。
为了编程方便,最好定义一个Activity基类,处理这些共通问题。
5.请介绍下Android中常用的五种布局
Android布局是应用界面开发的重要一环,在Android中,共有五种布局方式,分别是:FrameLayout(框架布 局),LinearLayout (线性布局),AbsoluteLayout(绝对布局),RelativeLayout(相对布局),TableLayout(表格布局)。
一、FrameLayout
这个布局可以看成是墙脚堆东西,有一个四方的矩形的左上角墙脚,我们放了第一个东西,要再放一个,那就在放在原来放的位置的上面,这样依次的放,会盖住原来的东西。这个布局比较简单,也只能放一点比较简单的东西。
二、LinearLayout
线性布局,这个东西,从外框上可以理解为一个div,他首先是一个一个从上往下罗列在屏幕上。每一个LinearLayout里面又可分为垂直布局 (android:orientation="vertical")和水平布局(android:orientation="horizontal" )。当垂直布局时,每一行就只有一个元素,多个元素依次垂直往下;水平布局时,只有一行,每一个元素依次向右排列。
linearLayout中有一个重要的属性 android:layout_weight="1",这个weight在垂直布局时,代表行距;水平的时候代表列宽;weight值越大就越大。
三、AbsoluteLayout
绝对布局犹如div指定了absolute属性,用X,Y坐标来指定元素的位置android:layout_x="20px" android:layout_y="12px" 这种布局方式也比较简单,但是在垂直随便切换时,往往会出问题,而且多个元素的时候,计算比较麻烦。
四、RelativeLayout
相对布局可以理解为某一个元素为参照物,来定位的布局方式。主要属性有:
相对于某一个元素
android:layout_below="@id/aaa" 该元素在 id为aaa的下面
android:layout_toLeftOf="@id/bbb" 改元素的左边是bbb
相对于父元素的地方
android:layout_alignParentLeft="true" 在父元素左对齐
android:layout_alignParentRight="true" 在父元素右对齐
还可以指定边距等,具体详见API
五。TableLayout
表格布局类似Html里面的Table。每一个TableLayout里面有表格行TableRow,TableRow里面可以具体定义每一个元素,设定他的对齐方式 android:gravity="" 。
每一个布局都有自己适合的方式,另外,这五个布局元素可以相互嵌套应用,做出美观的界面。
6. 请介绍下Android的数据存储方式
Android 提供了5种方式存储数据: --使用SharedPreferences存储数据; --文件存储数据; --SQLite数据库存储数据; --使用ContentProvider存储数据; --网络存储数据;在Android中通常使用File存储方式是用 Context.openFileOutput(String fileName, int mode)和Context.openFileInput(String fileName)。 Context.openFileOutput(String fileName, int mode)生成的文件自动存储在/data/data/Package Name/files目录下,其全路径是/data/data/Package Name/files/fileName 。注意下,这里的参数fileName不可以包含路径分割符(如"/")。 通常来说,这种方式生成的文件只能在这个apk内访问。但这个结论是指使用Context.openFileInput(String fileName)的方式。使用这种方式,每个apk只可以访问自己的/data/data/Package Name/files目录下的文件,原因很简单,参数fileName中不可以包含路径分割符,Android会自动在/data/data /Package Name/files目录下寻找文件名为fileName的文件。一:使用SharedPreferences存储数据
首先说明SharedPreferences存储方式,它是 Android提供的用来存储一些简单配置信息的一种机制,例如:登录用户的用户名与密码。其采用了Map数据结构来存储数据,以键值的方式存储,可以简单的读取与写入,具体实例如下: void ReadSharedPreferences(){ String strName,strPassword; SharedPreferences user = getSharedPreferences(“user_info”,0); strName = user.getString(“NAME”,””); strPassword = user getString(“PASSWORD”,””); } void WriteSharedPreferences(String strName,String strPassword){ SharedPreferences user = getSharedPreferences(“user_info”,0); uer.edit(); user.putString(“NAME”, strName); user.putString(“PASSWORD” ,strPassword); user.commit(); } 数据读取与写入的方法都非常简单,只是在写入的时候有些区别:先调用edit()使其处于编辑状态,然后才能修改数据,最后使用commit()提交修改的数据。实际上SharedPreferences是采用了XML格式将数据存储到设备中,在DDMS中的File Explorer中的/data/data/<package name>/shares_prefs下。以上面的数据存储结果为例,打开后可以看到一个user_info.xml的文件,打开后可以看到: <?xml version=”1.0″ encoding=”UTF-8″?> <map> <string name=”NAME”>moandroid</string> <string name=” PASSWORD”>SharedPreferences</string> </map> 使用SharedPreferences是有些限制的:只能在同一个包内使用,不能在不同的包之间使用。二:文件存储数据
文件存储方式是一种较常用的方法,在Android中读取/写入文件的方法,与 Java中实现I/O的程序是完全一样的,提供了openFileInput()和openFileOutput()方法来读取设备上的文件。 FilterInputStream, FilterOutputStream等可以到Java io package说明中去详细学习,不再此详细说明,具体实例如下: String fn = “moandroid.log”; FileInputStream fis = openFileInput(fn); FileOutputStream fos = openFileOutput(fn,Context.MODE_PRIVATE); 除此之外,Android还提供了其他函数来操作文件,详细说明请阅读Android SDK。
三:网络存储数据 网络存储方式,需要与Android 网络数据包打交道,关于Android 网络数据包的详细说明,请阅读Android SDK引用了Java SDK的哪些package?。
四:ContentProvider
1、ContentProvider简介 当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据。而使用ContentProvider共享数据的好处是统一了数据访问方式。?
2、Uri类简介 Uri代表了要操作的数据,Uri主要包含了两部分信息:1.需要操作的ContentProvider ,2.对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成: 1.scheme:ContentProvider(内容提供者)的scheme已经由Android所规定为:content://。
2.主机名(或Authority):用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
3.路径(path):可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下: ? 要操作contact表中id为10的记录,可以构建这样的路径:/contact/10 ? 要操作contact表中id为10的记录的name字段, contact/10/name ? 要操作contact表中的所有记录,可以构建这样的路径:/contact? 要操作的数据不一定来自数据库,也可以是文件等他存储方式,如下: 要操作xml文件中contact节点下的name节点,可以构建这样的路径:/contact/name 如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下: Uri uri = Uri.parse("content://com.changcheng.provider.contactprovider/contact") 3、UriMatcher、ContentUrist和ContentResolver简介
因为Uri代表了要操作的数据,所以我们很经常需要解析Uri,并从 Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris 。掌握它们的使用,会便于我们的开发工作。 ? UriMatcher:用于匹配Uri,它的用法如下: 1.首先把你需要匹配Uri路径全部给注册上,如下: //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码(-1)。 UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); //如果match()方法匹配content://com.changcheng.sqlite.provider.contactprovider /contact路径,返回匹配码为1 uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact”, 1);//添加需要匹配uri,如果匹配就会返回匹配码 //如果match()方法匹配 content://com.changcheng.sqlite.provider.contactprovider/contact/230路径,返回匹配码为2 uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact/#”, 2);//#号为通配符
2.注册完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用 addURI()方法传入的第三个参数,假设匹配 content://com.changcheng.sqlite.provider.contactprovider/contact路径,返回的匹配码为1。 ? ContentUris:用于获取Uri路径后面的ID部分,它有两个比较实用的方法: ? withAppendedId(uri, id)用于为路径加上ID部分 ? parseId(uri)方法用于从路径中获取ID部分 ? ContentResolver:当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用 ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。 ContentResolver使用insert、delete、update、query方法,来操作数据。
五:总结说明 以上5中存储方式,在以后的开发过程中,根据设计目标、性能需求、空间需求等找到合适的数据存储方式。Android 中的数据存储都是私有的,其他应用程序都是无法访问的,除非通过ContentResolver获取其他程序共享的数据。采用文件方式对外共享数据,需要进行文件操作读写数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据。而使用ContentProvider共享数据的好处是统一了数据访问方式。
8.如何启用Service,如何停用ServiceAndroid中的服务和windows中的服务是类似的东西,服务一般没有用户操作界面,它运行于系统中不容易被用户发觉,可以使用它开发如监控之类的程序。服务的开发比较简单,如下: 第一步:继承Service类 public class SMSService extends Service { } 第二步:在AndroidManifest.xml文件中的<application>节点里对服务进行配置: <service android:name=".SMSService" /> 服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可以启动Service,但是它们的使用场合有所不同。使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。 如果打算采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法。如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。 如果打算采用Context.bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onBind()方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的onUnbind()方法,接着调用onDestroy()方法。如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法并不会导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。如果调用者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,调用该方法也会导致系统调用服务的onUnbind()-->onDestroy()方法。
服务常用生命周期回调方法如下:onCreate() 该方法在服务被创建时调用,该方法只会被调用一次,无论调用多少次startService()或bindService()方法,服务也只被创建一次。 onDestroy()该方法在服务被终止时调用。
与采用Context.startService()方法启动服务有关的生命周期方法 onStart() 只有采用Context.startService()方法启动服务时才会回调该方法。该方法在服务开始运行时被调用。多次调用startService()方法尽管不会多次创建服务,但onStart() 方法会被多次调用。
与采用Context.bindService()方法启动服务有关的生命周期方法 onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。 onUnbind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务解除绑定时被调用
采用Context.startService()方法启动服务的代码如下: public class HelloActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { ...... Button button =(Button) this.findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener(){ public void onClick(View v) { Intent intent = new Intent(HelloActivity.this, SMSService.class); startService(intent); }}); } }
采用Context. bindService()方法启动服务的代码如下: public class HelloActivity extends Activity { ServiceConnection conn = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder service) { } public void onServiceDisconnected(ComponentName name) { } }; @Override public void onCreate(Bundle savedInstanceState) { Button button =(Button) this.findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener(){ public void onClick(View v) { Intent intent = new Intent(HelloActivity.this, SMSService.class); bindService(intent, conn, Context.BIND_AUTO_CREATE); //unbindService(conn);//解除绑定 }}); } }
|
|
常用链接
留言簿
随笔分类
随笔档案
文章分类
搜索
最新评论
阅读排行榜
评论排行榜
|
|