Android項目實戰--手機衛士08--獲取手機聯繫人



最新實戰教程,讓你瞭解Android自動化刷量、作弊與防作弊的那些事,案例:刷友盟統計、批量註冊蘋果帳號




 

首先,我把把昨天忘記了的兩張設置嚮導的圖片放出來先

  

 

我們從上面的第一張圖片可以看到,我們有一個選擇聯繫人這一操作,那麼怎樣才能獲取到手機裏面的聯繫人呢,其實方法有很多的,現在我們來講一下我們這個項目裏面用到的方法

其實要想知道怎樣獲取手機裏面的聯繫人,去看一下Android自己的源碼就知道的了

我們只要把platform/packages/providers/ContactsProvider這一部分的內容下載下來看看就可以的啦

下面是我下載之後,打開裏面的AndroidManifest的內容

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.android.providers.contacts"
        android:sharedUserId="android.uid.shared"
        android:sharedUserLabel="@string/sharedUserLabel">

    <permission
            android:name="com.android.voicemail.permission.READ_WRITE_ALL_VOICEMAIL"
            android:label="@string/read_write_all_voicemail_label"
            android:description="@string/read_write_all_voicemail_description"
            android:permissionGroup="android.permission-group.PERSONAL_INFO"
            android:protectionLevel="signature"
            />

    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.BIND_DIRECTORY_SEARCH" />
    <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
    <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" />
    <uses-permission android:name="com.android.voicemail.permission.READ_WRITE_ALL_VOICEMAIL" />

    <application android:process="android.process.acore"
        android:label="@string/app_label"
        android:icon="@drawable/app_icon"
        android:allowBackup="false">

        <provider android:name="ContactsProvider2"
            android:authorities="contacts;com.android.contacts"
            android:label="@string/provider_label"
            android:multiprocess="false"
            android:exported="true"
            android:readPermission="android.permission.READ_CONTACTS"
            android:writePermission="android.permission.WRITE_CONTACTS">
            <path-permission
                    android:pathPrefix="/search_suggest_query"
                    android:readPermission="android.permission.GLOBAL_SEARCH" />
            <path-permission
                    android:pathPrefix="/search_suggest_shortcut"
                    android:readPermission="android.permission.GLOBAL_SEARCH" />
            <path-permission
                    android:pathPattern="/contacts/.*/photo"
                    android:readPermission="android.permission.GLOBAL_SEARCH" />
            <grant-uri-permission android:pathPattern=".*" />
        </provider>

        <provider android:name="CallLogProvider"
            android:authorities="call_log"
            android:syncable="false" android:multiprocess="false"
            android:exported="true"
            android:readPermission="android.permission.READ_CALL_LOG"
            android:writePermission="android.permission.WRITE_CALL_LOG">
        </provider>

        <provider android:name="VoicemailContentProvider"
            android:authorities="com.android.voicemail"
            android:syncable="false" android:multiprocess="false"
            android:exported="true"
            android:permission="com.android.voicemail.permission.ADD_VOICEMAIL">
        </provider>

        <!-- Handles database upgrades after OTAs, then disables itself -->
        <receiver android:name="ContactsUpgradeReceiver">
            <!-- This broadcast is sent after the core system has finished
                 booting, before the home app is launched or BOOT_COMPLETED
                 is sent. -->
            <intent-filter>
                <action android:name="android.intent.action.PRE_BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>

        <receiver android:name="PackageIntentReceiver">
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_ADDED" />
                <data android:scheme="package" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_REPLACED" />
                <data android:scheme="package" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_REMOVED" />
                <data android:scheme="package" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_CHANGED" />
                <data android:scheme="package" />
            </intent-filter>
        </receiver>

        <receiver android:name="LocaleChangeReceiver">
            <intent-filter>
                <action android:name="android.intent.action.LOCALE_CHANGED"/>
            </intent-filter>
        </receiver>

        <service android:name="VoicemailCleanupService"/>

        <activity android:name=".debug.ContactsDumpActivity"
                android:label="@string/debug_dump_title"
                android:theme="@android:style/Theme.Holo.Dialog"
                >
            <intent-filter>
                <action android:name="com.android.providers.contacts.DUMP_DATABASE"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

        <provider android:name=".debug.DumpFileProvider"
            android:authorities="com.android.contacts.dumpfile"
            android:exported="true">
        </provider>

    </application>
</manifest>


 

我們可以看一下第一個provider,裏面就有我們想要的uri還有它已經寫好了的類了,各位有興趣的可以去看一下是如何實現的,

 

其實我們要獲取的東西,都是存放在一個數據庫裏面的,我們不妨把那個數據庫拿出來看一下,拿到那個數據庫也很簡單,只要在Eclipse裏面的ddms界面裏面,在右上邊

 

那個contacts2.db就是我們想要的東西啦

