文档章节

ConnectSTU的制作过程

宋昊
 宋昊
发布于 2016/05/17 08:10
字数 3972
阅读 20
收藏 0

首先,软件追求的目的是简洁和自动化,让我用尽量少的步骤来自动重复登录这个无线网络(反复提交登录请求),并且保持长久的连接(Activity和Service要尽量不被后台杀死)。

因为需要解析登录之后返回的页面,所以在网络方面,我选择使用Jsoup这一工具(后来发现不用也行)。

那么,制作过程就开始了。

一开始,一个简单的界面:俩EditText和一个Button附带一些说明的TextView和一个反馈TextView。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
    android:padding="@dimen/activity_margin"
    tools:context="org.out.naruto.connectstu.Activity_Main">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/str_main_introduce" />

    <EditText
        android:id="@+id/id_main_et_stuid"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="学号"
        android:inputType="number" />

    <EditText
        android:id="@+id/id_main_et_pwd"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="密码"
        android:inputType="textPassword" />
    <Button
        android:id="@+id/id_main_bt_login"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/str_main_bt_login"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/str_main_more"/>

    <TextView
        android:layout_marginTop="20dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:autoLink="email"
        android:text="@string/str_main_fb"/>

</LinearLayout>

点击button之后,另外启动一个线程来登录。咦,这时候就不对了,app后台之后,线程还跑个**。

 

那还是写个service吧,点击button之后,startService,这Service犹如脱缰野马,不受我控制了,都能独立于Activity之外存在了,用户想要控制的太少,想提前下线换设备登录都不行。

 

那就BindService吧,这样Service生命周期就和启动它的Activity相关了,Activity还可以把用户名和密码放到Intent里传过去,顺手在Service里写个接口,设置一个回调接口。

serviece完整代码:

package org.out.naruto.connectstu;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by Hao_S on 2016/5/5.
 */

public class ConnectService extends Service {
    public static final int LOGIN_SUCCESS = 0x100, PWD_WRONG = 0x101, UN_WRONG = 0x102,
            UNKNOWN_WRONG = 0x103, LOGOUT_SUCCESS = 0x104, LIMITED_WROING = 0x105,
            TIMEOUT_WROING = 0x106, WIFICHANGE = 0x107, DOCNULL_WRONG = 0x108;// 一些状态码


    private final static String TAG = "Connect_ConnectService";
    private NotificationManager notificationManager;
    private Timer connectTimer;

    private Document document;
    private static final String url = "http://192.168.8.10/portal/login.jsp?Flag=0";
    private static final String logoutUrl = "http://192.168.8.10/portal/logout.jsp";

    private Map<String, String> map;
    private User user;

    private OnConnectListener onConnectListener;

    private Notification.Builder notification;

    private boolean logINorOUT = true;// true = login, false = logout;

    private int connectTimes = 0;

    public ConnectService() {
        map = new HashMap<>();// 这些需要提交的固定参数,在一开始就准备好。
        map.put("isSavePass", "on");
        map.put("Submit1", "%C1%AC%BD%D3");
        map.put("Language", "Chinese");
        map.put("sessionID", "3970696304798764551");
        map.put("timeoutvalue", "45");
        map.put("heartbeat", "240");
        map.put("fastwebornot", "false");
        map.put("StartTime", new Date().getTime() + "");
        map.put("shkOvertime", "720");
        map.put("iIPCONFIG", "0");
        map.put("sHttpPrefix", "http://192.168.8.10");
        map.put("title", "CAMS Portal");
    }

