您的位置:首页 > 其它

project00:一个简单项目学到的东西总结

2014-08-16 07:34 267 查看
----------------------------------------------------------------------------------------

索引

----------------------------------------------------------------------------------------

0)登陆模块自定义editText样式

1)http通信

2)自动升级

3)json解析

4)数据库操作、sharePreference的用法

5)自定义spinner样式

6)startActivityForResult的用法

7)二维码的扫描解析

8)使用正则表达式对editText进行输入限制

9)关于调试

----------------------------------------------------------------------------------------

正文

----------------------------------------------------------------------------------------

0)登陆的editText样式

本来就是简单的输入框,比较死板,没有花样,但是我们可以在它的样式里面对选择器写点相应的动作,这样交互效果就比较好了。



<EditText
android:id="@+id/edit_username"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:background="@drawable/style_mess"
android:hint="@string/login_user"
android:padding="12dp"
android:paddingLeft="10dp"
android:singleLine="true" />
上面的是xml文件,然后主要看下面的样式syle,主要的就是在获取焦点的时候给它的描边stroke属性color颜色与没有焦点的时候区分开来,这里用的是蓝色和灰色区分的。
<?xml version="1.0" encoding="UTF-8"?>
<selector
xmlns:XXX">
<item android:state_focused="false" >
<shape>
<solid android:color="#F9FBFA"/>
<stroke
android:width="2dp"
android:color="#cccccc" />

<corners
android:topRightRadius="3dp"
android:topLeftRadius="3dp"
android:bottomLeftRadius="3dp"
android:bottomRightRadius="3dp"
/>
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp"/>
</shape>
</item  >

<item android:state_focused="true">
<shape>
<solid android:color="#F9FBFA"/>
<stroke
android:width="2dp"
android:color="#4699df" />

<corners
android:topRightRadius="3dp"
android:topLeftRadius="3dp"
android:bottomLeftRadius="3dp"
android:bottomRightRadius="3dp"
/>
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp"/>
</shape>
</item>

</selector>
关于样式,还有一个问题就是,输入文字之后,右侧显示一个可以删除的×,这个需求,其实也很简单的。我这边没有复写editText,只是简单的写了一个布局,里面放了这个editText,还有一个button,就是那个X,点击的时候清理掉edittext中的内容。也有自定义editText实现这个需求的,下一次在具体实践。

xml文件如下:

<RelativeLayout
android:id="@+id/username"
android:layout_width="wrap_content"
android:layout_height="56dp"
android:gravity="center_vertical"
android:orientation="horizontal" >

<EditText
android:id="@+id/edit_username"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:background="@drawable/style_mess"
android:hint="@string/login_user"
android:padding="12dp"
android:paddingLeft="10dp"
android:singleLine="true" />

<Button
android:id="@+id/btn_unclear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
android:background="@drawable/close_ico"
android:onClick="clearText"
android:visibility="invisible" />
</RelativeLayout>
清除按钮的点击事件的,注册的地方是xml中的onClick事件,用这个方法可以只写一个清除就可以完成用户名和密码两个文本框的清除了:
android:onClick="clearText"
.java 如下:

public void clearText(View view) {
if (view.getId() == R.id.btn_unclear) {
login_username.getText().clear();
} else {
login_password.getText().clear();
}
}


----------------------------------------------------------------------------------------

1)http通信
登陆模块的数据采集完成之后,就是点击登陆的那个按钮的动作了,准备好和服务器那段交互的接口数据,根据接口选择post方式还是get方式。下面是get的实例,具体的可以参照Android使用HttpClient方法和易错问题,注意一点,不能在主线程联网,开一个runnable线程,里面放联网的逻辑。

public static String httpGetLogin(Context context, String servletURL,
String url) throws Exception {

String res = null;
try {
// 处理连接超时工具
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, 15000);// 设置连接超时
HttpConnectionParams.setSoTimeout(params, 5000);// 设置请求超时

// 1. 获取到一个浏览器的实例
HttpClient client = new DefaultHttpClient(params);

if (client != null) {
String x = Constfinal._SERVICE_URL + Constfinal._USERPATH
+ servletURL + "?" + url;
HttpGet getMethod = new HttpGet(x);
// Log.v("url", x);

// 4. 发送数据给服务器
HttpResponse response = client.execute(getMethod);

int code = response.getStatusLine().getStatusCode();
if (code == 200) {
InputStream is = response.getEntity().getContent();
byte[] result = StreamTool.getBytes(is);
res = new String(result);
} else {
throw new IllegalStateException("服务器状态异常");
}
}
} catch (Exception e) {
return null;
}
return res;
}


然后根据接口对登陆成功与否res值进行相应的处理。具体的可以参照上面的那个。

----------------------------------------------------------------------------------------

2)自动升级

自动升级,看情况了,我们这个应用的背景是专用的,所以不会托管给第三方,需要DIY完成这自动升级的需求。

参考Android应用自动更新功能的实现!!!

这里讲一下步骤:

