安卓开发遇到的几个问题(网络定位,从网络获取所有省/市,SQLite,Service等)

来源:互联网 发布:广告投放算法好吃 编辑:程序博客网 时间:2024/03/28 20:09

//本文是作者原创文章,其中的代码部分引用了网上现有的demo,感谢大神们无私的奉献各种demo,转载请注明出处

今天在写公司的一个项目,其中用到了定位的功能,想到网上有很多现成的demo,兴致冲冲的找了很多demo,都没有想要的效果,网上现有的demo获取数据的方法大致分为两种:
<1> 将包含了地址信息的数据库文件(.db文件)存在项目的assets文件里面。
<2> 将地址信息放在arrays.xml文件里面,例如:

                 <string-array name="city">                        <item>北京</item>                        <item>成都</item>                        <item>重庆</item>                        <item>广州</item>                        <item>杭州</item>                        <item>南京</item>                        <item>上海</item>                        <item>深圳</item>                        <item>天津</item>                        <item>武汉</item>                        <item>西安</item>                    </string-array>

然而这些都不是我想要的效果,Boss要求地址的数据在后期是可以修改的,
所以获取地址就必要链接网络服务器,在网上找了个仿美图的地址选择器,页面效果如下:

仿美团地址选择器

然而打开demo后就绝望了,
自动定位的功能只能看不能用就算了,用的竟然是第二种方法存数据…..
那岂不是说我得将300多条数据一点点的写到arrays.xml文件里面?于是仔细的看了该demo的代码,修改如下:

