Android - 如何在活动运行时将最新短信添加到对话列表?
我正在开发短信聊天应用程序。我想知道当活动打开时如何在列表视图的底部添加最新的短信(发送或接收),就像股票短信应用程序或任何其他信使一样。
我尝试使用 ContentObserver。一旦 SMS 数据库发生一些更改,我尝试使用新数据集重新加载 ListView,但它不起作用。每次看到新的短信(发送或接收)时,我都必须重新启动应用程序,以便可以重新加载列表。我希望这些新消息在我发送或接收后立即显示在聊天窗口中,就像我们通过 gtalk、msn 或任何 SMS 应用程序聊天的方式一样。
这是我的代码:-
public class ThreadData extends ListActivity
{
private static final Uri SMS_URI = Uri.parse("content://sms");
HashMap<Long, BodyType> bodies = new HashMap<Long, BodyType>();
private String name, number;
private ListView listView;
private Activity activity;
ThreadDataAdapter adapter;
Handler handler;
ArrayList<BodyType> items;
private Context context;
private static final String PHONE_NUMBER_SEPARATORS = " ()-./";
static HashMap<String, ContactInfo.ContactDetail> info = new HashMap<String, ContactInfo.ContactDetail>();
public void onCreate(Bundle bundle)
{
super.onCreate(bundle);
setContentView(R.layout.chats);
Bundle extras = getIntent().getExtras();
activity = this;
context = this;
listView = getListView();
if(extras != null)
{
number = extras.getString("address");
ContactInfo.ContactDetail nameInfo = getContactsDetailWithNumber(number);
if(nameInfo != null)
{
name = nameInfo.name;
}
else
{
name = number;
}
}
TextView person = (TextView) findViewById(R.id.chat_person);
person.setText(name);
ImageButton callPerson = (ImageButton) findViewById(R.id.call_person);
callPerson.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
popUpDialerAlert();
}
});
buildMessageList();
items = sortBodies(bodies);
adapter = new ThreadDataAdapter(this, items);
listView.setAdapter(adapter);
listView.setStackFromBottom(true);
getContentResolver().registerContentObserver(SMS_URI, true, new MyContentObserver(handler));
//Intent intent = new Intent(this, RBSMSService.class);
//startService(intent);
}
public void loadListView()
{
items.clear();
items = sortBodies(bodies);
adapter = new ThreadDataAdapter(this, items);
listView.setAdapter(adapter);
listView.setStackFromBottom(true);
}
public void buildMessageList()
{
Cursor cursor = getContentResolver().query(SMS_URI, null, null, null, "date ASC");
startManagingCursor(cursor);
while (cursor.moveToNext())
{
BodyType bodyInfo = new BodyType();
String address = cursor.getString(cursor.getColumnIndex("address"));
bodyInfo.body = cursor.getString(cursor.getColumnIndexOrThrow("body"));
Long date = cursor.getLong(cursor.getColumnIndexOrThrow("date"));
bodyInfo.date = date;
String type = cursor.getString(cursor.getColumnIndexOrThrow("type"));
if(type.equals("1"))
{
bodyInfo.type = "received";
}
else if(type.equals("2"))
{
bodyInfo.type = "sent";
}
else if(type.equals("3"))
{
bodyInfo.type = "draft";
}
String number = filterPhoneNumber(address);
ContactInfo.ContactDetail nameInfo = getContactsDetailWithNumber(number);
String personName = number;
if(nameInfo != null)
{
personName = nameInfo.name;
}
else
{
personName = number;
}
if(personName.equals(name))
{
bodies.put(date, bodyInfo);
}
}
}
public void popUpDialerAlert()
{
AlertDialog.Builder dialerAlert = new AlertDialog.Builder(this);
dialerAlert.setTitle("Confirm");
dialerAlert.setMessage("Call" + " " + name + "?");
dialerAlert.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
Uri uri = Uri.parse("tel:" + number);
Intent intent = new Intent((Intent.ACTION_CALL));
intent.setData(uri);
context.startActivity(intent);
}
});
dialerAlert.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
}
});
dialerAlert.show();
}
public ArrayList<BodyType> sortBodies(HashMap<Long, BodyType> bodies)
{
ArrayList<Long> dates = new ArrayList<Long>(bodies.keySet());
Collections.sort(dates);
ArrayList<BodyType> items = new ArrayList<BodyType>();
for(Long date : dates)
{
for(Long key : bodies.keySet())
{
if(date.equals(key))
{
items.add(bodies.get(key));
}
}
}
return items;
}
public void printBodies(ArrayList<BodyType> items)
{
for(BodyType bodyType : items)
{
log(bodyType.date.toString());
log(bodyType.body);
log(bodyType.type);
}
}
static class BodyType
{
public String type;
public String body;
public Long date;
}
public static ContactInfo.ContactDetail getContactsDetailWithNumber(String number)
{
if(info.containsKey(number))
{
return info.get(number);
}
return null;
}
public static String filterPhoneNumber(String phoneNumber)
{
if (phoneNumber == null)
{
return null;
}
int length = phoneNumber.length();
StringBuilder builder = new StringBuilder(length);
for (int i = 0; i < length; i++)
{
char character = phoneNumber.charAt(i);
if (PHONE_NUMBER_SEPARATORS.indexOf(character) == -1)
{
builder.append(character);
}
}
return builder.toString();
}
public class MyContentObserver extends ContentObserver
{
public MyContentObserver(Handler handler)
{
super(handler);
}
@Override
public void onChange(boolean selfChange)
{
bodies.clear();
buildMessageList();
items = sortBodies(bodies);
runOnUiThread(new Runnable() {
public void run() {
loadListView();
}
});
super.onChange(selfChange);
}
}
public void log(String msg)
{
Log.e("ThreadData", msg);
}
}
请帮忙!
谢谢
I am working on a SMS chat app. I am wondering how to add the latest SMS(sent or receive) at the bottom of the listview when the activity is opened just like stock SMS app or any other messenger.
I tried using ContentObserver. As soon as there is some changes in SMS database, i tried reloading the ListView with the new Dataset but it is not working. Everytime to see a new SMS(sent of receive) i have to restart the app so the list could be reloaded. I want these new message to be displayed in chat window as soon as i sent or receive them just like the way we chat over gtalk, msn or any SMS app.
Here is my code:-
public class ThreadData extends ListActivity
{
private static final Uri SMS_URI = Uri.parse("content://sms");
HashMap<Long, BodyType> bodies = new HashMap<Long, BodyType>();
private String name, number;
private ListView listView;
private Activity activity;
ThreadDataAdapter adapter;
Handler handler;
ArrayList<BodyType> items;
private Context context;
private static final String PHONE_NUMBER_SEPARATORS = " ()-./";
static HashMap<String, ContactInfo.ContactDetail> info = new HashMap<String, ContactInfo.ContactDetail>();
public void onCreate(Bundle bundle)
{
super.onCreate(bundle);
setContentView(R.layout.chats);
Bundle extras = getIntent().getExtras();
activity = this;
context = this;
listView = getListView();
if(extras != null)
{
number = extras.getString("address");
ContactInfo.ContactDetail nameInfo = getContactsDetailWithNumber(number);
if(nameInfo != null)
{
name = nameInfo.name;
}
else
{
name = number;
}
}
TextView person = (TextView) findViewById(R.id.chat_person);
person.setText(name);
ImageButton callPerson = (ImageButton) findViewById(R.id.call_person);
callPerson.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
popUpDialerAlert();
}
});
buildMessageList();
items = sortBodies(bodies);
adapter = new ThreadDataAdapter(this, items);
listView.setAdapter(adapter);
listView.setStackFromBottom(true);
getContentResolver().registerContentObserver(SMS_URI, true, new MyContentObserver(handler));
//Intent intent = new Intent(this, RBSMSService.class);
//startService(intent);
}
public void loadListView()
{
items.clear();
items = sortBodies(bodies);
adapter = new ThreadDataAdapter(this, items);
listView.setAdapter(adapter);
listView.setStackFromBottom(true);
}
public void buildMessageList()
{
Cursor cursor = getContentResolver().query(SMS_URI, null, null, null, "date ASC");
startManagingCursor(cursor);
while (cursor.moveToNext())
{
BodyType bodyInfo = new BodyType();
String address = cursor.getString(cursor.getColumnIndex("address"));
bodyInfo.body = cursor.getString(cursor.getColumnIndexOrThrow("body"));
Long date = cursor.getLong(cursor.getColumnIndexOrThrow("date"));
bodyInfo.date = date;
String type = cursor.getString(cursor.getColumnIndexOrThrow("type"));
if(type.equals("1"))
{
bodyInfo.type = "received";
}
else if(type.equals("2"))
{
bodyInfo.type = "sent";
}
else if(type.equals("3"))
{
bodyInfo.type = "draft";
}
String number = filterPhoneNumber(address);
ContactInfo.ContactDetail nameInfo = getContactsDetailWithNumber(number);
String personName = number;
if(nameInfo != null)
{
personName = nameInfo.name;
}
else
{
personName = number;
}
if(personName.equals(name))
{
bodies.put(date, bodyInfo);
}
}
}
public void popUpDialerAlert()
{
AlertDialog.Builder dialerAlert = new AlertDialog.Builder(this);
dialerAlert.setTitle("Confirm");
dialerAlert.setMessage("Call" + " " + name + "?");
dialerAlert.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
Uri uri = Uri.parse("tel:" + number);
Intent intent = new Intent((Intent.ACTION_CALL));
intent.setData(uri);
context.startActivity(intent);
}
});
dialerAlert.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
}
});
dialerAlert.show();
}
public ArrayList<BodyType> sortBodies(HashMap<Long, BodyType> bodies)
{
ArrayList<Long> dates = new ArrayList<Long>(bodies.keySet());
Collections.sort(dates);
ArrayList<BodyType> items = new ArrayList<BodyType>();
for(Long date : dates)
{
for(Long key : bodies.keySet())
{
if(date.equals(key))
{
items.add(bodies.get(key));
}
}
}
return items;
}
public void printBodies(ArrayList<BodyType> items)
{
for(BodyType bodyType : items)
{
log(bodyType.date.toString());
log(bodyType.body);
log(bodyType.type);
}
}
static class BodyType
{
public String type;
public String body;
public Long date;
}
public static ContactInfo.ContactDetail getContactsDetailWithNumber(String number)
{
if(info.containsKey(number))
{
return info.get(number);
}
return null;
}
public static String filterPhoneNumber(String phoneNumber)
{
if (phoneNumber == null)
{
return null;
}
int length = phoneNumber.length();
StringBuilder builder = new StringBuilder(length);
for (int i = 0; i < length; i++)
{
char character = phoneNumber.charAt(i);
if (PHONE_NUMBER_SEPARATORS.indexOf(character) == -1)
{
builder.append(character);
}
}
return builder.toString();
}
public class MyContentObserver extends ContentObserver
{
public MyContentObserver(Handler handler)
{
super(handler);
}
@Override
public void onChange(boolean selfChange)
{
bodies.clear();
buildMessageList();
items = sortBodies(bodies);
runOnUiThread(new Runnable() {
public void run() {
loadListView();
}
});
super.onChange(selfChange);
}
}
public void log(String msg)
{
Log.e("ThreadData", msg);
}
}
Please Help!
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您需要保留对您的列表(项目)的引用。
当内容提供者调用 OnChange 时,清除相同的列表(不要创建新对象,回收您的列表)并再次添加新邮件。由于此列表与您的适配器绑定,因此当您调用notifyDataChanged 时它将更新您的列表视图。
您必须回收相同的列表。
问候
史蒂芬
PS:请注意,您可以保留旧线程再次询问相同的问题。
You need to keep a reference to your list (items).
When the content provider calls OnChange, clear the very same list (don't create a new object, recycle your list) and add again your new mails. As this list is tied to your adapter, then it will update your listview when you call notifyDataChanged.
You must recycle the same list.
Regards
Stéphane
PS : please note that you could have kept your old thread to ask the same question again.
因此,要在添加新项目时让列表滚动到底部,您应该将其设置为“转录模式"。然而,您必须重新启动应用程序才能显示新内容这一事实告诉我还有其他问题。
编辑:Stephane 是对的,当您收到
onChange
通知时,不要再次调用buildMessageList();
,只需更新适配器中的数据并调用notifyDatasetChanged()
So, to get the list to scroll to the bottom when you add new items, you should set it to be in "transcriptMode". However, the fact that you have to restart your app for new content to show tells me something else is wrong.
Edit: Stephane is right, don't call
buildMessageList();
again when you get theonChange
notification just update the data in the adapter and callnotifyDatasetChanged()