    @Override
    public void onCreate() {
        super.onCreate();

        // 动态注册监听,监听WIFI状态的变化。
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        registerReceiver(mReceiver, intentFilter);

        notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, Activity_Main.class), 0);
        notification = new Notification.Builder(this).setTicker(getString(R.string.app_name))
                .setSmallIcon(R.mipmap.ic_launcher).setOngoing(true).setContentTitle(getString(R.string.app_name))
                .setContentText("建议保持程序后台运行")
                .setContentIntent(pendingIntent);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 下面的代码我是纠结于放在哪,既然bindservice,放在activity里保持activity常驻后台,那么这个service也就理应会存在。

       /* notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, Activity_Main.class), 0);
        notification = new Notification.Builder(this).setTicker(getString(R.string.app_name))
                .setSmallIcon(R.mipmap.ic_launcher).setOngoing(true).setContentTitle(getString(R.string.app_name))
                .setContentText("建议保持程序后台运行")
                .setContentIntent(pendingIntent);*/

        return super.onStartCommand(intent, flags, startId);
    }

    public void setOnConnectListener(OnConnectListener onConnectListener) {
        this.onConnectListener = onConnectListener;
    }

    @Override
    public IBinder onBind(Intent intent) {

        Log.i(TAG, "onBind");

//        user = intent.getParcelableExtra("user"); // 获取数据

//        Log.i(TAG, user.getStrUN());

//        startConnect(user);

        return new MyBinder(); // 返回binder对象,方便activity控制。
    }


    /**
     * @param user 开始自动连接,每20s一次
     */

    public void startConnect(User user) {

        logINorOUT = user.isLogIn();

        if (logINorOUT) {
            notificationManager.notify(0, notification.build());
        } else {
            notificationManager.cancel(0);
        }

        map.put("ClientIP", user.getStrIp());
        map.put("username", user.getStrUN());
        map.put("password", user.getStrPwd());
        map.put("strOldPrivateIP", user.getStrIp());
        map.put("strOldPublicIP", user.getStrIp());
        map.put("strPrivateIP", user.getStrIp());
        map.put("PublicIP", user.getStrIp());

        connectTimer = new Timer();
        connectTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                Log.i(TAG, "TimerTask run~");
                if (onConnectListener != null)
                    onConnectListener.onConnectState(connect());
                document = null;
            }
        }, 0, 20000);
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        if (connectTimer != null)
            connectTimer.cancel();
        unregisterReceiver(mReceiver);
        if(notificationManager!=null&&notification!=null)
            notificationManager.cancel(0);
        Log.i(TAG, "service destroy");
    }

    /**
     * 具体访问网络的地方
     *
     * @return 连接之后的状态码
     */

    private int connect() {
        try {
            Log.i(TAG, "第" + ++connectTimes + "次连接");
            document = Jsoup.connect(logINorOUT ? url : logoutUrl).data(map).timeout(50000).post();// 开始尝试连接
            if (document.toString() == null || document == null)// 这个貌似没什么用 如果发生错误,Document是空的 直接报错 跳转到catch里,然后继续往下执行。
                return DOCNULL_WRONG;
        } catch (SocketTimeoutException e) {
            // 连接超时返回TIMEOUT
            return TIMEOUT_WROING;
        } catch (IOException e) {
            e.printStackTrace();
            return DOCNULL_WRONG;
        }

        try {
//            Log.i(TAG, document.toString());

            int length = document.toString().length();
//            Log.i(TAG, "length:" + length + "\n" + document.toString());
            if (length == 1942 || length == 2119) {
                // 请叫我机智的少年 ~ ~
                // 这两个长度都是连接成功时返回的html文本长度,其中1942是第一次连接成功的长度,返回一个空的页面,2119是提示已经连接成功后的页面。
                return LOGIN_SUCCESS;
            }

            if (length == 2334) {
                // 2334就是登出成功的长度。
                connectTimer.cancel();
                return LOGOUT_SUCCESS;
            }

            Element select = document.select("td[class]").get(0);
/*
            String stse = select.text().toString().substring(0, 5);


            if (stse.equals("您已经断开")) {
                connectTimer.cancel();
                return LOGOUT_SUCCESS;
                这段代码应该也用不到了
            }*/


//            if (select.text().toString().equals("\"您已经建立了连接。\"")) {
//                return LOGIN_SUCCESS;
//            } 这段代码可以不要了

            // 如果执行到这里还是没有返回,那么应该是遇到以下的一种情况了

            String string = select.getElementsByTag("b").text().toString().substring(0, 5);

            if (string.equals("E2553")) {
                Log.i(TAG, "用户密码错误");
                connectTimer.cancel();
                return PWD_WRONG;
            } else if (string.equals("E2531")) {
                Log.i(TAG, "用户不存在或者用户没有申请该服务");
                connectTimer.cancel();
                return UN_WRONG;
            } else if (string.equals("E2542")) {
                Log.i(TAG, "超出用户数量限制");
                connectTimer.cancel();
                return LIMITED_WROING;
            }

            return UNKNOWN_WRONG;
        } catch (IndexOutOfBoundsException e) {

            return UNKNOWN_WRONG;
        }
    }

    public class MyBinder extends Binder {

        public ConnectService getService() {
            return ConnectService.this;
        }

    }

    /**
     * 监听回调接口
     */
    public interface OnConnectListener {
        void onConnectState(int state);
    }


    /**
     * 一个广播接收,用以在WIFI状态变化时,及时断开连接
     */

    private BroadcastReceiver mReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
                Log.i(TAG, "network staite had changed!");
                WifiManager wifiManager = (WifiManager) getSystemService(ConnectService.this.WIFI_SERVICE);
                WifiInfo wifiInfo = wifiManager.getConnectionInfo();
                String wifiName = wifiInfo.getSSID();
                if (!wifiName.equals("\"QLSC_STU\"") || !wifiName.equals("QLSC_STU")) {
                    if (connectTimer != null) {
                        connectTimer.cancel();
                        Log.i(TAG, "timer has stoped!");
                        if (onConnectListener != null)
                            onConnectListener.onConnectState(WIFICHANGE);
                    }
                }
            }
        }

    };

}

