概述
整体是通过2个Fragment+FragmentTabHost组合而成,本节主要针对Fragment1做一个总结,该Fragment主要实现以下功能
【1】输入快递单号或者扫描二维码 查询快递信息
【2】侧滑栏集成的百度地图可以显示附近快递点,方便选择合适自己的地点
本篇只总结主界面架构和功能1,先上图有个直观感受
1、主界面结构
Fragment+FragmentTabHost组合而成,其中整体的布局文件是在LinearLayout(vertical)的布局中嵌入了FrameLayout,上图显示的文字和背景都在直接代码中加入的,main_tab_layout.xml具体布局如下
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:baiduadsdk="http://schemas.android.com/apk/res/com.weimeijing.feigeshudi"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical" >
-
- <FrameLayout
- android:id="@+id/realtabcontent"
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1" />
-
- <android.support.v4.app.FragmentTabHost
- android:id="@android:id/tabhost"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/maintab_toolbar_bg" >
-
- <FrameLayout
- android:id="@android:id/tabcontent"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="0" />
- </android.support.v4.app.FragmentTabHost>
-
- </LinearLayout>
框架MainTabActivity主要使用FragmentTabHost来管理,这里将俩个Fragment放入一个数组中
-
-
- private Class fragmentArray[] = { MainActivity.class,
- MyExpressActivity.class };
然后// 将Tab按钮添加进Tab选项卡中 mTabHost.addTab(tabSpec, fragmentArray[i], null);
具体代码如下
- package com;
-
- import android.os.Bundle;
- import android.support.v4.app.FragmentActivity;
- import android.support.v4.app.FragmentTabHost;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.widget.ImageView;
- import android.widget.TabHost.TabSpec;
- import android.widget.TextView;
-
- import com.baidu.mapapi.map.BaiduMap;
- import com.weimeijing.feigeshudi.R;
-
-
-
-
- public class MainTabActivity extends FragmentActivity {
-
- private FragmentTabHost mTabHost;
-
-
- private LayoutInflater layoutInflater;
-
-
-
- private Class fragmentArray[] = { MainActivity.class,
- MyExpressActivity.class };
-
-
- private int mImageViewArray[] = { R.drawable.tab_square_btn,
- R.drawable.tab_home_btn };
-
- private String mTextviewArray[] = { "快递追踪", "我的收藏" };
-
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main_tab_layout);
-
- initView();
- }
-
-
-
-
- private void initView() {
-
- layoutInflater = LayoutInflater.from(this);
-
-
- mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
- mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
-
-
- int count = fragmentArray.length;
-
- for (int i = 0; i < count; i++) {
-
- TabSpec tabSpec = mTabHost.newTabSpec(mTextviewArray[i])
- .setIndicator(getTabItemView(i));
-
- mTabHost.addTab(tabSpec, fragmentArray[i], null);
-
- mTabHost.getTabWidget().getChildAt(i)
- .setBackgroundResource(R.drawable.selector_tab_background);
- }
- }
-
-
-
-
- private View getTabItemView(int index) {
- View view = layoutInflater.inflate(R.layout.tab_item_view, null);
-
- ImageView imageView = (ImageView) view.findViewById(R.id.imageview);
- imageView.setImageResource(mImageViewArray[index]);
-
- TextView textView = (TextView) view.findViewById(R.id.textview);
- textView.setText(mTextviewArray[index]);
-
- return view;
- }
- }
框架部分其实还是很简单的,注释比较详细就不赘述了
2 、Fragment 快递追踪
2.1、布局文件
这里的布局文件非常重要,因为Fragment1里面实际包含了2部分 快递追踪+侧滑(来自github的开源控件开源控件)下一篇讲侧滑模块再详细介绍,布局文件中activity_main.xml其中 <include layout="@layout/left_slide" />是侧滑的布局文件,这里我们暂不考虑,
【1】使用了SlidingMenu,整个布局要在其中包含跟一般的布局文件不一样,这里需要导入slidingmenu_library才可以使用
【2】要注意由于要包含侧滑部分,因此整个LinearLayout属性使用"horizontal",而不是Vertical的
布局文件代码如下:
2.2、MainTabActivity.java总结
这里对该代码中一些要点做下总结:
【1】使用fragment与Activity通信
因为所有的Fragment都是依附于Activity的,所以通信起来并不复杂,大概归纳为:
a、如果你Activity中包含自己管理的Fragment的引用,可以通过引用直接访问所有的Fragment的public方法
b、如果Activity中未保存任何Fragment的引用,那么没关系,每个Fragment都有一个唯一的TAG或者ID,可以通过getFragmentManager.findFragmentByTag()或者findFragmentById()获得任何Fragment实例,然后进行操作。
c、在Fragment中可以通过getActivity得到当前绑定的Activity的实例,然后进行操作。
【2】使用Fragment时 onCreateView()参数详解
-
-
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
-
-
-
-
-
-
-
- return inflater.inflate(R.layout.activity_main, null);
-
- }
【3】startActivityForResult与startActivity区别
1、startActivity( )
仅仅是跳转到目标页面,若是想跳回当前页面,则必须再使用一次startActivity( )。
2、startActivityForResult( )
可 以一次性完成这项任务,当程序执行到这段代码的时候,假若从T1Activity跳转到下一个Text2Activity,而当这个 Text2Activity调用了finish()方法以后(必须调用该方法!),程序会自动跳转回T1Activity,并调用前一个T1Activity中的 onActivityResult( )方法。通过requestCode来判断执行
相关函数:
startActivityForResult(Intent intent, Int requestCode)
setResut(int resultCode, Intent intent)
onActivityResult(int requestCode, int resultCode, Intent intent)
本项中通过俩种形式手动输入快递号requestCode=1,扫描二维码requestCode=0
- startActivityForResult(openCameraIntent, 0);
- startActivityForResult(intent, 1);
然后在回调函数onActivityResult是这样处理的
-
-
-
-
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (data == null) {
- return;
- }
- super.onActivityResult(requestCode, resultCode, data);
- if (requestCode == 1) {
-
-
-
- code = data.getStringExtra("code");
- String name = data.getStringExtra("name");
- tv_main_express_name.setText(name);
- tv_main_express_number.setText("");
-
- } else if (requestCode == 0) {
- Bundle bundle = data.getExtras();
- String scanResult = bundle.getString("result");
- tv_main_express_number.setText(scanResult);
- }
-
- }
【4】这里在最开始就让MainActivity继承了 Fragment类 实现了 OnClickListener,以便通过switch统一处理监听对象,这种方式处理起来很简洁
-
- public void onClick(View v) {
-
- switch (v.getId()) {
-
- case R.id.scane_express_number:
- Intent openCameraIntent = new Intent(getActivity(),
- CaptureActivity.class);
- startActivityForResult(openCameraIntent, 0);
-
- case R.id.btn_main_reset:
-
- tv_main_express_number.setText("");
- break;
- case R.id.tv_main_express_name:
-
-
-
-
-
-
- Intent intent = new Intent(getActivity(), ExpressList.class);
- startActivityForResult(intent, 1);
- break;
-
- case R.id.btn_main_search:
-
- String name = tv_main_express_name.getText().toString();
- if (name.equals("")) {
- Toast.makeText(getActivity(), "请选择快递公司", Toast.LENGTH_SHORT)
- .show();
- } else {
- String number = tv_main_express_number.getText().toString();
- if (number.equals("")) {
- Toast.makeText(getActivity(), "快递号码不能为空",
- Toast.LENGTH_SHORT).show();
- } else {
-
-
- progressDialog = new ProgressDialog(getActivity());
-
-
-
-
-
-
-
-
-
-
- <span style="color:#33CC00;"> <span style="color:#006600;">QueryExpressUtil.queryExpressForNumber(number, name, code,
- getActivity(), progressDialog);</span></span>
- }
-
- }
- break;
- default:
- break;
- }
- }
【5】关键处理函数QueryExpressUtil.queryExpressForNumber
QueryExpressUtil.queryExpressForNumber(number, name, code,getActivity(), progressDialog);
* 输入参数含义分别为: number:快递单号 name:快递名称 code:快递拼音名称
* getActivity()当前Activity/fragment progressDialog控件的名称
整体核心函数主要做了以下几件事情:
(1)使用Xutil框架中的HttpUtils通过Get的请求方式,GET请求的数据会附在URL之后(就是 把数据放置在HTTP协议头中),以?分割URL和传输数据,参数之间以&相连(对比下post)
- String url;
- url = "http://api.ickd.cn/?id=102616&secret=16135ea51cb60246eff620f130a005bd&com=";
- url += code;
- url += "&nu=";
- url += number;
- url += "&type=json&encode=utf8&ord=asc";
- Log.v("tag", url);
-
- HttpUtils http = new HttpUtils();
- http.send(HttpRequest.HttpMethod.GET, url, new RequestCallBack<String>()
(2) 解析爱查快递提供信息使用Parcelable序列化方式将data和context保存到listInfo其中ExpressInfo为序列化数据模型
-
- public class ExpressInfo implements Parcelable {
- public String time;
- public String context;
-
-
- public static final Parcelable.Creator<ExpressInfo> CREATOR = new Creator<ExpressInfo>() {
-
- @Override
-
- public ExpressInfo createFromParcel(Parcel source) {
-
-
- ExpressInfo expressInfo = new ExpressInfo();
- expressInfo.time = source.readString();
- expressInfo.context = source.readString();
-
- return expressInfo;
- }
-
- @Override
-
- public ExpressInfo[] newArray(int size) {
-
- return new ExpressInfo[size];
- }
-
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
-
-
- dest.writeString(time);
- dest.writeString(context);
-
- }
- }
这里从服务器返回快递信息的是Json格式的数据,过程在Xutil框架中HttpUtils模块onSuccess函数中处理
- @Override
- public void onSuccess(ResponseInfo<String> responseInfo) {
- try {
- JSONObject all = new JSONObject(responseInfo.result);
- String status = all.getString("status");
-
-
- if (status.equals(STATE_FAIL)) {
- String message = all.getString("message");
- Toast.makeText(context, message,
- Toast.LENGTH_LONG).show();
-
- progressDialog.dismiss();
- return;
- }
-
-
-
- JSONArray jsonArray = all.getJSONArray("data");
- int length = jsonArray.length();
- Log.v("tag", "长度是" + length);
- <span style="color:#006600;">
- Intent intent = new Intent(context,ExpressInfoActivity.class);</span>
-
-
- ArrayList<ExpressInfo> infoList = new ArrayList<ExpressInfo>();
-
-
-
-
-
- for (int i = 0; i < length; i++) {
- ExpressInfo expressInfo = new ExpressInfo();
- String time = jsonArray.getJSONObject(i).getString("time");
- String context = jsonArray.getJSONObject(i).getString("context");
-
- expressInfo.time = time;
- expressInfo.context = context;
-
- infoList.add(expressInfo);
- }
-
-
- Bundle bundle = new Bundle();
- bundle.putParcelableArrayList("infos", infoList);
-
- intent.putExtras(bundle);
- intent.putExtra("state", status);
- intent.putExtra("name", name);
- intent.putExtra("number", number);
- intent.putExtra("code", code);
-
- progressDialog.dismiss();
-
- <span style="color:#009900;">
- context.startActivity(intent);
-
- } catch (JSONException e) {
- e.printStackTrace();
- }
- }
2.3、使用intent跳转到ExpressInfoActivity
该Activity用来提取序列化的消息并将其显示(ListView)
-
-
- infoList = getIntent().getExtras().getParcelableArrayList("infos");
-
- lv_express_info = (ListView) findViewById(R.id.lv_express_info_list);
-
- lv_express_info.setAdapter(<span style="color:#009900;">new ExpressInfoAdapter(this, infoList)</span>);
-
-
-
- number = getIntent().getStringExtra("number");
- code = getIntent().getStringExtra("code");
- name = getIntent().getStringExtra("name");
- expressState = getIntent().getStringExtra("state");
-
- if (expressState.equals(STATE_RECEIVED)) {
-
-
-
-
-
-
- findViewById(R.id.colorLine).setBackgroundResource(
- R.drawable.red_line_green);
- findViewById(R.id.dot_full).setVisibility(View.VISIBLE);
- }
- if (expressState.equals(STATE_ON_PASSAGE)) {
-
- findViewById(R.id.colorLine).setBackgroundResource(
- R.drawable.red_line_blue);
- }
这里面在加载消息时还使用了Listview的优化,lv_express_info.setAdapter(new ExpressInfoAdapter(this, infoList))
在 ExpressInfoAdapter中,主要使用了ViewHolder/convertView来优化ListView
ViewHolder不是Android的开发API,而是一种设计方法,就是设计个静态类,缓存一下,省得Listview更新的时候,还要重新操作;
convertView 在API中的解释是The old view to reuse, if possible, 第一次getView时还没有convertView,这时你便创建了一个新的view,下次getView时就有这个“旧的”convertView 了 setTag的作用才是把查找的view通过ViewHolder封装好缓存起来方便多次重用,当需要时可以getTag拿出来 ;
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
-
- ViewHolder holder;
-
- if (convertView == null) {
-
- convertView = mInflater.inflate(R.layout.list_express_info_item,parent, false);
-
- holder = new ViewHolder();
- holder.time = (TextView) convertView.findViewById(R.id.tv_info_time);
- holder.context = (TextView) convertView.findViewById(R.id.tv_info_context);
-
- convertView.setTag(holder);
- } else {
- holder = (ViewHolder) convertView.getTag();
- }
- holder.time.setText(lists.get(position).time);
- holder.context.setText(lists.get(position).context);
-
- return convertView;
- }
2.4 知识点总结
【1】使用fragment与Activity通信(见上)
【2】startActivityForResult与startActivity区别(见上)
【3】Parcelable序列化
Android中实现序列化有两个选择:一是实现Serializable接口 (是JavaSE本身就支持的),一是实现Parcelable接口(Android特有功能,效率比实现Serializable接口高效,可用于 Intent数据传递,也可以用于进程间通信(IPC))。实现Serializable接口非常简单,声明一下就可以了,而实现Parcelable接 口稍微复杂一些(实例化静态内部对象CREATOR实现接口Parcelable.Creator),但效率更高,推荐用这种方法提高性能。
注:Android中Intent传递对象有两种方法:一是 Bundle.putSerializable(Key,Object),另一种是Bundle.putParcelable(Key,Object)。 当然这些Object是有一定的条件的,前者是实现了Serializable接口,而后者是实现了Parcelable接口。
选择序列化方法的原则
1)在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。
2)Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
3)Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable 。
【4】Json解析
json一共有两种数据结构,一种是以 (key/value)对形式存在的无序的jsonObject对象,一个对象以“{”(左花括号)开始,“}”(右花括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔;
另一种数据格式就是有序的value的集合,这种形式被称为是jsonArray,数组是值(value)的有序集合。一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间使用“,”(逗号)分隔。
详细的网上有很多,推荐一篇json
【5】Xutil框架
【6】ListView的优化(见上)
转载:http://blog.csdn.net/xsf50717/article/details/47206939