我們可以把它導出來,然後用SQLite Database browser來打開它

獲取手機裏面的聯繫人,我們只要關注三個表就可以啦,一個是raw_contacts   data還有一個mime_type這三個表就行啦

mime_type存放的就是一些類型,是電話,還是短信,還是E-mail這些

data就是存放一些數據的東西

raw_contacts就是存放一些命名什麼的

這三個表的關係就是下面一樣的啦

 

從上面的可以看到,我們可以通過raw_contacts拿到那個id還有display_name然後就去data那裏找到對應的raw_contact_id,這樣就可以獲得對應的數據啦,然後還可以通過mimetype_id在mime_type表裏面找出想要的類型

好啦,原理就是這樣啦,下面我們來看一下代碼怎麼寫

我們先要用一個model類來存放我們的數據

com.xiaobin.security.domain.ContactInfo

package com.xiaobin.security.domain;

public class ContactInfo
{
	private String name;
	private String phone;
	
	public String getName()
	{
		return name;
	}
	public void setName(String name)
	{
		this.name = name;
	}
	public String getPhone()
	{
		return phone;
	}
	public void setPhone(String phone)
	{
		this.phone = phone;
	}
	
}


 

然後呢,我們就可以寫我們獲得手機聯繫人的代碼啦

新建一個類com.xiaobin.security.engine.ContactInfoService

package com.xiaobin.security.engine;

import java.util.ArrayList;
import java.util.List;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;

import com.xiaobin.security.domain.ContactInfo;

public class ContactInfoService
{
	private Context context;
	
	public ContactInfoService(Context context)
	{
		this.context = context;
	}
	
	public List<ContactInfo> getContactInfos()
	{
		List<ContactInfo> infos = new ArrayList<ContactInfo>();
		ContactInfo info;
		
		ContentResolver contentResolver = context.getContentResolver();
		//在源碼的AndroidManifest裏面可以看到這些uri
		Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
		Uri dataUri = Uri.parse("content://com.android.contacts/data");
		Cursor cursor = contentResolver.query(uri, null, null, null, null);
		while(cursor.moveToNext())
		{
			info = new ContactInfo();
			String id = cursor.getString(cursor.getColumnIndex("_id"));
			String name = cursor.getString(cursor.getColumnIndex("display_name"));
			info.setName(name);
			//通過raw_contacts裏面的id拿到data裏面對應的數據
			Cursor dataCursor = contentResolver.query(dataUri, null, "raw_contact_id = ? ", new String[] {id}, null);
			while(dataCursor.moveToNext())
			{
				String type = dataCursor.getString(dataCursor.getColumnIndex("mimetype"));
				//根據類型,只要電話這種類型的數據
				if(type.equals("vnd.android.cursor.item/phone_v2"))
				{
					String number = dataCursor.getString(dataCursor.getColumnIndex("data1"));//拿到數據
					info.setPhone(number);
				}
			}
			dataCursor.close();
			infos.add(info);
			info = null;
		}
		cursor.close();
		return infos;
	}

}


 

因爲我們是點擊按鈕,然後打開一個activity,然後選擇好了之後,再把值返回到原來的activity那裏的,所以我們就要用到startActivityForResult這個方法啦

好,我們來看一下setup_guide3這個嚮導頁面的邏輯是怎樣寫的

com.xiaobin.security.ui.SetupGuide3Activity

package com.xiaobin.security.ui;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.xiaobin.security.R;

public class SetupGuide3Activity extends Activity implements OnClickListener
{
	private Button bt_next;
	private Button bt_pervious;
	private Button bt_select;
	private EditText et_phoneNumber;
	private SharedPreferences sp;
	
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.setup_guide3);
		
		sp = getSharedPreferences("config", Context.MODE_PRIVATE);
		
		bt_next = (Button) findViewById(R.id.bt_guide_next);
		bt_pervious = (Button) findViewById(R.id.bt_guide_pervious);
		bt_select = (Button) findViewById(R.id.bt_guide_select);
		bt_next.setOnClickListener(this);
		bt_pervious.setOnClickListener(this);
		bt_select.setOnClickListener(this);
		
		et_phoneNumber = (EditText) findViewById(R.id.et_guide_phoneNumber);
	}
	
	//重寫這個方法,從acitivty裏面拿到數據
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data)
	{
		super.onActivityResult(requestCode, resultCode, data);
		//resultCode是乃至區分拿到的activity是從那一個activity裏面拿到的
		
		if(data != null)
		{
			String number = data.getStringExtra("number");
			et_phoneNumber.setText(number);
		}
	}

	@Override
	public void onClick(View v)
	{
		switch(v.getId())
		{
			case R.id.bt_guide_select : 
				Intent selectIntent = new Intent(this, SelectContactActivity.class);
				//啓動一個activity來獲取數據,獲取到的數據是在重寫的onActivityResult這個方法裏面拿到的
				startActivityForResult(selectIntent, 1);
				break;
				
			case R.id.bt_guide_next : 
				String number = et_phoneNumber.getText().toString().trim();
				if(number.equals(""))
				{
					Toast.makeText(this, "安全號碼不能爲空", Toast.LENGTH_SHORT).show();
				}
				else
				{
					Editor editor = sp.edit();
					editor.putString("number", number);
					editor.commit();
					
					Intent intent = new Intent(this, SetupGuide4Activity.class);
					finish();
					startActivity(intent);
					//這個是定義activity切換時的動畫效果的
					overridePendingTransition(R.anim.translate_in, R.anim.translate_out);
				}
				break;
			case R.id.bt_guide_pervious : 
				
				Intent i = new Intent(this, SetupGuide2Activity.class);
				finish();
				startActivity(i);
				//這個是定義activity切換時的動畫效果的
				overridePendingTransition(R.anim.alpha_in, R.anim.alpha_out);
				break;
				
			default : 
				break;
		}
	}

}


 