BingService的一些准备工作,需要三个参数:intent就不必说了,但是要把要传输的数据放到里面

connectIntent.putExtra("user", user);

这里要注意的是,自己写的对象类要implements Serializable或Parcelable。Parcelable是Android特有的,Serializable是Java带的,从效率上来说肯定是Parcelable更好一些,但是就我这点数据无所谓了~~。

实现Serializable还是比较简单的直接声明就好,实现Parcelable要实现两个方法和一个嵌入接口:

public interface Parcelable {
    //内容描述接口
    public int describeContents();
    //写入接口函数,打包
    public void writeToParcel(Parcel dest, int flags);
     //读取接口,目的是要从Parcel中构造一个实现了Parcelable的类的实例处理。因为实现类在这里还是不可知的,所以需要用到模板的方式,继承类名通过模板参数传入。
    //为了能够实现模板参数的传入,这里定义Creator嵌入接口,内含两个接口函数分别返回单个和多个继承类实例。
    public interface Creator<T> {
           public T createFromParcel(Parcel source);
           public T[] newArray(int size);
       }
}

//下面是我的实现 getter和setter就先省略了

private String strUN, strPwd, strIp;

private boolean logIn = true; // false 为登出

public static final Parcelable.Creator<User> CREATOR = new Creator<User>() {

        @Override
        public User createFromParcel(Parcel source) {
            User user = new User();
            user.setStrUN(source.readString());
            user.setStrPwd(source.readString());
            user.setStrIp(source.readString());
            user.setLogIn(Boolean.parseBoolean(source.readString()));
            return user;
        }

        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(strUN);
        dest.writeString(strPwd);
        dest.writeString(strIp);
        dest.writeString(logIn+"");
    }

    @Override
    public int describeContents() {
        return 0;
    }

 

第二个参数ServiceConncetion,用以和绑定的service来“互动”,其中要实现两个方法,onServiceConnected是连接成功的回调,onServiceDisconnected是连接断开的回调,根据自己的需求来操作。

我的是在连接成功之后,获取service对象,设置监听。

 private ServiceConnection serviceConnection = new ServiceConnection() {

        private boolean flag = true; // 用于标识是不是第一次连接~~ = =

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

            connectService = ((ConnectService.MyBinder) service).getService();

            if (connectService == null)
                Log.i(TAG, "connectService is null");

            Log.i(TAG, "onServiceConnected");

            connectService.setOnConnectListener(new ConnectService.OnConnectListener() {
                @Override
                public void onConnectState(int state) {
                    mainHandler.sendEmptyMessage(state);
                }
            });
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

第三个参数 flags 绑定时的选项,0为空。源码里是这么写的

@IntDef(flag = true,
            value = {
                BIND_AUTO_CREATE,
                BIND_DEBUG_UNBIND,
                BIND_NOT_FOREGROUND,
                BIND_ABOVE_CLIENT,
                BIND_ALLOW_OOM_MANAGEMENT,
                BIND_WAIVE_PRIORITY,
                BIND_IMPORTANT,
                BIND_ADJUST_WITH_ACTIVITY
            })

大部分网上的例子都是直接用了 BIND_AUTO_CREATE:只要绑定存在,就自动创建Service。

BIND_DEBUG_UNBIND:debug模式下用的,具体我也没这么设置过。

BIND_NOT_FOREGROUND: 不允许该绑定至目标服务的进程提高到前台调度优先级(PS:前台进程>可见进程>服务进程>后台进程>空进程;销毁方向逆序)。

BIND_ABOVE_CLIENT:表面该服务比该客户端还要重要(貌似是我想要的)。

BIND_ALLOW_OOM_MENEGEMENT: allow the process hosting the bound service to go through its normal memory management. 这是原话,允许进程托管的绑定服务经历正常的内存管理过程??难道还能不正常?

BIND_WAIVE_PRIOPITY:不影响目标服务的宿主进程的调度和内存管理的优先级。允许后台LRU列表就像在后台定期应用过程中对管理的服务的过程。

BIND_IMPORTANT:这项服务是在客户端非常重要的,所以当客户端应提请前台进程的水平。

BIND_ADJUST_WITH_ACTIVITY: If binding from an activity, allow the target service's process importance to be raised based on whether the activity is visible to the user, regardless whether another flag is used to reduce the amount that the client process's overall importance is used to impact it.(微笑脸)

这个问题探究的不是很深,不敢随意误导他人,暂且放置一下。

 

接着问题来了,在点击LoginButton自动连接之后,用户肯定会后台这个应用,一般都会直接按home键,保不保存状态先不说,运气不好的话没几分钟这三个service就被系统杀死了,真的好尴尬,本来学校WIFI是每15分钟断开一次,至少得撑得了15分钟吧。

遂决定去解决serviece常驻后台的事情。

一般都有用过安卓VPN客户端吧,我用lantern,它在连接之后就会发送一个常驻消息栏通知,借此来实现serviece不被后台杀死,那我也这么干吧。

首先创建这个通知、这个通知的点击事件同时获得通知管理对象。

 PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, Activity_Main.class), 0);
        notification = new Notification.Builder(this).setTicker(getString(R.string.app_name))
                .setSmallIcon(R.mipmap.ic_launcher).setOngoing(true).setContentTitle(getString(R.string.app_name))
                .setContentText("建议保持程序后台运行")
                .setContentIntent(pendingIntent);

 notificationManager = (NotificationManager) this
                .getSystemService(NOTIFICATION_SERVICE);

这里又出现另外一个point,这里new Intent,启动MainActivity,如果不加以修改,就会启动一个全新的Activity,所以需要在AndroidManifest文件里相应的Activity修改启动模式

android:launchMode="singleTask"

launchMode有四种模式,默认是standard;这里修改为singleTask,始终只存在这一个Activity;singleTop是当所启动的Activity在栈顶时不创建新的,通过onNewIntent返回栈顶目标Activity;singInstance非常类似singleTask,当确定此Activity只有一个时才用,貌似不推荐使用。

notification的创建过程也很简单,不必多说。

创建好之后合适的时机显示

notificationManager.notify(0, notification.build());

第一个参数0是我自己设置的,用来唯一标识这个通知,进行其他操作的时候用。

据说这样可以让应用在后台久一点。

还可以在AndroidMinafest文件的application标签下添加

android:persistent="true"

但我感觉没啥卵用......

 

2016/05/20更新

在前天的测试中,发现如果把notification放在Activity里,后台不出10分钟就会被杀死,真是尴尬啊,好尴尬好尴尬,还是放在serviece里面吧,

在serviece的onCreate方法里:

 notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, Activity_Main.class), 0);
        notification = new Notification.Builder(this).setTicker(getString(R.string.app_name))
                .setSmallIcon(R.mipmap.ic_launcher).setOngoing(true).setContentTitle(getString(R.string.app_name))
                .setContentText("建议保持程序后台运行")
                .setContentIntent(pendingIntent);

现在整理一下整个app的流程:

启动app(读取用户之前是否登陆过,如果有则填充用户名和密码Edittext;bindservice→用户点击登录button,serviece向通知栏发出通知,保持后台;启动timer,重复登录。

同时,在serviece里面动态注册了一个broadcastReciver,检测到WIFI变化时则停止timer,同时取消通知。

serviece里还曾经出过一个问题:在Android 4.1版本中,获取WIFI名称(getSSID)的结果和高版本不一样 =-= 所以就↓这样了

  String wifiName = wifiInfo.getSSID();
                if (!wifiName.equals("\"QLSC_STU\"") || !wifiName.equals("QLSC_STU")) {

在MainActivity下,在Activity被意外销毁时保存下状态,在onCreate里回复一下,这样让用户感觉Activity没有被销毁。

serviece的回调,handler更新UI就不详细写了,很基础的内容。

记得在onDestroy里释放相关资源服务。

经过真机测试,在自习室正常后台情况下可以后台一两个小时,内存大的手机同时聊微信QQ刷淘宝都没问题。CPU和内存占用率也很低。

最后附上MainActivity的代码(serviece代码在前面已经有了):

package org.out.naruto.connectstu;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class Activity_Main extends AppCompatActivity {
    private static final String TAG = "Activity_Main";

    private MainHandler mainHandler;
    private SharedPreferences sharedPreferences;
    private boolean connectSTUFlag = false;// false是准备登录,true是准备登出。
    private boolean breakFlag = false; // 中断是否重连标识。
    private int progremState = -1;

    private User user;

    private ConnectService connectService;
    private Intent connectIntent;
    private ServiceConnection serviceConnection = new ServiceConnection() {

        private boolean flag = true; // 用于标识是不是第一次连接~~ = =

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

            connectService = ((ConnectService.MyBinder) service).getService();

            if (connectService == null)
                Log.i(TAG, "connectService is null");

            Log.i(TAG, "onServiceConnected");

            if (breakFlag) {
                connectService.startConnect(user);
            }

            connectService.setOnConnectListener(new ConnectService.OnConnectListener() {
                @Override
                public void onConnectState(int state) {
                    mainHandler.sendEmptyMessage(state);
                }
            });
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

//    private NotificationManager notificationManager;
//    private Notification.Builder notification; // 也是无奈之举  = =

    private EditText stuidET, pwdET;
    private Button loginButton;

    private String str_bt_login, str_bt_logout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity__main);

        str_bt_login = getString(R.string.str_main_bt_login);
        str_bt_logout = getString(R.string.str_main_bt_logout);

        mainHandler = new MainHandler();

        stuidET = (EditText) findViewById(R.id.id_main_et_stuid);
        pwdET = (EditText) findViewById(R.id.id_main_et_pwd);
        loginButton = (Button) findViewById(R.id.id_main_bt_login);

        connectIntent = new Intent(Activity_Main.this, ConnectService.class);
        sharedPreferences = Activity_Main.this.getSharedPreferences("ConnectSTU", MODE_PRIVATE);

        if (user == null)
            user = new User();

        String stuid = sharedPreferences.getString("stuid", "null");
        String pwd = sharedPreferences.getString("pwd", "null");
        if (!stuid.equals("null") && !pwd.equals("null")) {
            stuidET.setText(stuid);
            pwdET.setText(pwd);
            user.setStrUN(stuid);
            user.setStrPwd(pwd);
        }

        connectIntent.putExtra("user", user);

        bindService(connectIntent, serviceConnection, Context.BIND_AUTO_CREATE);


        loginButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                loginButton.setClickable(false);
                if (connectSTUFlag) {
                    progremState = 2;
                    loginButton.setText("下线中...");
                    user.setLogIn(false);
                    connectIntent.putExtra("user", user);
                    connectService.startConnect(user);
                    connectSTUFlag = false;
                } else {

                    String ip = judgeWifiState();
                    if (!ip.equals("error")) {

                        if (user == null)
                            user = new User();
                        String stuid = stuidET.getText().toString().trim();
                        String pwd = pwdET.getText().toString().trim();
                        if (!stuid.equals("") && !pwd.equals("")) {
                            progremState = 1;
                            loginButton.setText("登录中...");
                            user.setStrIp(ip);
                            user.setStrUN(stuid);
                            user.setStrPwd(pwd);
                            user.setLogIn(true);

                            connectIntent.putExtra("user", user);

                            bindService(connectIntent, serviceConnection, Context.BIND_ABOVE_CLIENT);// 提升一下重要性??
                            connectService.startConnect(user);

                            connectSTUFlag = true;
                        } else {
                            ShowToast("用户名或密码不能为空");
                        }
                    }
                }
            }
        });