import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.os.Build;import android.os.Bundle;import android.text.Editable;import android.text.TextUtils;import android.text.TextWatcher;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.Window;import android.view.WindowManager;import android.widget.AdapterView;import android.widget.BaseAdapter;import android.widget.Button;import android.widget.GridView;import android.widget.ImageView;import android.widget.ListView;import android.widget.SectionIndexer;import android.widget.TextView;import android.widget.Toast;import com.amap.api.location.AMapLocation;import com.amap.api.location.AMapLocationClient;import com.amap.api.location.AMapLocationClientOption;import com.amap.api.location.AMapLocationListener;import com.example.myapplication.R;import com.example.myapplication.model.bean.CitySortModel;import com.example.myapplication.model.db.CityHelper;import com.example.myapplication.model.utils.ACache;import com.example.myapplication.model.utils.PortUtils;import com.example.myapplication.model.utils.SystemBarTintManager;import com.example.myapplication.view.activity.BaseActivity;import com.example.myapplication.view.selectcity.view.EditTextWithDel;import com.example.myapplication.view.selectcity.view.PinyinComparator;import com.example.myapplication.view.selectcity.view.PinyinUtils;import com.example.myapplication.view.selectcity.view.SideBar;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONObject;import org.xutils.common.Callback;import org.xutils.http.RequestParams;import org.xutils.x;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Collections;import java.util.Date;import java.util.List;/** 城市选择和定位* */public class CityActivity extends BaseActivity {    private String TAG = "CityActivity";    private ListView sortListView;    private SideBar sideBar;    private TextView dialog, mTvTitle;    private SortAdapter adapter;    private EditTextWithDel mEtCityName;    private List<CitySortModel> SourceDateList;//省份集合    private ImageView city_back;//返回键    private TextView city_commit;//确认    private ACache aCache;//缓存    private BroadcastMain receiver;//广播接收者    private Button button;    private List<String> list;    //声明AMapLocationClient类对象    public AMapLocationClient mLocationClient = null;    //声明AMapLocationClientOption对象    public AMapLocationClientOption mLocationOption = null;    //内部类,实现BroadcastReceiver    public class BroadcastMain extends BroadcastReceiver {        //必须要重载的方法,用来监听是否有广播发送        @Override        public void onReceive(Context context, Intent intent) {            //将收到的广播信息填充到标题栏            mTvTitle.setText(intent.getStringExtra("CITY"));        }    }    private CityHelper helper;//存放城市信息的数据库    private SQLiteDatabase read;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        /****************         * 沉浸式状态栏**         * **************         * */        //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {        //    Window window = getWindow();        //    // Translucent status bar        //    window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,        //            WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);        //    SystemBarTintManager tintManager = new SystemBarTintManager(this);        //    tintManager.setStatusBarTintEnabled(true);        //    tintManager.setStatusBarTintResource(R.color.tomato);// 通知栏所需颜色       // }        setContentView(R.layout.activity_city);        //初始化广播接收者        receiver = new BroadcastMain();        //在代码中注册广播接收程序        IntentFilter filter = new IntentFilter();        filter.addAction("city.choose");        registerReceiver(receiver, filter);        //初始化高德SDK定位配置        initLocationSDK();        //初始化控件        initViews();    }    private void initLocaitonSDK(){ //初始化定位        mLocationClient = new AMapLocationClient(getApplicationContext());        //设置定位回调监听        mLocationClient.setLocationListener(mAMapLocationListener);        //初始化AMapLocationClientOption对象        mLocationOption = new AMapLocationClientOption();        //设置定位模式为AMapLocationMode.Hight_Accuracy,高精度模式。        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);        //获取一次定位结果:        //该方法默认为false。        mLocationOption.setOnceLocation(true);        //获取最近3s内精度最高的一次定位结果:        //设置setOnceLocationLatest(boolean b)接口为true,启动定位时SDK会返回最近3s内精度最高的一次定位结果。        // 如果设置其为true,setOnceLocation(boolean b)接口也会被设置为true,反之不会,默认为false。        mLocationOption.setOnceLocationLatest(true);        //设置定位间隔,单位毫秒,默认为2000ms,最低1000ms。        mLocationOption.setInterval(1000);        //设置是否返回地址信息(默认返回地址信息)        mLocationOption.setNeedAddress(true);        //设置是否强制刷新WIFI,默认为true,强制刷新。        mLocationOption.setWifiActiveScan(false);        //设置是否允许模拟位置,默认为false,不允许模拟位置        mLocationOption.setMockEnable(false);        //单位是毫秒,默认30000毫秒,建议超时时间不要低于8000毫秒。        mLocationOption.setHttpTimeOut(20000);        //关闭缓存机制        mLocationOption.setLocationCacheEnable(false);        //给定位客户端对象设置定位参数        mLocationClient.setLocationOption(mLocationOption);    }    //可以通过类implement方式实现AMapLocationListener接口,也可以通过创造接口类对象的方法实现    AMapLocationListener mAMapLocationListener = new AMapLocationListener() {        @Override        public void onLocationChanged(AMapLocation amapLocation) {            if (amapLocation != null) {                if (amapLocation.getErrorCode() == 0) {                    //解析amapLocation获取相应内容。                   // amapLocation.getLocationType();//获取当前定位结果来源,如网络定位结果,详                    见定位类型表                   // amapLocation.getLatitude();//获取纬度                   // amapLocation.getLongitude();//获取经度                   // amapLocation.getAccuracy();//获取精度信息                   // amapLocation.getAddress();//地址,如果option中设置isNeedAddress为                   // false,则没有此结果,网络定位结果中会有地址信息,                    // GPS定位不返回地址信息。                   // amapLocation.getCountry();//国家信息                   // amapLocation.getProvince();//省信息                    String city = amapLocation.getCity();//城市信息                   // amapLocation.getDistrict();//城区信息                    //amapLocation.getStreet();//街道信息                   // amapLocation.getStreetNum();//街道门牌号信息                   // amapLocation.getCityCode();//城市编码                   // amapLocation.getAdCode();//地区编码                   // amapLocation.getAoiName();//获取当前定位点的AOI信息                   // amapLocation.getBuildingId();//获取当前室内定位的建筑物Id                   // amapLocation.getFloor();//获取当前室内定位的楼层                    //获取定位时间                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");                    Date date = new Date(amapLocation.getTime());                    df.format(date);                    button.setText(city);                    mTvTitle.setText(city);                    aCache.put("city", city);                    Log.i(TAG,"----------" + city);                } else {                    //定位失败时,可通过ErrCode(错误码)信息来确定失败的原因,errInfo是错误信息                    Log.e("AmapError", "location Error, ErrCode:"                            + amapLocation.getErrorCode() + ", errInfo:"                            + amapLocation.getErrorInfo());                }            }        }    };    private void initViews() {        aCache = ACache.get(this);//获取缓存        helper = new CityHelper(this, "city", null, 1);//初始化数据库        read = helper.getReadableDatabase();//拿到读取的read        city_back = (ImageView) findViewById(R.id.city_back);        city_commit = (TextView) findViewById(R.id.city_commit);        mEtCityName = (EditTextWithDel) findViewById(R.id.et_search);        sideBar = (SideBar) findViewById(R.id.sidrbar);        dialog = (TextView) findViewById(R.id.dialog);        mTvTitle = (TextView) findViewById(R.id.tv_title);        sortListView = (ListView) findViewById(R.id.country_lvcountry);        //填充控件        initDatas();        //填充省份数据        setAdapter();    }    private void setAdapter() {        //填充省份数据        SourceDateList = filledData(getDB());        Collections.sort(SourceDateList, new PinyinComparator());        sortListView.addHeaderView(initHeadView());        adapter = new SortAdapter(CityActivity.this, SourceDateList);        sortListView.setAdapter(adapter);//填充listview        //点击事件        initEvents();    }    private void initEvents() {        //设置右侧触摸监听        sideBar.setOnTouchingLetterChangedListener(new SideBar.OnTouchingLetterChangedListener() {            @Override            public void onTouchingLetterChanged(String s) {                //该字母首次出现的位置                int position = adapter.getPositionForSection(s.charAt(0));                if (position != -1) {                    sortListView.setSelection(position + 1);                }            }        });        //ListView的点击事件        sortListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> parent, View view,                                    int position, long id) {                //因为头文件的存在(占用了一个栏位),所以选择的城市的下标(position)需要 -1 ;                mTvTitle.setText(((CitySortModel) adapter.getItem(position - 1)).getName());                Toast.makeText(getApplication(), ((CitySortModel) adapter.getItem(position - 1)).getName(), Toast.LENGTH_SHORT).show();                aCache.put("city", ((CitySortModel) adapter.getItem(position - 1)).getName());            }        });        //根据输入框输入值的改变来过滤搜索        mEtCityName.addTextChangedListener(new TextWatcher() {            @Override            public void beforeTextChanged(CharSequence s, int start, int count, int after) {            }            @Override            public void onTextChanged(CharSequence s, int start, int before, int count) {                //当输入框里面的值为空,更新为原来的列表,否则为过滤数据列表                filterData(s.toString());            }            @Override            public void afterTextChanged(Editable s) {            }        });        city_back.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                finish();            }        });        city_commit.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                finish();            }        });    }    private void initDatas() {        sideBar.setTextView(dialog);    }    //定位,热门城市    private View initHeadView() {        View headView = getLayoutInflater().inflate(R.layout.headview, null);        GridView mGvCity = (GridView) headView.findViewById(R.id.gv_hot_city);        String[] datas = new String[]{"北京","上海","深圳","长沙","武汉","吉林"};//热门城市        //填充热门城市数据        final ArrayList<String> cityList = new ArrayList<>();        for (int i = 0; i < datas.length; i++) {            cityList.add(datas[i]);        }        CityAdapter adapter = new CityAdapter(getApplicationContext(), R.layout.gridview_item, cityList);        mGvCity.setAdapter(adapter);        button = (Button) headView.findViewById(R.id.btn_city_name);        //启动定位        mLocationClient.startLocation();        //点击定位操作        button.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Toast.makeText(CityActivity.this, "定位中....", Toast.LENGTH_SHORT).show();                //启动定位                mLocationClient.startLocation();            }        });        return headView;    }    /**     * 根据输入框中的值来过滤数据并更新ListView     */    private void filterData(String filterStr) {        List<CitySortModel> mSortList = new ArrayList<>();        if (TextUtils.isEmpty(filterStr)) {            mSortList = SourceDateList;        } else {            mSortList.clear();            for (CitySortModel sortModel : SourceDateList) {                String name = sortModel.getName();                if (name.toUpperCase().indexOf(filterStr.toString().toUpperCase()) != -1 || PinyinUtils.getPingYin(name).toUpperCase().startsWith(filterStr.toString().toUpperCase())) {                    mSortList.add(sortModel);                }            }        }        // 根据a-z进行排序        Collections.sort(mSortList, new PinyinComparator());        adapter.updateListView(mSortList);    }    //返回城市的名称的集合    private List<CitySortModel> filledData(List<CitySortModel> date) {        List<CitySortModel> mSortList = new ArrayList<>();        ArrayList<String> indexString = new ArrayList<>();        for (int i = 0; i < date.size(); i++) {            CitySortModel sortModel = new CitySortModel();            sortModel.setName(date.get(i).getName());            String pinyin = PinyinUtils.getPingYin(date.get(i).getName());            String sortString = pinyin.substring(0, 1).toUpperCase();            if (sortString.matches("[A-Z]")) {                sortModel.setSortLetters(sortString.toUpperCase());                if (!indexString.contains(sortString)) {                    indexString.add(sortString);                }            }            mSortList.add(sortModel);        }        Collections.sort(indexString);        sideBar.setIndexText(indexString);        return mSortList;    }    class SortAdapter extends BaseAdapter implements SectionIndexer {        private List<CitySortModel> list = null;        private Context mContext;        public SortAdapter(Context mContext, List<CitySortModel> list) {            this.mContext = mContext;            this.list = list;        }        /**         * 当ListView数据发生变化时,调用此方法来更新ListView         */        public void updateListView(List<CitySortModel> list) {            this.list = list;            notifyDataSetChanged();        }        public int getCount() {            return this.list.size();        }        public Object getItem(int position) {            return list.get(position);        }        public long getItemId(int position) {            return position;        }        public View getView(final int position, View view, ViewGroup arg2) {            ViewHolder viewHolder = null;            final CitySortModel mContent = list.get(position);            if (view == null) {                viewHolder = new ViewHolder();                view = LayoutInflater.from(mContext).inflate(R.layout.item_select_city, null);                viewHolder.tvTitle = (TextView) view.findViewById(R.id.tv_city_name);                viewHolder.tvLetter = (TextView) view.findViewById(R.id.tv_catagory);                view.setTag(viewHolder);            } else {                viewHolder = (ViewHolder) view.getTag();            }            int section = getSectionForPosition(position);            if (position == getPositionForSection(section)) {                viewHolder.tvLetter.setVisibility(View.VISIBLE);                viewHolder.tvLetter.setText(mContent.getSortLetters());            } else {                viewHolder.tvLetter.setVisibility(View.GONE);            }            viewHolder.tvTitle.setText(list.get(position).getName());            return view;        }        class ViewHolder {            TextView tvLetter;            TextView tvTitle;        }        public int getSectionForPosition(int position) {            return list.get(position).getSortLetters().charAt(0);        }        public int getPositionForSection(int section) {            for (int i = 0; i < getCount(); i++) {                String sortStr = list.get(i).getSortLetters();                char firstChar = sortStr.toUpperCase().charAt(0);                if (firstChar == section) {                    return i;                }            }            return -1;        }        @Override        public Object[] getSections() {            return null;        }    }    @Override    protected void onPause() {        super.onPause();        mLocationClient.stopLocation();//停止定位后,本地定位服务并不会被销毁    }    @Override    protected void onDestroy() {        super.onDestroy();        unregisterReceiver(receiver);//取消广播注册        mLocationClient.onDestroy();//销毁定位客户端,同时销毁本地定位服务。    }    //读取所有城市数据库    public List<CitySortModel> getDB() {        final List<CitySortModel> list = new ArrayList<>();        Cursor cursor = read.rawQuery("select * from city order by _id asc", null);//查询所有城市        while (cursor.moveToNext()) {            CitySortModel sortModel = new CitySortModel();            sortModel.setId(cursor.getString(cursor.getColumnIndex("_id")));            sortModel.setName(cursor.getString(cursor.getColumnIndex("name")));            list.add(sortModel);        }        return list;    }}

主要代码就是这些,大部分都写有注释,应该不难理解,具体代码稍后会上传。

遇到的第二个问题就是SQLite操作的时候报了datebase is locked的问题,很常见的问题,
网上给的很多解决办法对于初学者来说都很难理解,有一个比较简单的办法,就是开启一个service服务,
在service里面进行SQLite的写入操作,读取数据库的时候最好是判断一下数据库是否是开启状态。
SQLite是一个轻量级的数据库,最多开启线程池不能超过两个。

遇到的第三问题就是在开启service服务的时候,写了startService(new Intent(this,MyService.class));
然而县城并没有开启,检查了很久才发现是忘了在Androidmanifest.xml文件里面注册service服务。

以上为今天遇到的问题的全部,如果有碰到同样问题的朋友,可以参考一下我的办法。
代码片段应该能解决定位中遇到的问题了(高德地图的集成请前往高德地图API官网自行查看),
具体的代码正在从项目中抽取。
第一次写博客,如有不成熟或者错误的地方,欢迎大家指出,如果有更好的想法,也期待您的无私分享。

demo下载地址

点击此处下载demo

2 0