我們還要新建一個類用來做爲選擇的呢

com.xiaobin.security.ui.SelectContactActivity

package com.xiaobin.security.ui;

import java.util.List;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

import com.xiaobin.security.R;
import com.xiaobin.security.domain.ContactInfo;
import com.xiaobin.security.engine.ContactInfoService;

public class SelectContactActivity extends Activity
{
	private ListView lv;
	private List<ContactInfo> infos;
	
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.select_contact);
		
		infos = new ContactInfoService(this).getContactInfos();
		
		lv = (ListView) findViewById(R.id.lv_select_contact);
		lv.setAdapter(new SelectContactAdapter());
		lv.setOnItemClickListener(new OnItemClickListener()
		{
			@Override
			public void onItemClick(AdapterView<?> parent, View view, int position, long id)
			{
				String number = infos.get(position).getPhone();
				Intent intent = new Intent();
				intent.putExtra("number", number);
				//把要返回的數據設置進去,便通過onActivityResult(int, int, Intent)拿到
				setResult(1, intent);
				finish();
			}
		});
	}
	
	//=================================================================================
	
	private class SelectContactAdapter extends BaseAdapter
	{

		@Override
		public int getCount()
		{
			return infos.size();
		}

		@Override
		public Object getItem(int position)
		{
			return infos.get(position);
		}

		@Override
		public long getItemId(int position)
		{
			return position;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent)
		{
			ContactInfo info = infos.get(position);
			View view;
			ContactViews views;
			if(convertView == null)
			{
				views = new ContactViews();
				view = View.inflate(SelectContactActivity.this, R.layout.contact_item, null);
				views.tv_name = (TextView) view.findViewById(R.id.tv_contact_name);
				views.tv_number = (TextView) view.findViewById(R.id.tv_contact_number);
				views.tv_name.setText("聯繫人:" + info.getName());
				views.tv_number.setText("聯繫電話:" + info.getPhone());
				
				view.setTag(views);
			}
			else
			{
				view = convertView;
			}
			return view;
		}
		
	}
	
	private class ContactViews
	{
		TextView tv_name;
		TextView tv_number;
	}

}


 

這個類是非常簡單的,只有一個listView

大家也可以看到,這個類裏面有一個adapter,這個是爲了方便,所以寫在裏面的,而且那個listview我們也用到了上一次的優化方法

如果有什麼不瞭解的,可以回去看一下我們前面的那個Android項目實戰--手機衛士06--GridView的優化與修改Button的顯示樣式

好啦,下面是activity的佈局文件,還有listview的佈局文件

select_contact.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:background="@android:color/white"
    android:orientation="vertical" >
    
    <ListView 
        android:id="@+id/lv_select_contact"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

 

contact_item.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" >
    
    <TextView 
        android:id="@+id/tv_contact_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    
    <TextView 
        android:id="@+id/tv_contact_number"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>


 

好啦,獲取聯繫人的操作,我們也差不多完成的啦,現在還要加上兩個權限

    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>


 

到現在爲止,獲取聯繫人的操作就完成的啦,

因爲之前都是清一色的切換效果,所以我現寫多了兩個切換效果,大家可以看看,也是很簡單的

至於怎麼寫那些效果,那就要看一下我們的前一篇文章啦

translate_in.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="100%p"
    android:toXDelta="0"
    android:duration="400" >
    <!-- 100%p是指從看不到的地方進入到0這個地方 -->

</translate>


translate_out.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="0"
    android:toXDelta="-100%p"
    android:duration="400" >
    <!-- 100%p是指從看不到的地方進入到0這個地方 -->

</translate>


 

好啦,今天要說的基本上已經說完的啦

如果有什麼不明白的,或有什麼指導的,歡迎留言

 

今天源碼下載
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章