使用listView,继承BaseAdapter,实现聊天界面:,运行图:
layout_list_item.xml单个item条目的布局,即图片,聊天内容,时间的布局:
<?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" >
<TextView
android:id="@+id/tvTime"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_alignParentTop="true"
android:text="TextView" />
<ImageView
android:id="@+id/ivIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="48dp"
android:maxHeight="48dp"
android:adjustViewBounds="true"
android:layout_alignParentLeft="true"
android:layout_below="@+id/tvTime"
android:background="@drawable/ic_launcher" />
<TextView
android:id="@+id/tvMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/ivIcon"
android:textSize="22dp"
android:layout_below="@id/tvTime"
android:text="TextView" />
</RelativeLayout>
main_activity.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/textView1"
android:scrollingCache="false"
>
</ListView>
</RelativeLayout>
MyAdapter:通过循环向控件中添加数据,在封装进Adapter适配器里面,重写四个方法
public class MyAdapter extends BaseAdapter {
private List<HashMap<String, Object>> mDataSet;
private Context mContext;
// 转换器,XML文件转化成控件对象
private LayoutInflater mInflater;
public MyAdapter(Context c) {
mContext = c;
mDataSet = new ArrayList<HashMap<String, Object>>();
HashMap<String, Object> map;
for (int i = 0; i < 30; i++) {
map = new HashMap<String, Object>();
map.put("image", R.drawable.ic_launcher);
map.put("time", "19:32");
map.put("message", "聊天内容" + i);
mDataSet.add(map);
}
// 获得系统转化器
mInflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public List<HashMap<String, Object>> getDataSet(){
return mDataSet;
}
/**
* 用于返回数据集合数量
*/
@Override
public int getCount() {
return mDataSet.size();
}
//position:它要组装数据集合中第几个数据记录
//getItem : 根据一个索引(位置)获得该位置的对象
@Override
public Object getItem(int position) {
return null;
}
//getItemId : 获取条目的id
@Override
public long getItemId(int position) {
return 0;
}
/**
* 用于将循环器中将要显示的项进行数据组装 ListView会将移出显示区域的View项放到循环器中,等待getView来组装新项
* position:它要组装数据集合中第几个数据记录 convertView:循环器中的待用对象(可能为null)
* parent:ListVIew的父控件对象
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 判断convertView是否为空,如果为空,说明ListView刚刚初始化显示
// 如果不为空,说明是循环器中可用的项
if (convertView == null) {
// 将Layout文件中的控件转化成可用的控件对象
convertView = mInflater.inflate(R.layout.layout_list_item, null);
ImageView image = (ImageView) convertView.findViewById(R.id.ivIcon);
TextView time = (TextView) convertView.findViewById(R.id.tvTime);
TextView message = (TextView) convertView
.findViewById(R.id.tvMessage);
convertView.setTag(new Holder(image, time, message));
}
// long start = System.currentTimeMillis();
// System.out.println("Delay:" + (System.currentTimeMillis() - start));
// 重复使用已经存在的项
// 将position位置处的数据组装到该项中,返回
Holder h = (Holder) convertView.getTag();
h.image.setImageResource((Integer) mDataSet.get(position).get("image"));
h.time.setText((String) mDataSet.get(position).get("time"));
h.message.setText((String) mDataSet.get(position).get("message"));
return convertView;
}
private class Holder {
ImageView image;
TextView time;
TextView message;
public Holder(ImageView img, TextView tm, TextView msg) {
image = img;
time = tm;
message = msg;
}
}
}
MainActivity里面给每个listView里面的item(每一条)设置一个监听事件
public class MainActivity extends Activity {
private ListView mListView;
private List<String> mDataSet;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.listView1);
/* // 生成ListView数据
mDataSet = new ArrayList<String>();
for(int i = 0; i < 30; i++){
mDataSet.add("显示数据" + i);
}
// 适配器中封装有要显示的数据
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
mDataSet
);
mListView.setAdapter(adapter);*/
final MyAdapter adapter = new MyAdapter(this);
mListView.setAdapter(adapter);
mListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
Toast.makeText(MainActivity.this, "您点击了:" + adapter.getDataSet().get(arg2).get("message"), Toast.LENGTH_SHORT).show();
}
});
mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
Toast.makeText(MainActivity.this, "您长击了:" + adapter.getDataSet().get(arg2).get("message"), Toast.LENGTH_SHORT).show();
return true;
}
});
}
}
接下来:如何创建通知:Notification通知图解
Notification,是一种具有全局效果的通知,可以在系统的通知栏中显示。当 APP 向系统发出通知时,它将先以图标的形式显示在通知栏中。用户可以下拉通知栏查看通知的详细信息。
发送通知的函数:
Notification在android 8.0以上设置时,需要设置渠道信息才能够正常显示通知,新增如下代码
NotificationChannel mChannel = new NotificationChannel(id, name, NotificationManager.IMPORTANCE_LOW);
//Notification在android 8.0以上设置时,需要设置渠道信息才能够正常显示通知
private void notifyMessage(){
String id = "my_channel_01";
String name="我是渠道名字";
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notification = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel mChannel = new NotificationChannel(id, name, NotificationManager.IMPORTANCE_LOW);
Toast.makeText(this, mChannel.toString(), Toast.LENGTH_SHORT).show();
Log.i(TAG, mChannel.toString());
notificationManager.createNotificationChannel(mChannel);
notification = new Notification.Builder(this)
.setChannelId(id)
.setContentTitle("5 new messages")
.setContentText("hahaha")
.setSmallIcon(R.mipmap.ic_launcher).build();
} else {
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setContentTitle("5 new messages")
.setContentText("hahaha")
.setSmallIcon(R.mipmap.ic_launcher)
.setOngoing(true);
notification = notificationBuilder.build();
}
notificationManager.notify(111123, notification);
}
全部代码:
mainActivity:
package com.lmj.bluetoothchat;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.view.View;
public class MainActivity extends Activity {
/**
* 表示xx通知ID
*/
public static final int NOTIFY_ID = 100;
private Notification builder;
private PendingIntent contentIntent = null;
private NotificationManager nm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@RequiresApi(api = Build.VERSION_CODES.O)
private void notifyMessage(){
String id = "my_channel_01";
String name="我是渠道名字";
// 发送通知需要用到NotificationManager对象
nm = (NotificationManager)this.getSystemService(NOTIFICATION_SERVICE);
// 消息对象
Intent notificationIntent = new Intent(this, NotifyActivity.class);
// PendingIntent.getActivity(Context context, int requestCode, Intent intent, int flags)
// 用来获得一个挂起的PendingIntent,让该Intent去启动新的Activity来处理通知
//通过PendingIntent,来实现点击通知栏,跳转到Activity页面的功能,它类似于intent跳转页面。
contentIntent = PendingIntent.getActivity(MainActivity.this, 0, notificationIntent, 0);
// 定制我们要在状态栏显示的通知样式
//anv= new Notification.Builder(this)
builder = new Notification.Builder(this)
.setChannelId(id)
.setContentIntent(contentIntent)
.setSmallIcon(R.drawable.ic_launcher)//设置状态栏里面的图标(小图标) .setLargeIcon(BitmapFactory.decodeResource(res, R.drawable.i5))//下拉下拉列表里面的图标(大图标) .setTicker("this is bitch!") //设置状态栏的显示的信息
.setWhen(System.currentTimeMillis())//设置时间发生时间
.setAutoCancel(true)//设置可以清除
.setContentTitle("我是标题")//设置下拉列表里的标题
.setContentText("我是内容").build();//设置上下文内容
Notification在android 8.0以上设置时,需要设置渠道信息才能够正常显示通知,即需要加上NotificationChannel对象信息
//点击通知要跳转到 目标activity
/* Intent intent = new Intent(this, SecondeActivity.class);
PendingIntent pendingIntent =
PendingIntent.getActivity(this,1,intent,PendingIntent.FLAG_CANCEL_CURRENT);
//设置通知默认效果
builder.contentIntent = pendingIntent;
builder.flags = Notification.FLAG_SHOW_LIGHTS;*/
// startForegroundService(1, builder);
NotificationChannel mChannel = new NotificationChannel(id, name, NotificationManager.IMPORTANCE_LOW);
nm.createNotificationChannel(mChannel);
// 获得刚才创建的通知对象
// Notification notification = builder.getNotification();//获取一个Notification
// notification.defaults = Notification.DEFAULT_SOUND;//设置为默认的声音
// 通过NotificationManger来发送通知消息
// 参数1通知的ID,参数2发送哪个通知
// nm.notify(NOTIFY_ID, notification);
nm.notify(NOTIFY_ID,builder);
}
@RequiresApi(api = Build.VERSION_CODES.O)
public void sendNotifyBtn(View v){
notifyMessage();
}
public void cancelNotifyBtn(View v){
NotificationManager manger = (NotificationManager)this.getSystemService(NOTIFICATION_SERVICE);
manger.cancel(NOTIFY_ID);
}
public void turn1(View view){
Intent intent=new Intent(this,NotifyActivity.class);
startActivity(intent);
}
}
NotifyActivity代码:点击通知栏,弹出(原生android)对话框
package com.lmj.bluetoothchat;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.NotificationManager;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
public class NotifyActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
showDialog();
}
private void showDialog() {
// 创建并显示一个对话框
AlertDialog.Builder dlg = new AlertDialog.Builder(this);
// 自定义Dialog需要自己创建或转换一个View,将其通过下面的方法显示。
//dlg.setView(view);
// 设置对话框显示样式
dlg.setTitle("我是对话框标题");
dlg.setMessage("我是对话框内容");
dlg.setIcon(R.drawable.ic_launcher);
dlg.setPositiveButton("是", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
System.out.println("PositiveButton被点击");
NotificationManager manger = (NotificationManager)NotifyActivity.this.getSystemService(NOTIFICATION_SERVICE);
manger.cancel(MainActivity.NOTIFY_ID);
}
});
dlg.setNegativeButton("否", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
System.out.println("NegativeButton被点击");
}
});
dlg.setNeutralButton("取消", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
System.out.println("NeutralButton被点击");
}
});
// 不允许用户取消对话框
dlg.setCancelable(false);
dlg.create();
// 对话框显示必须要调用 show();
dlg.show();
}
}
secondeActivity:用于点击跳转第二个页面的测试类:
public class SecondeActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_seconde);
}
}
activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/button1"
android:layout_centerHorizontal="true"
android:layout_marginTop="44dp"
android:onClick="cancelNotifyBtn"
android:text="取消Notification" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/button2"
android:layout_alignParentTop="true"
android:layout_marginTop="134dp"
android:onClick="sendNotifyBtn"
android:text="发送Notification" />
</RelativeLayout>
secondeActivity.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我是第二个页面" />
</android.support.constraint.ConstraintLayout>
运行如下:
最后记得在mainfest里添加相应配置:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.lmj.bluetoothchat">
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
tools:ignore="ProtectedPermissions" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".NotifyActivity"/>
<activity android:name=".SecondeActivity"/>
</application>
</manifest>