android藍芽聊天開發(2)圖文混排+Notification訊息通知
阿新 • • 發佈:2019-01-09
使用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>