Android开发--IM聊天项目(四)--IPC实战

花了两天重写学习了一下IPC、binder等相关知识,于是决定把这个聊天项目也重构一下,让聊天的service功能单独在一个进程,一个是为了更加稳定,对内存的控制也能更加合理,使应用常驻后台,防止主进程被杀守护进程,守护进程和主进程之间相互监视,有一方被杀就重新启动它。 Android后台进程里有很多应用是多个进程的,因为它们要常驻后台,特别是即时通讯或者社交应用,不过现在多进程已经被用烂了。 典型用法是在启动一个不可见的轻量级私有进程,在后台收发消息,或者做一些耗时的事情,或者开机启动这个进程,然后做监听等。

下面放代码

// IChatManager.aidl
package com.sp.chattingroom;
// Declare any non-default types here with import statements
import com.sp.chattingroom.Model.Msg;
import com.sp.chattingroom.I_NewMessageArrived;
import com.sp.chattingroom.I_GetLoginResult;
interface IChatManager {
    void registerNewMsgListener(I_NewMessageArrived listener);
    void registerLoginResultListener(I_GetLoginResult listener);
    void Login(in String name,I_GetLoginResult listener);
    void SendMsg(in Msg msg);
}
// I_NewMessageArrived.aidl
package com.sp.chattingroom;

// Declare any non-default types here with import statements
import com.sp.chattingroom.Model.Msg;
interface I_NewMessageArrived {
    void newMessageArrive(in Msg msg);
}
// I_GetLoginResult.aidl
package com.sp.chattingroom;

// Declare any non-default types here with import statements

interface I_GetLoginResult {  
    void loginSucceed();
    void loginFailed();
}

注释上写了文件名字。
然后build之后就会生成了三个IInterface的类,就是进程通信的关键了,接下来就会利用他们的Binder来实现IPC。
然后是Service的改造

package com.sp.chattingroom.Service;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.github.nkzawa.emitter.Emitter;
import com.github.nkzawa.socketio.client.IO;
import com.github.nkzawa.socketio.client.Socket;
import com.sp.chattingroom.IChatManager;
import com.sp.chattingroom.I_GetLoginResult;
import com.sp.chattingroom.I_NewMessageArrived;
import com.sp.chattingroom.Model.Msg;

import java.net.URISyntaxException;

/**
 * Created by Administrator on 2017/2/20.
 */

public class ChatService extends Service {
    private static final String TAG = "ChatService";
    private Socket socket=null;
    private I_GetLoginResult i_getLoginResult;
    private I_NewMessageArrived i_newMessageArrived;
    private Binder mBinder=new IChatManager.Stub(){
        @Override
        public void SendMsg(Msg msg) throws RemoteException {
            socket.emit("postMsg",msg.getContent());
        }
        @Override
        public void Login(String name, final I_GetLoginResult listener) throws RemoteException {
            i_getLoginResult=listener;
            socket.emit("login",name);
            socket.on("nickExisted", new Emitter.Listener() {
                @Override
                public void call(Object... args) {
                    Log.e(TAG, "nickExisted" );
                    try {
                        listener.loginFailed();
                    }catch (RemoteException e){
                        e.printStackTrace();
                    }
                }
            });
            socket.on("loginSuccess",new Emitter.Listener() {
                @Override
                public void call(Object... args) {
                    Log.e(TAG, "loginSuccess:"+Thread.currentThread().getId());
                    try {
                        listener.loginSucceed();
                    }catch (RemoteException e){
                        e.printStackTrace();
                    }
                }
            });
        }

        @Override
        public void registerNewMsgListener(I_NewMessageArrived listener) throws RemoteException {
            i_newMessageArrived=listener;
        }
        @Override
        public void registerLoginResultListener(I_GetLoginResult listener) throws RemoteException {
            i_getLoginResult=listener;
        }
    };
    @Override
    public void onCreate(){
        super.onCreate();
        /*
         *在这里初始化socket链接
         */
        try {
            socket= IO.socket("http://115.159.38.75:3000");
            socket.connect();
        }catch (URISyntaxException e){
            Log.e(TAG, "run: "+"error" );
            e.printStackTrace();
        }
        while (!socket.connected()){}
        socket.on("newMsg", new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                String newcontent=args[1].toString();
                try {
                    i_newMessageArrived.newMessageArrive(new Msg(0,newcontent));
                }catch (RemoteException e){
                    e.printStackTrace();
                }
            }
        });
    }
    @Override
    public int onStartCommand(Intent i,int flags,int startId){
        Log.e(TAG, "onStartCommand: " );
        return super.onStartCommand(i,flags,startId);
    }
    @Override
    public void onDestroy(){
        /*
         *关闭连接,停止监听
         */
        super.onDestroy();
        while (socket.connected()){
            socket.disconnect();
        }
        socket.off();
        Log.e(TAG, "onDestroy: "+socket.connected());
    }
    @Override
    public IBinder onBind(Intent intent){
        return mBinder;
    }
}

