1. 程式人生 > >android藍芽聊天開發(2)圖文混排+Notification訊息通知

android藍芽聊天開發(2)圖文混排+Notification訊息通知

使用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通知圖解

Android 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>