checkUpdate-->isUpdate-->getVersionCode-->showNoticeDialogue-->showDownloadDialogue-->DownloadThread()-->InstallAPK

检查update,调用isUpda()获取服务器上的版本号,在getVersion()里面获取当前版本号然后对比,在noticeDialogue中显示出来是否有更新,如果版本号不一致了,点击立即更新,就调到下载线程,下载完成之后调用install方法安装。

----------------------------------------------------------------------------------------

3)json的解析

这里我用的是java自带的解析JSONObject,把接口返回的string转成jsonObject对象,然后用这个对象根据json里面的内容开个handler进行相应的处理,。

注意一点,这个json处理的逻辑需要放到try Catch中,还有抽取出来的值需要用异步任务handler执行。再提醒一下,不能在主线程联网。

jsonString = HttpLogin.httpGetLogin(
getApplicationContext(),
"PadSpAdminLogin", url);
System.out.println(jsonString);
json = new JSONObject(jsonString);
Success = json.getInt("Success");

android.os.Message msg = new android.os.Message();
msg.arg1 = (Success == 1) ? 1 : 2; // 1;
handler.sendMessage(msg);
msg = null;


----------------------------------------------------------------------------------------

4)数据库操作、sharePreference的用法

前面几个步骤中,已经完成了登陆服务器并取得解析了返回的json数据,下面就是对这个数据的保存和使用了,

android中对数据的保存和使用有好几种方式,contentProvider,数据库sqlite,sharePreference,文件file和网络,参考这个Android中的5种数据存储方式

我这里用到的数据库和sharePreference。

***用sharePreference保存登陆用户名和密码数据。

private void SaveUserLoginInfo() {// 保存用户登录信息
// TODO Auto-generated method stub
// 登录成功才被调用
SharedPreferences agPreferences = getSharedPreferences(
Constfinal.PREFERENCES_NAME_USER, Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = agPreferences.edit();
strUsername = login_username.getText().toString().trim();
strPassword = login_password.getText().toString().trim();

editor.putString(Constfinal.PREF_USER_NAME, strUsername);
editor.putString(Constfinal.PREF_USER_PSWD, strPassword);
editor.putBoolean(Constfinal.PREF_USER_REMR, login_remember.isChecked());
editor.commit();
}


***使用sharePreference取出数据

SharedPreferences sp3 = getSharedPreferences(
Constfinal.PREFERENCES_spAdmin, Activity.MODE_PRIVATE);

String Name = sp3.getString(Constfinal.PREF_PRE_spNAME, "testadmin");
String Id = sp3.getString(Constfinal.PREF_PRE_spID, "testNo");
然后就可以快乐的使用这些个string了。

***使用sqlite数据库保存解析到的json数据。

// 保存组织机构数据的对象
jsonarray = json.getJSONArray("OrgList");
for (int i = 0; i < jsonarray.length(); i++) {

JSONObject item = jsonarray.getJSONObject(i);
String Addr = item.getString("Addr");
String Tel = item.getString("Tel");
map = new HashMap<String, String>();
map.put("Addr", Addr);
map.put("Tel", Tel);
list.add(map);
}
把json数据封装到map中,然后一条条map对象遍历写到数据表中。
for (Map<String, String> list2 : list) {

String Addr = list2.get("Addr");
String Tel = list2.get("Tel");
dbAdapter.insert( Addr, Tel);
这里关键的对数据表的插入就是这句话,xx.insert().是传参数进去,然后将参数拼接成合法的sql语句,然后调用db.Execute(sql)即可完成对数据库的插入操作。

具体内容如下:

// 成功登陆之后将数据插入 Org表格
public void insert( String Addr, String Tel) {

String sql_insertOrg = "insert into Org( "+ "Addr, Tel)"+ "values(?,?,)";//这里就是按照sql语法拼接插入表的语句
db.execSQL(sql_insertOrg, new Object[] {  Addr, Tel });

}
至此,完成了登陆之后解析数据之后的数据保存。

***查询数据库中的数据,

// 查询表格
public ArrayList<String> queryOrgName(String outfit) {
ArrayList<String> orgnamelist = new ArrayList<String>();
// "select OrgNam from Org where Outfit like \""15\"%\"";
String sql_query = "select OrgNam from Org where Outfit like \""
+ outfit + "%\"";
Cursor cursor = db.rawQuery(sql_query, null);
while (cursor.moveToNext()) {
String orglist = cursor.getString(cursor.getColumnIndex("OrgNam"));
orgnamelist.add(orglist);
}
cursor.close();
return orgnamelist;
查询使用游标cursor对象,进行查询,然后返回这个list。

----------------------------------------------------------------------------------------

5)自定义spinner样式

使用到了一个下拉列表的控件来展示一些数据的,因为默认的样式一般,和应用总体风格不协调,所以就有必要自定义一下复写一个。

参考这个自定义spinner样式和item样式,这个里面讲的界面比较多。



自定义Spinner样式 ,这个里面讲的.java比较多。

对item的样式修改,就是那个弹出来的下拉窗口,这个是复写ArrayAdapter的getDropDownView()方法来实现的

上面两个博客写的很详细,我就不赘述了。

----------------------------------------------------------------------------------------

6)startActivityForResult的用法

开始的需求是获取一次前面的值,然后提交的,后来改了需求,再增加一次取值。

遇到这个问题,我开始想的方法是取好之后给一个布尔量,如果没有两次结束,那就再取一次,后来折腾了一下,原来的取值方法是封装的好好的了,改动一处就全部叉叉了。

然后就找破解方法,后来发现了以前讲的这个startActivityForResult(),完全可以满足这个需求。

Android startActivityForResult的使用

抽取一下重点:

*activityA----->**activityB获取值x1------->***回传给activityA

*activityA----->**activityB获取值x2------->***回传给activityA

*中:

Intent intent=new Intent(ActivityResultDemoActivity.this,SimpleTaskActivity.class);

//关键点来了,使用startActivityForResult来启动

startActivityForResult(intent, 100);

其中这个100,是requestCode,请求码,你在待会接受的时候需要用这个码来区分开这两个值,如下:

if (resultCode == RESULT_OK) {
if (requestCode == 100) {
x1 = intent.getExtras().getString("result");
tv_test.setText("x1-----" + x1);
}
if (requestCode == 101) {
x2 = intent.getExtras().getString("result");
tv_test.setText("x2----" +x2);

}
}
就这样,完美使用startActivityForResult解决这个需求。

----------------------------------------------------------------------------------------

7)二维码的扫描解析

