天天看點

微信核心功能全解析

最近做了一套及時通訊軟體,其中很多功能和微信是相仿的,下面詳細介紹一下具體實作。

做及時通訊肯定要用xmpp協定,微信和一些及時通訊軟體也是用的這套協定,隻是縱向開發深度不同。

1.複寫語音按鈕

@SuppressLint("NewApi")

public class RecordButton extends Button  {

public RecordButton(Context context) {

super(context);

init();

}

public RecordButton(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

public RecordButton(Context context, AttributeSet attrs) {

super(context, attrs);

public void setSavePath(String path) {

mFileName = path;

public void setOnFinishedRecordListener(OnFinishedRecordListener listener) {

finishedListener = listener;

private String mFileName = null;

private OnFinishedRecordListener finishedListener;

private static final int MIN_INTERVAL_TIME = 2000;// 2s

private long startTime;

/**

* 取消語音發送

*/

private Dialog recordIndicator;

private static int[] res = { R.drawable.mic_2, R.drawable.mic_3,

R.drawable.mic_4, R.drawable.mic_5 };

private static ImageView view;

private MediaRecorder recorder;

private ObtainDecibelThread thread;

private Handler volumeHandler;

public final static int   MAX_TIME =60;//一分鐘

private void init() {

volumeHandler = new ShowVolumeHandler();

@Override

public boolean onTouchEvent(MotionEvent event) {

if (mFileName == null)

return false;

int action = event.getAction();

switch (action) {

case MotionEvent.ACTION_DOWN:

setText("松開發送");

initDialogAndStartRecord();

break;

case MotionEvent.ACTION_UP:

this.setText("按住錄音");

finishRecord();

case MotionEvent.ACTION_CANCEL:// 當手指移動到view外面,會cancel

cancelRecord();

Toast.makeText(getContext(), "cancel", 1).show();

return true;

private void initDialogAndStartRecord() {

startTime = System.currentTimeMillis();

recordIndicator = new Dialog(getContext(),

R.style.like_toast_dialog_style);

view = new ImageView(getContext());

view.setImageResource(R.drawable.mic_2);

recordIndicator.setContentView(view, new LayoutParams(

ViewGroup.LayoutParams.WRAP_CONTENT,

ViewGroup.LayoutParams.WRAP_CONTENT));

recordIndicator.setOnDismissListener(onDismiss);

LayoutParams lp = recordIndicator.getWindow().getAttributes();

lp.gravity = Gravity.CENTER;

startRecording();

recordIndicator.show();

private void finishRecord() {

stopRecording();

recordIndicator.dismiss();

long intervalTime = System.currentTimeMillis() - startTime;

if (intervalTime < MIN_INTERVAL_TIME) {

Toast.makeText(getContext(), "時間太短!", Toast.LENGTH_SHORT).show();

File file = new File(mFileName);

file.delete();

return;

if (finishedListener != null)

finishedListener.onFinishedRecord(mFileName,(int) (intervalTime/1000));

private void cancelRecord() {

Toast.makeText(getContext(), "取消錄音!", Toast.LENGTH_SHORT).show();

private void startRecording() {

recorder = new MediaRecorder();

recorder.setAudioSource(MediaRecorder.AudioSource.MIC);

recorder.setAudioChannels(1);

recorder.setAudioEncodingBitRate(4000);

recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);

recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

//recorder.setVideoFrameRate(4000);

recorder.setOutputFile(mFileName);

try {

recorder.prepare();

} catch (IOException e) {

e.printStackTrace();

recorder.start();

thread = new ObtainDecibelThread();

thread.start();

private void stopRecording() {

if (thread != null) {

thread.exit();

thread = null;

if (recorder != null) {

recorder.stop();

recorder.release();

recorder = null;

private class ObtainDecibelThread extends Thread {

private volatile boolean running = true;

public void exit() {

running = false;

public void run() {

while (running) {

Thread.sleep(200);

} catch (InterruptedException e) {

if (recorder == null || !running) {

int x = recorder.getMaxAmplitude();

if (x != 0) {

int f = (int) (10 * Math.log(x) / Math.log(10));

if (f < 26)

volumeHandler.sendEmptyMessage(0);

else if (f < 32)

volumeHandler.sendEmptyMessage(1);

else if (f < 38)

volumeHandler.sendEmptyMessage(2);

else

volumeHandler.sendEmptyMessage(3);

private OnDismissListener onDismiss = new OnDismissListener() {

public void onDismiss(DialogInterface dialog) {

};

static class ShowVolumeHandler extends Handler {

public void handleMessage(Message msg) {

view.setImageResource(res[msg.what]);

public interface OnFinishedRecordListener {

public void onFinishedRecord(String audioPath,int time);

//private  boolean 

2.文字,語音,檔案發送接收

public class ChatActivity extends Activity {

private String userChat = "";// 目前聊天 userChat

private String userChatSendFile = "";// 給誰發檔案

private ChatListAdapter adapter;

private List<Msg> listMsg = new LinkedList<Msg>();

private String pUSERID;// 自己的user

private String pFRIENDID;// 視窗的 名稱

private EditText msgText;

private TextView chat_name;

private NotificationManager mNotificationManager;

private ChatManager cm;

private RecordButton mRecordButton;

// 發送檔案

private OutgoingFileTransfer sendTransfer;

public static String FILE_ROOT_PATH = Environment

.getExternalStorageDirectory().getPath() + "/chat/file";

public static String RECORD_ROOT_PATH = Environment

.getExternalStorageDirectory().getPath() + "/chat/record";

Chat newchat;

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

requestWindowFeature(Window.FEATURE_NO_TITLE);

setContentView(R.layout.chat_client);

mRecordButton = (RecordButton) findViewById(R.id.record_button);

String path = RECORD_ROOT_PATH;

File file = new File(path);

file.mkdirs();

path += "/" + System.currentTimeMillis() + ".amr";

mRecordButton.setSavePath(path);

mRecordButton

.setOnFinishedRecordListener(new OnFinishedRecordListener() {

public void onFinishedRecord(String audioPath, int time) {

Log.i("RECORD!!!", "finished!!!!!!!!!! save to "

+ audioPath);

if (audioPath != null) {

// 自己顯示消息

Msg myChatMsg = new Msg(pUSERID, time + "”語音消息",

TimeRender.getDate(), Msg.FROM_TYPE[1],

Msg.TYPE[0], Msg.STATUS[3], time + "",

audioPath);

listMsg.add(myChatMsg);

String[] pathStrings = audioPath.split("/"); // 檔案名

//發送 對方的消息

String fileName = null ;

if (pathStrings!=null && pathStrings.length>0) {

fileName = pathStrings[pathStrings.length-1];

Msg sendChatMsg = new Msg(pUSERID, time + "”語音消息",

TimeRender.getDate(), Msg.FROM_TYPE[0],

fileName);

// 重新整理擴充卡

adapter.notifyDataSetChanged();

// 發送消息

newchat.sendMessage(Msg.toJson(sendChatMsg));

sendFile(audioPath, myChatMsg);//

} catch (Exception e) {

} else {

Toast.makeText(ChatActivity.this, "發送失敗",

Toast.LENGTH_SHORT).show();

});

mNotificationManager = (NotificationManager) this

.getSystemService(Service.NOTIFICATION_SERVICE);

// 擷取Intent傳過來的使用者名

this.pUSERID = getIntent().getStringExtra("USERID");

this.userChat = getIntent().getStringExtra("user");/*

userChatSendFile = userChat + "/" + FriendListActivity.MY_RESOUCE_NAME;

this.pFRIENDID = getIntent().getStringExtra("FRIENDID");

chat_name = (TextView) findViewById(R.id.chat_name);

chat_name.setText(pFRIENDID);

ListView listview = (ListView) findViewById(R.id.formclient_listview);

listview.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);

this.adapter = new ChatListAdapter(this, listMsg);

listview.setAdapter(adapter);

// 擷取文本資訊

this.msgText = (EditText) findViewById(R.id.formclient_text);

// 消息監聽

cm = XmppConnection.getConnection().getChatManager();

// 傳回按鈕

Button mBtnBack = (Button) findViewById(R.id.chat_back);

mBtnBack.setOnClickListener(new OnClickListener() {

public void onClick(View arg0) {

finish();

receivedMsg();// 接收消息

sendMsg();// 發送消息

receivedFile();// 接收檔案

* 接收消息

public void receivedMsg() {

cm.addChatListener(new ChatManagerListener() {

public void chatCreated(Chat chat, boolean able) {

chat.addMessageListener(new MessageListener() {

public void processMessage(Chat chat2, Message message) {

// 收到來自pc伺服器的消息(擷取自己好友發來的資訊)

if (message.getFrom().contains(userChat)) {

// Msg.analyseMsgBody(message.getBody(),userChat);

// 擷取使用者、消息、時間、IN

// 在handler裡取出來顯示消息

android.os.Message msg = handler.obtainMessage();

System.out.println("伺服器發來的消息是 chat:"

+ message.getBody());

msg.what = 1;

msg.obj = message.getBody();

msg.sendToTarget();

* 發送消息

* @author Administrator

public void sendMsg() {

Button btsend = (Button) findViewById(R.id.formclient_btsend);

// 發送消息給pc伺服器的好友(擷取自己的伺服器,和好友)

newchat = cm.createChat(userChat, null);

btsend.setOnClickListener(new OnClickListener() {

public void onClick(View v) {

// 擷取text文本

final String msg = msgText.getText().toString();

if (msg.length() > 0) {

Msg chatMsg = new Msg(pUSERID, msg, TimeRender.getDate(),

Msg.FROM_TYPE[1]);

  listMsg.add(chatMsg);

  //發送對方

  Msg sendChatMsg = new Msg(pUSERID, msg, TimeRender.getDate(),

Msg.FROM_TYPE[0]); 

Toast.makeText(ChatActivity.this, "發送資訊不能為空",

// 清空text

msgText.setText("");

* 接收檔案

public void receivedFile() {

// Create the file transfer manager

final FileTransferManager manager = new FileTransferManager(

XmppConnection.getConnection());

// Create the listener

manager.addFileTransferListener(new FileTransferListener() {

public void fileTransferRequest(FileTransferRequest request) {

// Check to see if the request should be accepted

Log.d("receivedFile ", " receive file");

if (shouldAccept(request)) {

// Accept it

IncomingFileTransfer transfer = request.accept();

System.out.println(request.getFileName());

File file = new File(RECORD_ROOT_PATH

+ request.getFileName());

transfer.recieveFile(file);

Msg msgInfo = queryMsgForListMsg(file.getName());

msgInfo.setFilePath(file.getPath());//更新 filepath

new MyFileStatusThread(transfer, msgInfo).start();

} catch (XMPPException e) {

// Reject it

request.reject();

String[] args = new String[] { userChat,

request.getFileName(), TimeRender.getDate(), "IN",

Msg.TYPE[0], Msg.STATUS[1] };

Msg msgInfo = new Msg(args[0], "redio", args[2], args[3],

Msg.TYPE[0], Msg.STATUS[1]);

msg.what = 5;

msg.obj = msgInfo;

handler.sendMessage(msg);

* 發送檔案

* @param path

public void sendFile(String path, Msg msg) {

FileTransferManager sendFilemanager = new FileTransferManager(

// Create the outgoing file transfer

sendTransfer = sendFilemanager

.createOutgoingFileTransfer(userChatSendFile);

// Send the file

sendTransfer.sendFile(new java.io.File(path), "send file");

new MyFileStatusThread(sendTransfer, msg).start();

* 監聽

class MyFileStatusThread extends Thread {

private FileTransfer transfer;

private Msg msg;

public MyFileStatusThread(FileTransfer tf, Msg msg) {

transfer = tf;

this.msg = msg;

System.out.println(transfer.getStatus());

System.out.println(transfer.getProgress());

android.os.Message message = new android.os.Message();// handle

message.what = 3;

while (!transfer.isDone()) {

Thread.sleep(1000);

// TODO Auto-generated catch block

if (transfer.getStatus().equals(Status.error)) {

msg.setReceive(Msg.STATUS[2]);

} else if (transfer.getStatus().equals(Status.refused)) {

msg.setReceive(Msg.STATUS[1]);

msg.setReceive(Msg.STATUS[0]);// 成功

handler.sendMessage(message);

/*

* System.out.println(transfer.getStatus());

* System.out.println(transfer.getProgress());

private Handler handler = new Handler() {

public void handleMessage(android.os.Message msg) {

switch (msg.what) {

case 1:

Msg chatMsg = Msg.analyseMsgBody(msg.obj.toString());

if (chatMsg != null) {

listMsg.add(chatMsg);// 添加到聊天消息

case 2: // 發送檔案

case 3: // 更新檔案發送狀态

case 5: // 接收檔案

Msg msg2 = (Msg) msg.obj;

System.out.println(msg2.getFrom());

listMsg.add(msg2);

default:

public void onBackPressed() {

super.onBackPressed();

// XmppConnection.closeConnection();

System.exit(0);

protected void setNotiType(int iconId, String s) {

Intent intent = new Intent();

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

PendingIntent appIntent = PendingIntent.getActivity(this, 0, intent, 0);

Notification myNoti = new Notification();

myNoti.icon = iconId;

myNoti.tickerText = s;

myNoti.defaults = Notification.DEFAULT_SOUND;

myNoti.flags |= Notification.FLAG_AUTO_CANCEL;

myNoti.setLatestEventInfo(this, "QQ消息", s, appIntent);

mNotificationManager.notify(0, myNoti);

* 是否接收

* @param request

* @return

private boolean shouldAccept(FileTransferRequest request) {

final boolean isAccept[] = new boolean[1];

protected void dialog() {

* init file

static {

File root = new File(FILE_ROOT_PATH);

root.mkdirs();// 沒有根目錄建立根目錄

root = new File(RECORD_ROOT_PATH);

root.mkdirs();

* 從list 中取出 分揀名稱相同的 Msg

private Msg queryMsgForListMsg(String filePath){

Msg msg = null;

for (int i = listMsg.size()-1; i>=0; i--) {

msg = listMsg.get(i);

if (filePath!=null && filePath.contains(msg.getFilePath()) ) {// 對方傳過來的隻是檔案的名稱

return msg;

如需整個項目的留下郵箱位址。

轉載注明出處。