然后是LoginActivity

package com.sp.chattingroom;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.sp.chattingroom.base.LogUtil;
import com.sp.chattingroom.Service.ChatService;

import butterknife.BindView;
import butterknife.ButterKnife;
/**
 * Created by Administrator on 2017/2/21.
 */
public class LoginActivity extends Activity {
    @BindView(R.id.btn_login)Button button;
    @BindView(R.id.edt_username)EditText editText;
    private static final String TAG = "LoginActivity";
    private IChatManager mRemoteManager;
    private I_GetLoginResult mResultListener=new I_GetLoginResult.Stub(){
        @Override
        public void loginSucceed() throws RemoteException {
            LogUtil.log(TAG,"log suc");
            Intent intent=new Intent(LoginActivity.this,ChatActivity.class);
            startActivity(intent);
            finish();
        }
        @Override
        public void loginFailed() throws RemoteException {
            handler.obtainMessage().sendToTarget();
        }
    };
    private ServiceConnection serviceConnection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            LogUtil.log(TAG,"onServiceConnected");
            mRemoteManager=IChatManager.Stub.asInterface(service);
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            mRemoteManager=null;
            LogUtil.log(TAG,"onServiceDisconnected");
        }
    };
    @Override
    protected void onCreate(Bundle s){
        super.onCreate(s);
        setContentView(R.layout.loginactivity);
        ButterKnife.bind(this);
        Intent service=new Intent(this,ChatService.class);
        bindService(service,serviceConnection,BIND_AUTO_CREATE);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String name=editText.getText().toString();
                try {
                    mRemoteManager.Login(name, mResultListener);
                }
                catch (RemoteException e){
                    e.printStackTrace();
                }
            }
        });
    }
    Handler handler=new Handler(){
        @Override
        public void handleMessage(Message message){
            editText.setText("");
            Toast.makeText(LoginActivity.this,"用户名重复",Toast.LENGTH_SHORT).show();
        }
    };
    @Override
    protected void onStart(){
        LogUtil.log(TAG,"onStart");
        super.onStart();
    }
    @Override
    protected void onResume(){
        LogUtil.log(TAG,"onResume");
        super.onResume();
    }
    @Override
    protected void onPause(){
        LogUtil.log(TAG,"onPause");
        super.onPause();
    }
    @Override
    protected void onStop(){
        LogUtil.log(TAG,"onStop");
        super.onStop();
    }
    @Override
    protected void onRestart(){
        LogUtil.log(TAG,"onRestart");
        super.onRestart();
    }
    @Override
    protected void onDestroy(){
        LogUtil.log(TAG,"onDestroy");
        super.onDestroy();
        unbindService(serviceConnection);
    }
    @Override
    protected void onSaveInstanceState(Bundle outState){
        LogUtil.log(TAG,"onSaveInstance");
        super.onSaveInstanceState(outState);
    }
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState){
        LogUtil.log(TAG,"onRestoreInstance");
        super.onSaveInstanceState(savedInstanceState);
    }
    @Override
    public void onConfigurationChanged(Configuration configuration){
        super.onConfigurationChanged(configuration);
        LogUtil.log(TAG,"onConfigurationChanged:"+configuration.orientation);
    }
}

ChatActivity

package com.sp.chattingroom;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import com.github.nkzawa.socketio.client.Socket;
import com.sp.chattingroom.Adapter.ChatRecyclerAdpter;
import com.sp.chattingroom.Adapter.DBHelper;
import com.sp.chattingroom.base.LogUtil;
import com.sp.chattingroom.Model.Msg;
import com.sp.chattingroom.Service.ChatService;

import java.util.ArrayList;
import butterknife.BindView;
import butterknife.ButterKnife;
public class ChatActivity extends AppCompatActivity {
    private static final String TAG = "ChatActivity";
    @BindView(R.id.text_list)RecyclerView recyclerView;
    @BindView(R.id.send_btn)Button button;
    @BindView(R.id.chat_edit)EditText editText;
    private static String IPAddress="115.159.38.75";
    private static int PORT=4000;
    private Socket socket=null;
    private ChatRecyclerAdpter adpter;
    private ArrayList<Msg> msg_list=new ArrayList<>();
    private DBHelper dbHelper;
    private Cursor cursor;
    private Thread thread;
    private NotificationManager notificationManager;
    private IChatManager iChatManager;
    private I_NewMessageArrived i_newMessageArrived=new I_NewMessageArrived.Stub(){
        @Override
        public void newMessageArrive(Msg msg) throws RemoteException {
            Log.e(TAG, "newMsg: "+msg.getContent());
            SendNotification(msg.getContent());
            msg_list.add(msg);
            dbHelper.insert(msg);
            cursor.requery();
            Message.obtain(handler).sendToTarget();
        }
    };
    private ServiceConnection connection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            LogUtil.log("from util","onServiceConnected: "+name.toString());
            iChatManager=IChatManager.Stub.asInterface(service);
            try {
                iChatManager.registerNewMsgListener(i_newMessageArrived);
            }catch (RemoteException e){
                e.printStackTrace();
            }
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            LogUtil.log(TAG, "onServiceDisconnected: "+name.toString());
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.chatactivity);
        ButterKnife.bind(this);
        notificationManager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
        dbHelper=new DBHelper(this);
        cursor=dbHelper.select();
        for (int i=0;i<cursor.getCount();i++){
            cursor.moveToPosition(i);
            Msg msg=new Msg(cursor.getInt(2),cursor.getString(1));
            //msg.setContent(cursor.getString(1));
            //msg.setType(cursor.getInt(2));
            msg_list.add(msg);
        }
        adpter=new ChatRecyclerAdpter(this,msg_list);
        LinearLayoutManager manager=new LinearLayoutManager(this);
        recyclerView.setLayoutManager(manager);
        recyclerView.setAdapter(adpter);
        //绑定service
        Intent startservice=new Intent(this,ChatService.class);
        bindService(startservice,connection,BIND_AUTO_CREATE);

        recyclerView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                recyclerView.scrollToPosition(msg_list.size()-1);
            }
        });
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String msg_send=editText.getText().toString();
                //binder.sendMSg(msg_send);
                Msg msg=new Msg(1,msg_send);
                try {
                    iChatManager.SendMsg(msg);
                }catch (RemoteException e){
                    e.printStackTrace();
                }
                //msg.setType(1);
                //msg.setContent(msg_send);
                msg_list.add(msg);
                dbHelper.insert(msg);
                cursor.requery();
                Message.obtain(handler).sendToTarget();
                editText.setText("");
            }
        });
    }
    Handler handler=new Handler(){
        @Override
        public void handleMessage(Message message){
            adpter.notifyDataSetChanged();
            recyclerView.scrollToPosition(msg_list.size()-1);
        }
    };
    private void SendNotification(String content){
        LogUtil.log(TAG, "SendNotification: "+content );
        /*这里要注意一个细节。
         *如果当前Activity存在的话,不应该再create一个新的活动,应该是回到当前活动。
         * 所以要给Intent添加对应的flag
         */
        Intent i=new Intent(Intent.ACTION_MAIN);
        i.addCategory(Intent.CATEGORY_LAUNCHER);
        i.setComponent(new ComponentName(this,ChatActivity.class));
        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
        PendingIntent p=PendingIntent.getActivity(this,0,i,0);
        Notification notification=new Notification.Builder(this)
                .setAutoCancel(true)
                .setContentText(content)
                .setContentTitle("新消息")
                .setTicker("Ticker")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher)
                .setDefaults(Notification.DEFAULT_SOUND)
                .setContentIntent(p)
                .build();
        notificationManager.notify(0,notification);
    }
    @Override
    public void onDestroy(){
        unbindService(connection);
        super.onDestroy();
        Log.e(TAG, "onDestroy");
    }
    @Override
    public void onBackPressed(){
        Intent home = new Intent(Intent.ACTION_MAIN);
        home.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        home.addCategory(Intent.CATEGORY_HOME);
        startActivity(home);
    }
}

下一阶段目标:

  • 继续实现断线重连。。。
  • 同时搭建推送平台
  • 进程保活,互相拉活的学习。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值