一般的就是使用Zxing的开源包了,很管用。

参考这个Zxing的使用

整合进项目之后,出现了一个奇怪的情况,就是横竖屏不对,偏差了90度,

参考这个Android ZXing改横屏辨别为竖屏识别,这个时候就能使用zxing解码了。

然后你需要自己修改界面的时候,要注意,不要再frame外面写布局,,否则解析的速度慢的不得了,这个问题纠结了我很久,甚至看完了zxing的源码没有找出问题来,后来改了布局文件的时候突然发现的。

<FrameLayout>

<zxing/>

</FrameLayout>

<!-- 不可以再framework外面写布局,否咋会挤压界面降低扫描相机解码速度-->

----------------------------------------------------------------------------------------

8)使用正则表达式对editText进行输入限制

这个需求是基于实际情况下的,我这里要实现的是只允许中文输入,过滤掉数字和英文。

查询来查询去,有两种方案,一个是给editText设置textWatcher,一个是给获取string之后remove掉。

String newString=string.replaceAll("[a-z,A-Z,0-9]+","").trim();
但是用string的方式的话,没法动态出现在输入框中,而且,需要考虑的东西很多,还有标点符号什么的各种需要排除,显然这个情景下不适合,果断使用正则。

RE很强大。

RE语法

RE在线测试工具

get了上面的知识之后,就是如何子android(java)中应用这个了,看下面:

adminName.addTextChangedListener(new editNameWatcher(adminName));//增加覆写的监听器


class editNameWatcher implements TextWatcher {

private EditText editText;

public editNameWatcher(EditText adminName) {
this.editText = adminName;
}

@Override
public void onTextChanged(CharSequence s, int start, int before,//在文字改变的事件里面,即有输入的时候
int count) {
// TODO Auto-generated method stub
String editable = editText.getText().toString();
Log.i("OnTextChangeing---adminname", editable);
String str = stringFilter(editable.toString());//获取正则过滤过的string
Log.i("FilterDone----Reed", str);
if (!editable.equals(str)) {//关于这里的逻辑,需要大家好好思考一下,我搞反了逻辑起初,结果把中文全部过滤掉了
editText.setText(str);
editText.setSelection(str.length());
}
}
与RE相关的是过滤器:

public static String stringFilter(String string)
throws PatternSyntaxException {
// TODO Auto-generated method stub^[\u4e00-\u9fa5]+$

Log.i("in2Filter-----", string);
final String RE ="[\\u4e00-\\u9fa5]+";
Pattern p = Pattern.compile(RE);
Matcher m = p.matcher(string);
String s = m.replaceAll("").trim();//去除掉空格
return string.replaceAll(s, "");
}


"[\\u4e00-\\u9fa5]+"
关于正则,有个问题一定要注意,本来是RE = "[\u4e00-\u9fa5]+";这样的

但是我跑起来一直不出结果,然后debug一下发型,问题出在RE转到java中,它的 \ 被转义了,需要在增加一个 \ 才行。

这样就解决掉了这个需求。

9)关于调试

这里啰嗦一下,调试的话,一般的可以打个log跟踪一下,实在需要看里面的情况的话,就要插断点,然后进去inspect,看具体的,F6下一步(IDE是eclipse)。
前面Re的转义问题就是插断点找到的,一般的空指针debug一下,妥妥的干掉。

----------------------------------------------------------------------------------------

写在最后,以后就按照项目中总结get的方式穿插组件学习的方式写点东西吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: