源码下载 点击打开链接
首先看第一个会话列表界面
activity_main.xml 里面只有一个ListView控件,用来为ListView填充会话列表内容
package com.example.mysmsthreads;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract.PhoneLookup;
import android.app.Activity;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.support.v4.widget.CursorAdapter;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
/**
* AsyncQueryHandler 异步数据库查询 CursorAdapter 就是数据库的特有的适配器 获取短信的url
*
* @author wyf
*
*/
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
ListView mListView;
private CursorAdapter mAdapter;
private MyAsyncQueryHandler asyncQueryHandler;
private String[] projection = new String[] { "sms.thread_id AS _id",
"sms.body AS snippet", "groups.msg_count AS msg_count",
"sms.address AS address", "sms.date AS date" };
private String[] contentProjection = new String[] { PhoneLookup._ID,
PhoneLookup.DISPLAY_NAME };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.mListView);
mAdapter = new MyAdatper(this, null);
// 获取数据库数据
mListView.setAdapter(mAdapter);
asyncQueryHandler = new MyAsyncQueryHandler(getContentResolver());
asyncQueryHandler.startQuery(0, null,
Uri.parse("content://sms/conversations/"), projection, null,
null, " date desc");
}
class MyAsyncQueryHandler extends AsyncQueryHandler {
public MyAsyncQueryHandler(ContentResolver cr) {
super(cr);
// TODO Auto-generated constructor stub
}
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
super.onQueryComplete(token, cookie, cursor);
Log.i(TAG, "onQueryComplete" + (cursor == null));
mAdapter.changeCursor(cursor);
}
}
class MyAdatper extends CursorAdapter {
private ViewHolder mHolder;
public MyAdatper(Context context, Cursor c) {
super(context, c);
// TODO Auto-generated constructor stub
}
/**
*
"sms.thread_id AS _id", "sms.body AS snippet",
* "groups.msg_count AS msg_count", "sms.address AS address",
* "sms.date AS date"
*
* private String[] projection = new String[] { "_id", "address", "person",
"body", "type", "date" };
*/
@Override
public void bindView(View view, Context arg1, Cursor cursor) {
if (view != null) {
mHolder = (ViewHolder) view.getTag();
TextView nameTv = mHolder.name;
TextView contentTv = mHolder.content;
final String thread_id = cursor.getString(0);
String content = cursor.getString(1);
int count = cursor.getInt(2);
final String address = cursor.getString(3);
long date = cursor.getLong(4);
// 短信内容
if (content != null && content.length() > 10) {
contentTv.setText(content.substring(0, 10));
} else {
contentTv.setText(content);
}
// 次数--时间--java基础知识,获取时间的
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(date);
SimpleDateFormat format = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
String formatTime = format.format(calendar.getTime());
/**
* 定义成局部变量,不要定义成成员变量
*/
String phoneName = null;
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(address));
Cursor concatCursor = getContentResolver().query(uri,
contentProjection, null, null, null);
if (concatCursor.moveToFirst()) {
// 查询到了联系人
phoneName = concatCursor.getString(1);
}
concatCursor.close();
if (phoneName != null) {
nameTv.setText(phoneName + "(" + count + ")" + formatTime);
Log.i(TAG, "phoneName:" + phoneName);
} else {
nameTv.setText(address + "(" + count + ")" + formatTime);
Log.i(TAG, "address:" + address);
}
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, ThreadDetailActivity.class);
intent.putExtra("thread_id",thread_id);
intent.putExtra("phone", address);
startActivity(intent);
}
});
}
}
@Override
public View newView(Context arg0, Cursor arg1, ViewGroup arg2) {
View view = null;
if (view == null) {
mHolder = new ViewHolder();
view = View.inflate(getApplicationContext(), R.layout.item,
null);
}
mHolder.name = (TextView) view.findViewById(R.id.name);
mHolder.content = (TextView) view.findViewById(R.id.content);
view.setTag(mHolder);
return view;
}
}
class ViewHolder {
TextView name;
TextView content;
}
}
然后看第二个页面就是短信详情页面
package com.example.mysmsthreads;
import java.util.ArrayList;
import android.R.array;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Contacts.Intents.UI;
import android.provider.ContactsContract.PhoneLookup;
import android.telephony.gsm.SmsManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
/**
* 同志们回去总结下
* 发送短信的2种方法
* 发送广播、对方受到广播
* 监听数据库变化的广播,以及内容观察着
* 推荐 http://www.itnose.net/detail/6132802.html
* @author wyf
*
*/
public class ThreadDetailActivity extends Activity implements OnClickListener {
private static final String TAG = "ThreadDetailActivity";
ListView mListView;
private String thread_id;
private String phone;
private MyThreadDetailAdapter mThreadDetailAdapter;
private ArrayList mDatas;
private Uri uri = Uri.parse("content://sms/");
private String[] projection = new String[]{ "_id", "address", "person",
"body", "type", "date" };
private String[] contactProjection = new String[]{PhoneLookup._ID,PhoneLookup.DISPLAY_NAME};
EditText sms_content;
Button send_sms;
MySendBr sendBr = new MySendBr();
MyDeliverBr deliverBr = new MyDeliverBr();
private mySmsContentObserver observer = new mySmsContentObserver(new Handler());
class mySmsContentObserver extends ContentObserver{
public mySmsContentObserver(Handler handler) {
super(handler);
// TODO Auto-generated constructor stub
}
@Override
public void onChange(boolean selfChange) {
// TODO Auto-generated method stub
super.onChange(selfChange);
init();
}
}
class MySendBr extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
if (getResultCode() == Activity.RESULT_OK) {
Log.e(TAG, "mysend_sms");
Toast.makeText(context, "send ok", 0).show();
//刷新页面而已 TODO
init();
}
/**
* 加上这个判断会打印不出来?? 大家回去查查吧
*/
if (intent!=null && intent.equals("SENT_SMS_ACTION")) {
}
}
}
class MyDeliverBr extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null && intent.getAction().equals("DELIVERED_SMS_ACTION")) {
Toast.makeText(context, "deliverd ok", 0).show();
Log.e(TAG, "myDeliverd");
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.thread_detail);
//动态注册2个广播--发送成功,对方接收成功
registerReceiver(sendBr, new IntentFilter("SENT_SMS_ACTION"));
registerReceiver(deliverBr, new IntentFilter("DELIVERED_SMS_ACTION"));
//受到系统的短信 注册短信数据库变化通知的。。
getContentResolver().registerContentObserver(uri, true, observer);
init();
}
private void init() {
Intent intent = getIntent();
if (intent!=null) {
thread_id = intent.getStringExtra("thread_id");
phone = intent.getStringExtra("phone");
Log.i(TAG, "thread_id"+thread_id+",phone::"+phone);
}
sms_content = (EditText) findViewById(R.id.sms_content);
send_sms = (Button) findViewById(R.id.send_sms);
send_sms.setOnClickListener(this);
mListView = (ListView) findViewById(R.id.mThreadListView);
//data--数据库中获取!!!!
Cursor threadDetailCursor = getContentResolver().query(uri, projection, "thread_id=?",new String[]{thread_id} , "date desc");
praseThreadDetailCursor(threadDetailCursor);
//适配器
mThreadDetailAdapter = new MyThreadDetailAdapter(this,mDatas);
//设置适配器
mListView.setAdapter(mThreadDetailAdapter);
}
private void praseThreadDetailCursor(Cursor threadDetailCursor) {
mDatas = new ArrayList();
if (threadDetailCursor!=null && threadDetailCursor.getCount()>0) {
while (threadDetailCursor.moveToNext()) {
String address = threadDetailCursor.getString(threadDetailCursor.getColumnIndex("address"));
String body = threadDetailCursor.getString(threadDetailCursor.getColumnIndex("body"));
String type = threadDetailCursor.getString(threadDetailCursor.getColumnIndex("type"));
String date = threadDetailCursor.getString(threadDetailCursor.getColumnIndex("date"));
//type為1是对方的item,为2是自己的itme
//通过电话获取联系人的姓名
String contactName = null;
Uri contactNameUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(address));
Cursor contactNameCursor = getContentResolver().query(contactNameUri, contactProjection, null, null, null);
if (contactNameCursor!=null&& contactNameCursor.moveToFirst()) {
contactName = contactNameCursor.getString(1);
}
Log.i(TAG, "address"+address+",body"+body+",type"+type+",date"+date+",contactName"+contactName);
if (type.equals("1")) {
//对方
ThreadDetailBean heiBean = null;
if (contactName!=null) {
heiBean = new ThreadDetailBean(contactName, date, body, R.layout.hei_item);
}else {
heiBean = new ThreadDetailBean(address, date, body, R.layout.hei_item);
}
mDatas.add(heiBean);
}else {
//自己
ThreadDetailBean mBean = new ThreadDetailBean(null, date, body, R.layout.me_item);
mDatas.add(mBean);
}
}
Log.i(TAG, "mDatas.size()>>>>"+mDatas.size());
}
}
@SuppressWarnings("deprecation")
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.send_sms:
String smsContent = sms_content.getText().toString().trim();
if (smsContent.equals("")) {
return ;
}
/**
* 发送系统短信需要一个类-smsManager
* 1、短信发送成功对方接受到的话,自己会受到广播
* 2、发送成功也将会受到广播
* 区别:deliveryIntent 对方受到短信然后对方给移动。。回馈,然后移动。。在回馈给自己
* sentIntent 说明自己发送给移动。。的通讯商了
*/
SmsManager manager = SmsManager.getDefault();
Intent mySendIntent = new Intent("SENT_SMS_ACTION");
Intent myDeliverIntent = new Intent("DELIVERED_SMS_ACTION");
PendingIntent sentIntent = PendingIntent.getBroadcast(ThreadDetailActivity.this, 0, mySendIntent, 0);
PendingIntent deliveryIntent = PendingIntent.getBroadcast(ThreadDetailActivity.this, 0, myDeliverIntent, 0);
if (smsContent.length()>70) {
ArrayList divideMessage = manager.divideMessage(smsContent);
for (int i = 0; i < divideMessage.size(); i++) {
manager.sendTextMessage(phone, null, divideMessage.get(i), sentIntent, deliveryIntent);
}
}else {
manager.sendTextMessage(phone, null, smsContent, sentIntent, deliveryIntent);
}
ContentValues values = new ContentValues();
values.put("address", phone); // 发送地址
values.put("body", smsContent); // 消息内容
values.put("date", System.currentTimeMillis()); // 创建时间
values.put("read", 0); // 0:未读; 1:已读
values.put("type", 2); // 1:接收; 2:发送
getContentResolver().insert(Uri.parse("content://sms/sent"), values); // 插入数据
break;
default:
break;
}
}
}
package com.example.mysmsthreads;
import java.util.ArrayList;
import android.content.Context;
import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListAdapter;
import android.widget.TextView;
public class MyThreadDetailAdapter extends BaseAdapter{
private Context mContext;
private ArrayList mDatas;
public MyThreadDetailAdapter(Context mContext,
ArrayList mDatas) {
this.mContext = mContext;
this.mDatas = mDatas;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mDatas.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return mDatas.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public int getItemViewType(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ThreadDetailBean threadDetailBean = mDatas.get(position);
int layoutId = threadDetailBean.getLayoutId();
if (layoutId==R.layout.hei_item) {
//type 1 对方
convertView = View.inflate(mContext, R.layout.hei_item, null);
}else if (layoutId==R.layout.me_item) {
//type 2 自己
convertView = View.inflate(mContext, R.layout.me_item, null);
}
TextView name = (TextView) convertView.findViewById(R.id.name);
TextView content = (TextView) convertView.findViewById(R.id.content);
name.setText(threadDetailBean.getPhone()+":"+threadDetailBean.getDate());
content.setText(threadDetailBean.getContent());
return convertView;
}
/**
* 这里如果填写2的话 ,滑动屏幕就会崩溃??为什么呢??? 我也不知道,
* 查查资料??
*/
@Override
public int getViewTypeCount() {
// TODO Auto-generated method stub
return mDatas.size();
}
}
package com.example.mysmsthreads;
public class ThreadDetailBean {
private String phone;
private String date;
private String content;
private int layoutId;
public ThreadDetailBean() {
super();
// TODO Auto-generated constructor stub
}
public ThreadDetailBean(String phone, String date, String content,
int layoutId) {
super();
this.phone = phone;
this.date = date;
this.content = content;
this.layoutId = layoutId;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getLayoutId() {
return layoutId;
}
public void setLayoutId(int layoutId) {
this.layoutId = layoutId;
}
}