手机卫士-05
手機衛士-05
課1
模仿網易新聞下拉加載分頁數據listView
在activtiycallsafe.xml里重新修改(去掉原來的button)
activtiycallsafe.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" ><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" ><TextViewstyle="@style/textview_title_style"android:layout_height="60dp"android:gravity="center"android:text="通訊衛士" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:onClick="addBlackNumber"android:text="添加" /></RelativeLayout><!-- android:fastScrollEnabled="true" 設置快速滑動 --><FrameLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:layout_weight="10" ><LinearLayoutandroid:id="@+id/ll_loading"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:orientation="vertical"android:visibility="invisible" ><ProgressBarandroid:layout_width="wrap_content"android:layout_height="wrap_content" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="玩命加載中...." /></LinearLayout><ListViewandroid:id="@+id/list_view"android:layout_width="match_parent"android:layout_height="match_parent"android:divider="@drawable/list_devider"android:fastScrollEnabled="true" /></FrameLayout></LinearLayout>在CallSafeActivity.class里重新修改
list_view.setOnScrollListener//初始化listview的滾動監聽 在方法里有分別識別(慣性滑動、當滾動然后停下來閑置的時候、在觸摸屏幕的時候調用方法)的操作 現在目的是下拉滑動的數據到20條截止就再請求數據庫獲取數據 在case OnScrollListener.SCROLLSTATEIDLE里進行操作
CallSafeActivity.class
list_view.setOnScrollListener(new OnScrollListener() {@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {switch (scrollState) {// 慣性滑動case OnScrollListener.SCROLL_STATE_FLING:break;// 當滾動然后停下來閑置的時候case OnScrollListener.SCROLL_STATE_IDLE:// 最后一個顯示可見的位置int lastVisiblePosition = list_view.getLastVisiblePosition();System.out.println("lastVisiblePosition----->"+ lastVisiblePosition);if (lastVisiblePosition == lists.size() - 1) {startIndex += pageCount;if (startIndex > countTotal) {Toast.makeText(CallSafeActivity.this,"沒有更多的數據進行加載了", 0).show();return;}}initData();break;// 在觸摸屏幕的時候調用的方法case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:break;}}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {// TODO Auto-generated method stub}});在BlackNumberDao里繼續加功能(分批加載數據)
CallSafeActivity.class里使用分批加載數據的方法(首先定義好startIndex、pageCount初始化了)
CallSafeActivity.class
/*** 從第0條數據進行加載*/ private int startIndex = 0; /*** 每頁最多的加載數據*/ private int pageCount = 20; 調用lists = dao.findPage2() BlackNumberDao.java/*** 分批加載數據* * @param startIndex* 開始數據的條目* @param pageCount* 每頁最多加載多少條數據* @return 返回一個黑名單的集合數據*/ public List<BlackNumberInfo> findPage2(int startIndex, int pageCount) {SQLiteDatabase db = helper.getReadableDatabase();Cursor cursor = db.rawQuery("select number,mode from blackinfo order by _id desc limit ? offset ?",new String[] { String.valueOf(pageCount),String.valueOf(startIndex) });// 初始化黑名單的集合ArrayList<BlackNumberInfo> lists = new ArrayList<BlackNumberInfo>();while (cursor.moveToNext()) {BlackNumberInfo info = new BlackNumberInfo();info.setMode(cursor.getString(1));info.setNumber(cursor.getString(0));lists.add(info);}cursor.close();db.close();return lists; }但是這樣做加載后就把之前的給覆蓋了 解決小bug,在使用lists = dao.findPage2()的時候加個判斷,如果lists!=null,就再lists里追加加載后的數據。
CallSafeActivity.class
// 當滾動然后停下來閑置的時候 case OnScrollListener.SCROLL_STATE_IDLE:// 最后一個顯示可見的位置int lastVisiblePosition = list_view.getLastVisiblePosition();System.out.println("lastVisiblePosition----->"+ lastVisiblePosition);if (lastVisiblePosition == lists.size() - 1) {startIndex += pageCount;if (startIndex > countTotal) {Toast.makeText(CallSafeActivity.this,"沒有更多的數據進行加載了", 0).show();return;}}initData();break;繼續解決小bug,由于每次都追加后都new一個新的adapter,所以在new一個適配器時需要進行判斷,如果已經有適配器時,就使用刷新界面的適配器方法notifyDataSetChanged
CallSafeActivity.class
//判斷當前的結果值是否添加成功 boolean result = dao.add(phone, mode);if(result){if(adapter == null){CallSafeAdapter adapter = new CallSafeAdapter(CallSafeActivity.this, lists);list_view.setAdapter(adapter);}else{adapter.notifyDataSetChanged();}}繼續實現黑名單里的刪除圖片的刪除功能 在getView里添加圖片控件,并讓holder去管理
itemcallsafe.xml
<ImageView android:id="@+id/iv_delete"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/delet_selector"android:layout_centerVertical="true"android:layout_alignParentRight="true"android:layout_marginRight="10dp"/>ViewHolder的詳解(減低ListView里工作)
holder用來管理ListView里的GetView所綁定的xml文件里的控件 簡單來說就是通過在下面 private class ViewHolder { TextView tvnumber; TextView tvmode; ImageView iv_delete; } ViewHolder里管理的控件變量,當在獲取getView要綁定的xml資源到View view時,通過在綁定后把holder里管理的變量通過該view去findViewById獲取對象并添加一個標記view.setTag(holder);,那么每次getView時就可以實現不用重復再重復的去findViewById獲取對象,這就可以節省手機的cpu處理資源,大大減低ListView的效率在設置的點擊事件里進行操作集合移除的操作
但是如果不使用adapter的刷新方法,那么也看不出馬上被刪除的效果,解決這個小bug
CallSafeActivity.class
private class ViewHolder {TextView tv_number;TextView tv_mode;ImageView iv_delete; }private class CallSafeAdapter extendsMyBaseAdapter<BlackNumberInfo, ListView> {private View view;private ViewHolder holder;//private BlackNumberInfo info;public CallSafeAdapter(CallSafeActivity callSafeActivity,List<BlackNumberInfo> lists) {super(lists, callSafeActivity);}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {if (convertView == null) {view = View.inflate(context, R.layout.item_call_safe, null);holder = new ViewHolder();holder.tv_number = (TextView) view.findViewById(R.id.tv_number);holder.tv_mode = (TextView) view.findViewById(R.id.tv_mode);holder.iv_delete = (ImageView) view.findViewById(R.id.iv_delete);// 添加一個標記view.setTag(holder);} else {view = convertView;holder = (ViewHolder) view.getTag();}final BlackNumberInfo info = lists.get(position);System.out.println("---------------------"+info.getNumber());//給imageview設置刪除點擊事件holder.iv_delete.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubString blackNumber = info.getNumber();//刪除黑名單電話號碼boolean result = dao.delete(blackNumber);//從集合里面移除黑名單電話號碼lists.remove(info);if(result){adapter.notifyDataSetChanged();}}});
課2
繼續在黑名單里加上添加黑名單按鈕的功能 在activitycallsafe.xml增加按鈕控件
activitycallsafe.xml
<Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:onClick="addBlackNumber"android:text="添加" />在CallSafeActivity.java里為按鈕方法添加一個對話框
CallSafeActivity.java
/*** 添加黑名單電話號碼* @param view*/ public void addBlackNumber(View view){AlertDialog.Builder builder = new Builder(this);View dialogview = View.inflate(CallSafeActivity.this, R.layout.dialog_add_black_number, null);final EditText et_phone = (EditText) dialogview.findViewById(R.id.et_phone);final CheckBox cb_phone = (CheckBox) dialogview.findViewById(R.id.cb_phone);final CheckBox cb_sms = (CheckBox) dialogview.findViewById(R.id.cb_sms);//取消dialogview.findViewById(R.id.bt_cancel).setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubdialog.dismiss();}});//確定dialogview.findViewById(R.id.bt_ok).setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {String mode = "0";String phone = et_phone.getText().toString().trim();//判斷當前的電話號碼是否有值if(TextUtils.isEmpty(phone)){Toast.makeText(CallSafeActivity.this, "請輸入電話號碼", 0).show();return ;}/*** 攔截模式 1 全部攔截 2 短信攔截 3 電話攔截*/if(cb_phone.isChecked() && cb_sms.isChecked()){mode = "1";}else if(cb_phone.isChecked()){mode = "3";}else if(cb_sms.isChecked()){mode = "2";}else{Toast.makeText(CallSafeActivity.this, "請勾選攔截模式", 0).show();return;}BlackNumberInfo info = new BlackNumberInfo();info.setMode(mode);info.setNumber(phone);lists.add(0,info);//判斷當前的結果值是否添加成功boolean result = dao.add(phone, mode);if(result){if(adapter == null){CallSafeAdapter adapter = new CallSafeAdapter(CallSafeActivity.this, lists);list_view.setAdapter(adapter);}else{adapter.notifyDataSetChanged();}}dialog.dismiss();}});builder.setView(dialogview);dialog = builder.show(); }實現對話框的布局dialogaddblack_number.xml
dialogaddblack_number.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" ><TextViewandroid:layout_width="match_parent"android:layout_height="40dp"android:background="#5500ff00"android:gravity="center"android:text="黑名單電話號碼添加"android:textSize="24sp" /><EditTextandroid:id="@+id/et_phone"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="請輸入電話號碼"android:inputType="phone" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal" ><CheckBoxandroid:id="@+id/cb_phone"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="電話攔截" /><CheckBoxandroid:id="@+id/cb_sms"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="短信攔截" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal" ><Buttonandroid:id="@+id/bt_ok"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:background="@drawable/btn_selector"android:text="確定" /><Buttonandroid:id="@+id/bt_cancel"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:background="@drawable/btn_selector"android:text="取消" /></LinearLayout></LinearLayout>
設計完畢后就繼續注入dialogView去使用。
CallSafeActivity.java
AlertDialog.Builder builder = new Builder(this);View dialogview = View.inflate(CallSafeActivity.this, R.layout.dialog_add_black_number, null);final EditText et_phone = (EditText) dialogview.findViewById(R.id.et_phone);final CheckBox cb_phone = (CheckBox) dialogview.findViewById(R.id.cb_phone);final CheckBox cb_sms = (CheckBox) dialogview.findViewById(R.id.cb_sms);(技巧)我們可以設置dialog里面的一個方法setCanceledOnTouchOutside(true);的一個方法去鎖定提示框
AlertDialog dialog = builder.show(); dialog.setCanceledOnTouchOutside(true);主要邏輯是對話框里的確定按鈕響應事件
1、拿到EditText里的內容 2、判斷checkBox是否有勾上 3、操作賦值 4、更新適配器CallSafeActivity.java
//確定 dialogview.findViewById(R.id.bt_ok).setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {String mode = "0";String phone = et_phone.getText().toString().trim();//判斷當前的電話號碼是否有值if(TextUtils.isEmpty(phone)){Toast.makeText(CallSafeActivity.this, "請輸入電話號碼", 0).show();return ;}/*** 攔截模式 1 全部攔截 2 短信攔截 3 電話攔截*/if(cb_phone.isChecked() && cb_sms.isChecked()){mode = "1";}else if(cb_phone.isChecked()){mode = "3";}else if(cb_sms.isChecked()){mode = "2";}else{Toast.makeText(CallSafeActivity.this, "請勾選攔截模式", 0).show();return;}BlackNumberInfo info = new BlackNumberInfo();info.setMode(mode);info.setNumber(phone);lists.add(0,info);//判斷當前的結果值是否添加成功boolean result = dao.add(phone, mode);if(result){if(adapter == null){CallSafeAdapter adapter = new CallSafeAdapter(CallSafeActivity.this, lists);list_view.setAdapter(adapter);}else{adapter.notifyDataSetChanged();}}dialog.dismiss();} });bug,如果添加的話,它會加載到lists的最后,解決lists.add(position,xxx); 解決了上一個bug之后,發現關掉該頁面后再打開,lists還是按順序展示,所以我們需要修改dao層里的數據庫的sql
BlackNumberDao.java
public List<BlackNumberInfo> findPage2(int startIndex, int pageCount) {SQLiteDatabase db = helper.getReadableDatabase();Cursor cursor = db.rawQuery("select number,mode from blackinfo order by _id desc limit ? offset ?",new String[] { String.valueOf(pageCount),String.valueOf(startIndex) });
真正實現電話和信息攔截的功能 首先實現電話攔截 短信攔截:在清單文件里已經實現過了(靜態注冊過了) 今天實現短信攔截的動態注冊
在之前學過activitysettingcenter.xml里添加二維碼的布局
activitysettingcenter.xml
<TextViewandroid:layout_width="match_parent"android:layout_height="40dp"android:background="@drawable/list_selector"android:clickable="true"android:enabled="true"android:focusable="true"android:onClick="about"android:text="關于我們"android:textSize="24sp" /><Viewandroid:layout_width="match_parent"android:layout_height="1dp"android:background="@drawable/list_devider" /><TextViewandroid:layout_width="match_parent"android:layout_height="40dp"android:background="@drawable/list_selector"android:clickable="true"android:enabled="true"android:focusable="true"android:text="掃一掃"android:textSize="24sp" /><Viewandroid:layout_width="match_parent"android:layout_height="1dp"android:background="@drawable/list_devider" />
二維碼實現 顏色選擇器添加:在value里新建color.xml--->然后在新建的listselector.xml來調用,然后再在關于的TextView里調用 activityabount.xml--->ImageView 里加上一個網上下載的二維碼圖片在abountActivity.class注入,然后通過SettingCenterActivity.java里的關于(點擊時加上選擇器)跳到abountActivity.class里 并在SettingCenterActivity.java里實現二維碼功能--->調到處理二維碼的類:abountActivity.class
AboutActivity.java
public class AboutActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_about);} }清單文件加上activity節點
<!-- 關于 --> <activityandroid:name="com.itheima.mobile47.AboutActivity"android:screenOrientation="portrait" > </activity>布置布局文件activity_abount.xml--->ImageView
activity_about.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center_horizontal"android:textSize="24sp"android:background="#ff0000"android:text="關于" /><ImageViewandroid:layout_width="200dp"android:layout_height="200dp"android:layout_centerInParent="true"android:background="@drawable/qrcode" /></RelativeLayout>
課3
繼續在xx實現掃一掃的功能 zxing的githut里下載二維碼的開源代碼 移植到項目中 然后通過順藤摸瓜去找到項目如何把鏈接顯示在照片上,然后找到首頁面,首頁面所支持的TextView,然后在TextView要setText時找到大致的地方去截取要set的地址值,然后進行處理
繼續在activitysettingcenter.xml設置中心布局里實現黑名單攔截功能打開
在SettingCenterActivity.java里加上響應事件里增加功能 使用服務實現功能 新建黑名單攔截服務:CallSafeService.java
四大組件配置清單文件(服務)
true:開啟服務、false:關閉服務,在手機本地的應用服務里查看沒加功能的服務開啟沒
SettingCenterActivity.java
@Override protected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_setting_center);intent = new Intent(this,CallSafeService.class);//黑名單設置setting_view_black.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {if(setting_view_black.isChecked()){setting_view_black.setChecked(false);stopService(intent);}else{setting_view_black.setChecked(true);startService(intent);}}});繼續實現服務功能CallSafeService.java 過濾器是廣播的一種實現receiver節點里的action節點 在CallSafeService.java動態注冊短信的廣播,然后在filter里設置setPriority,在然后就registerReceiver
CallSafeService.java
public class CallSafeService extends Service {private BlackNumberDao dao; private TelephonyManager tm;@Override public IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn null; }@Override public void onCreate() {// TODO Auto-generated method stubsuper.onCreate();// 獲取到黑名單的數據dao = new BlackNumberDao(this);// 獲取到電話相關的服務tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);// 初始化電話狀態的監聽MyPhoneStateListener listener = new MyPhoneStateListener();tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);// 初始化內部攔截短信的廣播InnerSmsReceiver receiver = new InnerSmsReceiver();// 初始化一個短信攔截的actionIntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");filter.setPriority(Integer.MAX_VALUE);// 注冊短信的廣播registerReceiver(receiver, filter); }在內部類InnerSmsReceiver實現短信攔截的功能
CallSafeService.java
private class InnerSmsReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// 獲取到短信Object[] objs = (Object[]) intent.getExtras().get("pdus");for (Object obj : objs) {SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) obj);// 獲取到短信的電話號碼String number = smsMessage.getOriginatingAddress();// 獲取到短信的內容String body = smsMessage.getMessageBody();// 獲取到攔截模式String mode = dao.findNumberMode(number);// 如果是全部攔截或者是短信攔截。那么就全部攔截下來if (mode.equals("1") || mode.equals("2")) {System.out.println("攔截下來了");abortBroadcast();}// 智能攔截if (body.contains("fapiao")) {System.out.println("垃圾短信攔截下來了");abortBroadcast();}}}}在onCreate里操作dao通過電話號碼獲取攔截模式,然后給內部類
String mode = dao.findNumberMode(number); // 如果是全部攔截或者是短信攔截。那么就全部攔截下來 if (mode.equals("1") || mode.equals("2")) {System.out.println("攔截下來了");abortBroadcast(); }InnerSmsReceiver實現短信攔截的功能abortBroadcast(),我們可以把短信服務理解為一個有序廣播,然后我們通過條件定位到手機號,當服務一促發就查詢dao,當對比有該號碼就攔截abortBroadcast()。 該服務打開時繼續設置一個方法攔截一些垃圾短信,只要短信body包含了一些我們自己我想見到信息內容,就abortBroadcast(),上下文的方法
繼續在CallSafeService實現電話號碼攔截
使用getSystemService(TelephonyManager)獲得電話服務,然后繼續實現,這是之前學習服務時候學習過的電話竊聽的一個例子 在電話不同的狀態下進行攔截操作。(在手機鈴響時就使用dao查詢攔截的模式,從而進行分類攔截)
課4
繼續實現攔截短信中結束電話的方法(在TelephonyManager查看源碼):CallSafeService.class TelephonyManager里的getService是關于服務的知識,回憶起老師當時的調用遠程服務的例子 掛掉電話的方法(觀察源碼后想到的方法) endcall()://使用反射的方法獲得類 然后再獲取方法,然后獲取到ibunder遠程服務(getService) 把遠程服務的aidl拿過來 放在和該aidl一樣的包名里(打開aidl里查看包名) 最后調用遠程服務,把ibunder傳進去,最后調用endcall()系統遠程服務來掛斷電話 課下回憶老師教我們遠程服務的實例對比今天的課的內容 解決小bug,在設置中心關閉服務,但是后臺服務卻沒有關,如何控制呢?把開關標記存在sp不合適,因為在應用設置處清除數據后sp沒了,但是服務卻依然在跑。 新建類ServiceIsRunning.java,該util類用來判斷服務是否開啟、 使用ActivityManager來判斷正在運行的一些服務am.getRunningServices(50) 把傳進來的服務名字和系統獲得的服務名字做對比,如果名字相同,就進行關閉操作,然后設置中心SettingCenterActivity.class就使用該工具類來進行開關服務操作onstart();
CallSafeService.java
@Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); // 獲取到黑名單的數據 dao = new BlackNumberDao(this);// 獲取到電話相關的服務tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);// 初始化電話狀態的監聽MyPhoneStateListener listener = new MyPhoneStateListener();tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);// 初始化內部攔截短信的廣播InnerSmsReceiver receiver = new InnerSmsReceiver();// 初始化一個短信攔截的actionIntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");filter.setPriority(Integer.MAX_VALUE);// 注冊短信的廣播registerReceiver(receiver, filter); }private class MyPhoneStateListener extends PhoneStateListener {@Overridepublic void onCallStateChanged(int state, String incomingNumber) {switch (state) {// 閑置狀態case TelephonyManager.CALL_STATE_IDLE:break;// 響鈴狀態case TelephonyManager.CALL_STATE_RINGING:String mode = dao.findNumberMode(incomingNumber);if(mode.equals("1")||mode.equals("3")){System.out.println("電話攔截");//掛斷電話endcall();}break;// 通話狀態case TelephonyManager.CALL_STATE_OFFHOOK:break;}super.onCallStateChanged(state, incomingNumber);}} /** * 掛掉電話 */ public void endcall() {try {//使用類加載器去加載一個類Class<?> clazz = getClassLoader().loadClass("android.os.ServiceManager");//獲取到方法/*** 第一個參數是名字* 第二個參數是類型*/Method method = clazz.getDeclaredMethod("getService", String.class);//實現調用這個方法//第一個參數:如果是靜態的那么就是設置為nullIBinder iBinder = (IBinder) method.invoke(null, TELEPHONY_SERVICE);//通過IBinder對象獲取到ITelephonyITelephony iTelephony = ITelephony.Stub.asInterface(iBinder);//掛斷電話iTelephony.endCall();} catch (Exception e) {e.printStackTrace();}}課5
實現號碼歸屬地查詢 在高級工具里設計case 7 新建ToolsActivity.java 布局activity_tools.xml
activity_tools.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" ><TextViewstyle="@style/textview_title_style"android:gravity="center"android:text="高級工具" /><TextViewandroid:onClick="queryLocation"android:layout_width="match_parent"android:layout_height="wrap_content"android:drawableLeft="@android:drawable/star_big_off"android:textSize="24sp"android:clickable="true"android:focusable="true"android:enabled="true"android:background="@drawable/list_selector"android:text="歸屬地查詢" /></LinearLayout>ToolsActivity.java
public class ToolsActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_tools);}/*** 歸屬地查詢* @param view*/public void queryLocation(View view){Intent intent = new Intent(this,QueryLocationActivity.class);startActivity(intent);} }
回到ToolsActivity.java實現號碼歸屬地查詢:queryLocation--->方法跳到下一個號碼歸屬地查詢的Activity:新建QueryLocationActivity+布局文件activityquerylocation.xml
activityquerylocation.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" ><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/main_title_bg"android:gravity="center"android:text="號碼歸屬地查詢"android:textColor="#fff"android:textSize="24sp" /><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="輸入你要查詢的電話號碼"android:textSize="20sp" /><EditTextandroid:id="@+id/et_number"android:layout_width="match_parent"android:layout_height="wrap_content" /><TextViewandroid:id="@+id/tv_address"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="20sp"android:text="歸屬地信息" /><Button android:onClick="btQuery"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="點擊查詢"/></LinearLayout>QueryLocationActivity.java
public class QueryLocationActivity extends Activity {@ViewInject(R.id.et_number)private EditText et_number;@ViewInject(R.id.tv_address)private TextView tv_address;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_query_location);ViewUtils.inject(this);}/*** 點擊查詢歸屬地* * @param view*/public void btQuery(View view) {String number = et_number.getText().toString().trim();if(TextUtils.isEmpty(number)){Toast.makeText(QueryLocationActivity.this, "請輸入查詢號碼", 0).show();}else{LocationDao dao = new LocationDao();String address = dao.getLocation(number);tv_address.setText("地理位置號碼歸屬地 : " +address);}} }
實現點擊查詢歸屬地的功能btQuery(查詢數據庫) 觀察金山手機衛士發現,清空該app的數據后,重新打開時會自動導入之前的數據庫 因此我們也模擬該app的導入數據庫模式導入,即在打開首頁時就導入進來 先把數據庫放入到assets目錄下 在SplashActivity里加上拷貝數據庫方法copyDB,用來初始化數據庫 把asset里的文件流拷貝到data/data下 考慮到如果拷貝的數據比較大,所以使用子線程來作拷貝操作 這里使用線程池來執行線程操作
SplashActivity.java
@Override protected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);// 設置沒有標題 必須寫到setcontview前面requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_splash);ViewUtils.inject(this);// ImageView image_view = (ImageView) findViewById(R.id.image_view);// image_view.setBackgroundResource(R.drawable.ic_launcher);// 獲取到包的管理者。PackageManager pm = getPackageManager();try {// 拷貝數據庫到data/data目錄下面copyDB("address.db");SplashActivity.java
/*** 拷貝數據庫* * @param dbName* 數據庫的名字*/ private void copyDB(String dbName) {ExecutorService executorService = Executors.newFixedThreadPool(1);TaskRunnable taskRunnable = new TaskRunnable(dbName);executorService.execute(taskRunnable);}private class TaskRunnable implements Runnable {private String dbName = null;public TaskRunnable(String dbName) {this.dbName = dbName;}@Overridepublic void run() {try {InputStream is = getAssets().open(dbName);// 獲取到一個輸出流.// 第一個參數是數據庫的名字。第二個參數是模式。設置是私有的FileOutputStream fos = openFileOutput(dbName, 0);byte[] buffer = new byte[1024];int len = 0;while ((len = is.read(buffer)) != -1) {fos.write(buffer, 0, len);}is.close();fos.close();} catch (Exception e) {e.printStackTrace();}} }繼續實現號碼歸屬地查詢,QueryLocationActivity中的btQuery 在edittext里進行輸入號碼,然后進行與數據庫查詢比較 新建一個為號碼歸屬地查詢的dao--->getLocation(返回地理位置)
LocationDao.java
public class LocationDao {/*** 返回地理位置* * @param number* 查詢的電話號碼* @return*/public String getLocation(String number) {String location = "";// 獲取到Database// 第一個參數是數據庫的路徑,第二個參數是工廠默認不要。第三個參數是標記。設置只讀SQLiteDatabase db = SQLiteDatabase.openDatabase("/data/data/com.itheima.mobile47/files/address.db", null,SQLiteDatabase.OPEN_READONLY);Cursor cursor = db.rawQuery("select location from data2 where id =( select outkey from data1 where id = ?) ",new String[] { number.substring(0, 7) });if(cursor.moveToNext()){location = cursor.getString(0);}return location;} }(新技巧)在getLocation里獲取數據庫的代碼是SQLiteDatabase db = SQLiteDatabase.openDatabase("/data/data/com.itheima.mobile47/files/address.db",null,SQLiteDatabase.READONLY); 拿到了db后,繼續實現查詢方法。需要做聯表查詢 1、select outkey from data1 where id = 1300020 得到id = 3 2、select location from data2 where id = 3 得到結果
課下對比一下以前使用數據庫的方式和這節課的方式的方式的不同:
那是因為以前我們那樣做是為了先創建一個數據庫,而現在的是數據庫已經存在,所以直接拿到數據庫的對象返回location 回到QueryLocationActivity.class,在btQuery里把location設置到控件TextView里
QueryLocationActivity.java
/*** 點擊查詢歸屬地* * @param view*/ public void btQuery(View view) {String number = et_number.getText().toString().trim();if(TextUtils.isEmpty(number)){Toast.makeText(QueryLocationActivity.this, "請輸入查詢號碼", 0).show();}else{LocationDao dao = new LocationDao();String address = dao.getLocation(number);tv_address.setText("地理位置號碼歸屬地 : " +address);}}技巧小結
如何讓TextView實現可點擊化:在該控件里加上focusable\clickable\enabled來實現
- ViewHolder的詳解(減低ListView里工作)
holder用來管理ListView里的GetView所綁定的xml文件里的控件 簡單來說就是通過在下面 private class ViewHolder { TextView tvnumber; TextView tvmode; ImageView iv_delete; } ViewHolder里管理的控件變量,當在獲取getView要綁定的xml資源到View view時,通過在綁定后把holder里管理的變量通過該view去findViewById獲取對象并添加一個標記view.setTag(holder);,那么每次getView時就可以實現不用重復再重復的去findViewById獲取對象,這就可以節省手機的cpu處理資源,大大減低ListView的效率
在設置的點擊事件里進行操作集合移除的操作
但是如果不使用adapter的刷新方法,那么也看不出馬上被刪除的效果,解決這個小bug
CallSafeActivity.class
private class ViewHolder {TextView tv_number;TextView tv_mode;ImageView iv_delete; } private class CallSafeAdapter extends MyBaseAdapter<BlackNumberInfo, ListView> {private View view;private ViewHolder holder; // private BlackNumberInfo info;public CallSafeAdapter(CallSafeActivity callSafeActivity,List<BlackNumberInfo> lists) {super(lists, callSafeActivity);}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {if (convertView == null) {view = View.inflate(context, R.layout.item_call_safe, null);holder = new ViewHolder();holder.tv_number = (TextView) view.findViewById(R.id.tv_number);holder.tv_mode = (TextView) view.findViewById(R.id.tv_mode);holder.iv_delete = (ImageView) view.findViewById(R.id.iv_delete);// 添加一個標記view.setTag(holder);} else {view = convertView;holder = (ViewHolder) view.getTag();}final BlackNumberInfo info = lists.get(position);System.out.println("---------------------"+info.getNumber());//給imageview設置刪除點擊事件holder.iv_delete.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubString blackNumber = info.getNumber();//刪除黑名單電話號碼boolean result = dao.delete(blackNumber);//從集合里面移除黑名單電話號碼lists.remove(info);if(result){adapter.notifyDataSetChanged();}}});listView里的適配器中數據刷新的技巧,為了節省cpu資源,不用每次顯示listView時都要new出一個新的適配器
private Handler handler = new Handler() {public void handleMessage(android.os.Message msg) {// 設置loading的圖片不可以見ll_loading.setVisibility(View.INVISIBLE);if (lists != null && lists.size() > 0) {//判斷適配器里面是否有數據。第一次為null那么就需要創建一個適配器。//為了防止每一次就重新新建適配器。那么就只需要刷新界面if (adapter == null) {adapter = new CallSafeAdapter(CallSafeActivity.this, lists);list_view.setAdapter(adapter);} else {// 刷新界面adapter.notifyDataSetChanged();}}}; }; 資料下載總結
- 上一篇: VirtualBox安装Mac
- 下一篇: 服装厂岗位说明书