//        notificationManager = (NotificationManager) this
//                .getSystemService(NOTIFICATION_SERVICE);

        if (savedInstanceState != null) {
            Log.i(TAG, "savedInstanceState is not null");
            int tempInt = savedInstanceState.getInt("state");
            user = savedInstanceState.getParcelable("user");
            breakFlag = true;
            switch (tempInt) {
                case ConnectService.LOGIN_SUCCESS:
                    loginButton.setText(str_bt_logout);
                    break;
                case 1:
                    loginButton.setText("登录中...");
                    break;
                case 2:
                    loginButton.setText("下线中...");
                    break;
                default:
                    breakFlag = false;
                    loginButton.setText(str_bt_login);
            }
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        breakFlag = true;
        outState.putInt("state", progremState);
        outState.putParcelable("user", user);
        outState.putBoolean("breakFlag", breakFlag);
    }

    private String judgeWifiState() {
        //获取wifi服务
        WifiManager wifiManager = (WifiManager) getSystemService(Activity_Main.this.WIFI_SERVICE);
        //判断wifi是否开启
        if (!wifiManager.isWifiEnabled()) {
            // 打开wifi = =
            wifiManager.setWifiEnabled(true);
            ShowToast("我给你打开 \t WIFI 了");
        }
        WifiInfo wifiInfo = wifiManager.getConnectionInfo();

        String wifiName = wifiInfo.getSSID();

        if (wifiName.equals("\"QLSC_STU\"") || wifiName.equals("QLSC_STU")) {
            int ipAddress = wifiInfo.getIpAddress();
            String ip = intToIp(ipAddress);
            return ip;
        } else {
            Log.i(TAG, "wifiName:" + wifiName);
            ShowToast("连接的不是QLSC_STU,连好了再试一下。");
            loginButton.setClickable(true);
            return "error";
        }
    }

    private void ShowToast(String message) {
        Toast.makeText(Activity_Main.this, message, Toast.LENGTH_SHORT).show();
    }

    public static String intToIp(int i) {
        // 把获取到的int型ip转化成string
        return (i & 0xFF) + "." +
                ((i >> 8) & 0xFF) + "." +
                ((i >> 16) & 0xFF) + "." +
                (i >> 24 & 0xFF);
    }

    private class MainHandler extends Handler {

        private boolean isFirstLogin = true;

        @Override
        public void handleMessage(Message msg) {
            loginButton.setClickable(true);
            progremState = msg.what;
            connectSTUFlag = false;
            breakFlag = false;
            loginButton.setText(str_bt_login);
            switch (msg.what) {
                case ConnectService.PWD_WRONG:
                    ShowToast("密码错误!登录失败");
                    break;
                case ConnectService.UN_WRONG:
                    ShowToast("用户名错误!登录失败");
                    loginButton.setText(str_bt_login);
                    break;
                case ConnectService.LOGIN_SUCCESS:
                    connectSTUFlag = true;
                    loginButton.setText(str_bt_logout);
                    if (isFirstLogin) {
                        ShowToast("连接成功!");
                        // 存储用户名和密码~
                        SharedPreferences.Editor editor = sharedPreferences.edit();
                        editor.putString("stuid", user.getStrUN());
                        editor.putString("pwd", user.getStrPwd());
                        editor.commit();
                        isFirstLogin = false;
                    }
                    break;
                case ConnectService.UNKNOWN_WRONG:
                    ShowToast("遇到了未知错误");
                    break;
                case ConnectService.LOGOUT_SUCCESS:
                    ShowToast("登出成功");
                    break;
                case ConnectService.LIMITED_WROING:
                    ShowToast("在线用户数量限制!");
                    break;
                case ConnectService.TIMEOUT_WROING:
                    ShowToast("连接超时!\n可能是网路不好,但我还在努力连接中!");
                    break;
                case ConnectService.WIFICHANGE:
                    ShowToast("WIFI状态变化,已停止自动连接!");
                    break;
                case ConnectService.DOCNULL_WRONG:
                    // donothing
                    break;
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(serviceConnection);
    }
}

参考博客:

http://www.juwends.com/tech/android/android-service-2.html

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0520/2897.html

2016/05/20 11:13完结

© 著作权归作者所有

共有 人打赏支持
宋昊
粉丝 3
博文 7
码字总数 11731
作品 0
济南
程序员
怎样在几何画板中查看课件制作过程

几何画板主要以点、线、圆为基本元素,通过对这些基本元素的变换、构造、测算、计算、动画、跟踪轨迹等,构造出其它较为复杂的图形。是数学、物理教学中强有力的工具。对于一个几何画板初学者...

学术研究软件
2016/04/11
55
0
USB启动盘制作软件 - iBurnMgr

iBurnMgr是一款基于Direct2D DirectWrite开发的USB启动盘制作软件,采用流行的扁平风格,使用原生C++开发,不依赖任何第三方库,USB启动盘制作过程使用多线程技术,制作过程可以中途终止,界...

Force武装卫队
2014/06/18
0
4
安装盘制作工具--NextInstaller

NextInstaller是一个功能强大的安装盘制作工具 1.可以制作C/S应用软件安装盘。 2.可以制作软件升级包。 3.可以制作数据库安装盘。 4.可以制作数据库升级包。 5.可以制作Web安装盘(asp,.net,j...

匿名
2009/03/30
4.4K
1
NextInstaller的网友评论

NextInstaller是一个功能强大的安装盘制作工具 1.可以制作C/S应用软件安装盘。 2.可以制作软件升级包。 3.可以制作数据库安装盘。 4.可以制作数据库升级包。 5.可以制作Web安装盘(asp,.net,j...

nextinstaller
2009/12/11
172
1
Groover

制作各种节奏的鼓声音乐。制作过程如下:一共有三种鼓声(还包括一种类似沙槌的声音)。界面上出现3*16的格子,每一行对应一种乐器的声音,每一格表示击打一次。对这48个格子,随便点击选择(...

匿名
2012/11/05
320
0

没有更多内容

加载失败,请刷新页面

加载更多

20180920 rzsz传输文件、用户和用户组相关配置文件与管理

利用rz、sz实现Linux与Windows互传文件 [root@centos01 ~]# yum install -y lrzsz # 安装工具sz test.txt # 弹出对话框,传递到选择的路径下rz # 回车后,会从对话框中选择对应的文件传递...

野雪球
今天
2
0
OSChina 周四乱弹 —— 毒蛇当辣条

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @ 达尔文:分享花澤香菜/前野智昭/小野大輔/井上喜久子的单曲《ミッション! 健?康?第?イチ》 《ミッション! 健?康?第?イチ》- 花澤香菜/前野智...

小小编辑
今天
7
3
java -jar运行内存设置

java -Xms64m #JVM启动时的初始堆大小 -Xmx128m #最大堆大小 -Xmn64m #年轻代的大小,其余的空间是老年代 -XX:MaxMetaspaceSize=128m # -XX:CompressedClassSpaceSize=6...

李玉长
今天
4
0
Spring | 手把手教你SSM最优雅的整合方式

HEY 本节主要内容为:基于Spring从0到1搭建一个web工程,适合初学者,Java初级开发者。欢迎与我交流。 MODULE 新建一个Maven工程。 不论你是什么工具,选这个就可以了,然后next,直至finis...

冯文议
今天
2
0
RxJS的另外四种实现方式(四)——性能最高的库(续)

接上一篇RxJS的另外四种实现方式(三)——性能最高的库 上一篇文章我展示了这个最高性能库的实现方法。下面我介绍一下这个性能提升的秘密。 首先,为了弄清楚Most库究竟为何如此快,我必须借...

一个灰
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部