Android实现模拟登陆教务系统并解析网页数据

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 版权声明:本文为博主原创文章,转载请注明出处http://blog.csdn.net/u013132758。 https://blog.csdn.net/u013132758/article/details/73203820 前言     时光飞逝,日月如梭,转眼间四年的大学生活已经结束啦!开始了程序员的加班生活。
版权声明:本文为博主原创文章,转载请注明出处http://blog.csdn.net/u013132758。 https://blog.csdn.net/u013132758/article/details/73203820

前言

     时光飞逝,日月如梭,转眼间四年的大学生活已经结束啦!开始了程序员的加班生活。我的第二学位的毕业设计是实现一个学习小助手。这其中最重要的环节就是模拟登录学校的教务系统,获取到教务系统的数据并解析,用自己的数据库存储,展示在自己设计的界面上。例如课程表我是仿照超级课程表的界面来设计的。废话不多说下面先看看效果。

   

        

抓取教务系统登录时需要传递的参数

     模拟登录之前我们首先需要抓取我们登录时所需要传递的数据,可能有人会想用专业的抓包工具来抓包,其实不用那么复杂,用火狐浏览器或者Chrom浏览器的开发者模式就可以了。博主用的是火狐浏览器抓包,传的一些参数也是按照火狐浏览器来的。

首先,我们来看一下模拟器登录时需要传递的参数及HTTP请求头,我们可以看到请求是post请求,请求头字段基本差不多

传递的参数有这么些



其中这些参数中lt这个是搞的我最头疼的。本以为lt是一个固定值,但是模拟登录的时候发现不对,每次抓包lt是不一样的。最后,只能通过学习JS代码,研究这个lt的取值,最后发现lt及其他参数都隐藏在返回的HTML页面的代码中:(如下图)


搞清楚需要传什么参数和请求的HTTP头了,我们就可以模拟登录教务系统了。

自定义HTTPClient实现模拟登录

实现模拟登录首先要自定义HTTPClient,来模拟浏览器发送HTTP请求。自定义HTTP如下代码:

/**
 * Http请求工具类
 * @author leiqi
 * @date 2017-3-4
 */
public class HttpUtil {
	private static AsyncHttpClient client = new AsyncHttpClient(); // 实例话对象
	// Host地址
	public static final String HOST = "cas.hdu.edu.cn";
	// 基础地址
	public static final String URL_BASE = "http://i.hdu.edu.cn/dcp/xphone/";
	// 验证码地址
	public static final String URL_CODE = "http://cas.hdu.edu.cn/cas/Captcha.jpg";
	// 登陆地址
	public static final String URL_LOGIN = "http://cas.hdu.edu.cn/cas/login?service=http%3a%2f%2fi.hdu.edu.cn%2fdcp%2fxphone%2fm.jsp";
	// 登录成功的首页
	public static String URL_MAIN = "http://i.hdu.edu.cn/dcp/xphone/m.jsp";
	//当前学期课表
	public static String URL_Course= "http://i.hdu.edu.cn/dcp/xphone/kbcx0.jsp";
	//考试安排url
	public static String URl_KSAP = "http://i.hdu.edu.cn/dcp/xphone/ksap.jsp";
	//校园新闻
	public static String Url_XYXW = "http://m.hdu.edu.cn/";
	//上课时间
	public static String Url_Time = URL_BASE+"TimeTable.jsp";
	//我的学费
	public static String Url_WDXF = "http://yxt.hdu.edu.cn/EducationManager/xphone/m.jsp";

	/**
	 * 请求参数
	 */
	public static String captcha = "";//验证码
	public static String encodedService = "http%3a%2f%2fi.hdu.edu.cn%2fdcp%2fxphone%2fm.jsp";
	public static String loginErrCnt = "0";
	public static String lt = "LT-1552500-7P9jMewfE3wH2dWObBuJ";
	public static String password = "19191cf09b99b03ab0df1db04c3840ed";
	public static String username = null;
	public static String service = "http://i.hdu.edu.cn/dcp/xphone/m.jsp";
	public static String serviceName = null;
	public static String ticket = null;
	public static String Cookie = "key_dcp_cas=HHxRYyDMhr0GmDfQ6vgPxXQT8yCsvPSCg0MWBnnnWMGv4dQngpLS!748587538; route=4376efc7edf61c9fe699e82a2fb7a34f" ;
	// 静态初始化
	static {
		client.setTimeout(10000); // 设置链接超时,如果不设置,默认为10s
		// 设置请求头
		client.addHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
		client.addHeader("Accept-Encoding","gzip, deflate");
		client.addHeader("Accept-Language","zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
		client.addHeader("Connection","keep-alive");
		client.addHeader("Cookie", Cookie);
		client.addHeader("Host", HOST);
		client.addHeader("Referer", URL_LOGIN);
		client.addHeader("User-Agent",
				"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:52.0) Gecko/20100101 Firefox/52.0");
		client.addHeader("Upgrade-Insecure-Requests","1");

	}



	/**
	 * get,用一个完整url获取一个string对象
	 * 
	 * @param urlString
	 * @param res
	 */
	public static void get(String urlString, AsyncHttpResponseHandler res) {
		client.get(urlString, res);
	}

	/**
	 * get,url里面带参数
	 *  @param urlString
	 * @param params
	 * @param res
	 */
	public static void get(String urlString, RequestParams params,
						   AsyncHttpResponseHandler res) {
		client.get(urlString, params, res);
	}

	/**
	 * get,不带参数,获取json对象或者数组
	 * 
	 * @param urlString
	 * @param res
	 */
	public static void get(String urlString, JsonHttpResponseHandler res) {
		client.get(urlString, res);
	}

	/**
	 * get,带参数,获取json对象或者数组
	 * 
	 * @param urlString
	 * @param params
	 * @param res
	 */
	public static void get(String urlString, RequestParams params,
                           JsonHttpResponseHandler res) {
		client.get(urlString, params, res);
	}

	/**
	 * get,下载数据使用,会返回byte数据
	 * 
	 * @param uString
	 * @param bHandler
	 */
	public static void get(String uString, BinaryHttpResponseHandler bHandler) {
		client.get(uString, bHandler);
	}

	/**
	 * post,不带参数
	 * 
	 * @param urlString
	 * @param res
	 */
	public static void post(String urlString, AsyncHttpResponseHandler res) {
		client.post(urlString, res);
	}

	/**
	 * post,带参数
	 * 
	 * @param urlString
	 * @param params
	 * @param res
	 */
	public static void post(String urlString, RequestParams params,
                            AsyncHttpResponseHandler res) {
		client.post(urlString, params, res);
	}

	/**
	 * post,不带参数,获取json对象或者数组
	 * 
	 * @param urlString
	 * @param res
	 */
	public static void post(String urlString, JsonHttpResponseHandler res) {
		client.post(urlString, res);
	}

	/**
	 * post,带参数,获取json对象或者数组
	 * 
	 * @param urlString
	 * @param params
	 * @param res
	 */
	public static void post(String urlString, RequestParams params,
                            JsonHttpResponseHandler res) {
		client.post(urlString, params, res);
	}

	/**
	 * post,返回二进制数据时使用,会返回byte数据
	 * 
	 * @param uString
	 * @param bHandler
	 */
	public static void post(String uString, BinaryHttpResponseHandler bHandler) {
		client.post(uString, bHandler);
	}

	/**
	 * 返回请求客户端
	 * 
	 * @return
	 */
	public static AsyncHttpClient getClient() {
		return client;
	}

	/**
	 * 获得登录时所需的请求参数
	 * 
	 * @return
	 */
	public static RequestParams getLoginRequestParams() {
		// 设置请求参数
		RequestParams params = new RequestParams();
		params.add("captcha", captcha);
		params.add("encodedService", encodedService);
		params.add("loginErrCnt", loginErrCnt);
		params.add("lt", lt);
		params.add("password", password);
		params.add("username", username);
		params.add("service", service);
		params.add("serviceName", serviceName);
		return params;
	}

	/**
	 * 获取请求首页参数
	 * @return
	 */
	public static RequestParams gethomeRequestParams(){
		RequestParams params = new RequestParams();
		params.add("ticket",ticket);
		return params;
	}


}
定义完HTTP客户端,我们就需要去模拟登录,当然模拟登录必须要设置CookieStore如下所示:

   /**
     * 初始化Cookie
     */
    private void initCookie(Context context) {
        //必须在请求前初始化
        cookie = new PersistentCookieStore(context);
        HttpUtil.getClient().setCookieStore(cookie);
        httpClient.setCookieStore(cookie);
    }
然后在请求登录页面时候就可以将返回的cookie设置给HTTPClient了。

难到这样就可以了?那那个lt值怎么获取传递过去昵?先贴一段获取lt的代码后面做解释:

/**
     * 获取lt
     */
    private void getlt(){
        Document doc = null;
            doc = Jsoup.parse(GetShouye());
            if (doc != null)
        if (doc != null) {
            Elements login = doc.body().getElementsByClass("login_form");
            Document containerDoc = Jsoup.parse(login.toString());
            Elements ddd = containerDoc.getElementsByTag("input");
            for (Element aaa : ddd) {
                if (aaa.toString().contains("lt")) {
                    String l = aaa.toString();
                    String lt = l.substring(38, l.length() - 4);
                    HttpUtil.lt = lt;
                }
            }
        }
    }

 /**
     * 请求首页
     * @return
     */
    public String GetShouye()
    {
        String result= "";

//    	创建HttpGet或HttpPost对象,将要请求的URL通过构造方法传入HttpGet或HttpPost对象。
        if (urlll == null){
            urlll = HttpUtil.URL_MAIN;
        }
        HttpGet httpRequst = new HttpGet(urlll);

//    	new DefaultHttpClient().execute(HttpUriRequst requst);
        try {
            //使用DefaultHttpClient类的execute方法发送HTTP GET请求,并返回HttpResponse对象。
            HttpResponse httpResponse = httpClient.execute(httpRequst);//其中HttpGet是HttpUriRequst的子类
            if (httpResponse.getStatusLine().getStatusCode() == 200) {
                HttpEntity httpEntity = httpResponse.getEntity();
                result = EntityUtils.toString(httpEntity);//取出应答字符串
                // 一般来说都要删除多余的字符
                result.replaceAll("\r", "");//去掉返回结果中的"\r"字符,否则会在结果字符串后面显示一个小方格
            } else{
                httpRequst.abort();
            }
        }catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            result = e.getMessage().toString();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            result = e.getMessage().toString();
        }
        return result;
    }
所有准备工作做好我们就可以发送登录请求了

 /**
     * 登录
     */
    private void login() {
        HttpUtil.username = username.getText().toString().trim();
        String md5 = "@";
        try {
            md5= MD5Until.GetMD5Code(password.getText().toString().trim());
        } catch (Exception e) {
            e.printStackTrace();
        }
        Log.d("md5  ",md5);
        HttpUtil.password = md5;
        //需要时打开验证码注释
        HttpUtil.captcha = secrectCode.getText().toString().trim();
        Log.d("cookie",HttpUtil.Cookie);
        if (TextUtils.isEmpty(HttpUtil.username)
                || TextUtils.isEmpty(HttpUtil.password)) {
            Toast.makeText(getApplicationContext(), "账号或者密码不能为空!",
                    Toast.LENGTH_SHORT).show();
            return;
        }
        final ProgressDialog dialog =CommonUtil.getProcessDialog(BindActivity.this,"正在登录中!!!");
        dialog.show();
        RequestParams params = HttpUtil.getLoginRequestParams();// 获得请求参数
        Log.d("http",params.toString());
        HttpUtil.getClient().setURLEncodingEnabled(true);
        HttpUtil.post(HttpUtil.URL_LOGIN, params,
                new AsyncHttpResponseHandler() {

                    @Override
                    public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
                        try {
                            String resultContent = new String(arg2, "gb2312");
                            Log.d("Header",arg1.toString());
                            Log.d("resunt",resultContent);
//							List<String> list = Getlt.match(resultContent,"input","name=\"lt\" ");
//							Log.d("list",list.toString());
                            if(linkService.isLogin(resultContent)!=null){
                                String ret = linkService.parseMenu(resultContent);
                                Log.d("cas", "login success:"+ret);
                                GetHerfUrl(resultContent);
                                Toast.makeText(getApplicationContext(),
                                        "登录成功!!!", Toast.LENGTH_SHORT).show();
                                new Thread(new Runnable() {
                                    @Override
                                    public void run() {
                                        String s = GetShouye();
                                        Log.d("sdfsdaf",s);
                                        String ss = Getksap();
                                        Log.d("qqqqqq",ss);
                                        jump2Main();
                                    }
                                }).start();

                            }else{
                                getCode();
                                Toast.makeText(getApplicationContext(),"账号或者密码错误!!!", Toast.LENGTH_SHORT).show();
                            }

                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        } finally {
                            dialog.dismiss();
                        }

                    }
                    @Override
                    public void onFailure(int arg0, Header[] arg1, byte[] arg2,
                                          Throwable arg3) {
                        Toast.makeText(getApplicationContext(), "登录失败!!!!",
                                Toast.LENGTH_SHORT).show();
                        dialog.dismiss();
                    }
                });
    }
登录成功后会返回一个链接,并不是登录后的教务首页,我们还需要解析提取链接并用GET请求去请求,即可!下面我们就来说一下关于HTML网页数据的解析。

JSOUP对HTML网页数据的解析

       JSOUP是一个非常好用的,用JAVA来抓取网页数据的开源框架。使用起来也非常简单,就是根据HTML内容,先获取BODY====》》》提取字段对应的class====》》》对应的标签ID。我们还是以lt为例来看:

    /**
     * 获取lt
     */
    private void getlt(){
        Document doc = null;
            doc = Jsoup.parse(GetShouye());
            if (doc != null)
        if (doc != null) {
            //获取解析后的body及对应的class——login_form
            Elements login = doc.body().getElementsByClass("login_form");
            Document containerDoc = Jsoup.parse(login.toString());
            //获取到标签id对应的数据
            Elements ddd = containerDoc.getElementsByTag("input");
            for (Element aaa : ddd) {
                //从这些数据中提取出lt
                if (aaa.toString().contains("lt")) {
                    String l = aaa.toString();
                    String lt = l.substring(38, l.length() - 4);
                    HttpUtil.lt = lt;
                }
            }
        }
    }
后面所有的数据获取都是这样,不过后面都是解析table而已。下面觉得重点应该说一下对课程信息的存储。

课程表信息的存储与读取

      课程表信息的存储也是非常麻烦的一件事,当时没想明白,存储完之后发现读到的数据全乱了。

{\"Course_address\":\"第12教研楼405\",\"Course_name\":\"网站规划与设计\",
        \"Course_teacher\":\"李君君\",\"Course_type\":\"必修\",\"Course_week\":\"周一第3,4节{第1-16周}\"},
上面是用JSON数组来存储每节课信息的存储结构,绘制课程表时,根据课表中的字段。如下所示:

public class CourseActivity extends Activity {
    private ArrayList<CourseBean> mCourse;
    private SharedPreferences mShaerPreferences;
    // 每天有多少节课
    private int mMaxCouese;
    // 一共有多少周
    private int mMaxWeek;
    // 现在是第几周
    private int mNowWeek;
    // 左边一节课的高度
    private float mLeftHeight;
    // 左边一节课的宽度
    private float mLeftWidth;

    private TextView mChangeWeek;
    private LinearLayout mLeftNo;
    private LinearLayout mMonday;
    private LinearLayout mTuesday;
    private LinearLayout mWednesday;
    private LinearLayout mThursday;
    private LinearLayout mFirday;
    private LinearLayout mSaturday;
    private LinearLayout mWeekend;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_course);
        // 实例化所有对象
        initCtrl();
        // 初始化数据
        initData();

        // 绘制左边的课程节数
        drawLeftNo();
        // 绘制当前周
        drawNowWeek();
        // 绘制所有课程 其实可以使用redrawAll替代三步
        drawAllCourse();
    }

    /**
     * 实例化所有对象
     */
    private void initCtrl() {
        mChangeWeek = (TextView) findViewById(R.id.changeWeek);
        mLeftNo = (LinearLayout) findViewById(R.id.leftNo);
        mMonday = (LinearLayout) findViewById(R.id.monday);
        mTuesday = (LinearLayout) findViewById(R.id.tuesday);
        mWednesday = (LinearLayout) findViewById(R.id.wednesday);
        mThursday = (LinearLayout) findViewById(R.id.thursday);
        mFirday = (LinearLayout) findViewById(R.id.firday);
        mSaturday = (LinearLayout) findViewById(R.id.saturday);
        mWeekend = (LinearLayout) findViewById(R.id.weekend);
    }

    /**
     * 初始化所有数据
     */
    private void initData() {
        // 初始化课表
        praseJson();
        // 读取配置信息
        readIniFile();

        // 点击选择切换周
        mChangeWeek.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                showChangeWeekDlg(v);
            }
        });
    }

    /**
     * 绘制左边的课程节数
     */
    private void drawLeftNo() {
        mLeftHeight = getResources().getDimension(R.dimen.left_height);
        mLeftWidth = getResources().getDimension(R.dimen.left_width);
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                (int) mLeftWidth, (int) mLeftHeight);
        for (int i = 1; i <= mMaxCouese; i++) {
            TextView tv = new TextView(this);
            tv.setText(i + "");
            tv.setGravity(Gravity.CENTER);
            tv.setTextColor(getResources().getColor(R.color.font));
            tv.setBackgroundResource(R.drawable.boder);
            mLeftNo.addView(tv, lp);
        }
    }

    /**
     * 绘制课表
     *
     * @param ll
     *            绘制课表到哪一个LinearLayout上
     * @param dayOfWeek
     *            绘制的数据来自周几 一二三四五六七
     */
    private void drawCourse(LinearLayout ll, char dayOfWeek) {
        // 删除所有子View
        ll.removeAllViews();
        // 上一节课结束是第几节
        int perCourse = -1;
        for (CourseBean course : mCourse) {
            // 判断是否显示这节课
            // 是不是同一天 是不是这一周
            if (course.getDayOfWeek() != dayOfWeek
                    || !course.inThisWeek(mNowWeek))
                continue;

            // 设置TextView的属性样式
            TextView tv = new TextView(this);
            tv.setText(course.getCourse_name() + "\n@"
                    + course.getCourse_address());
            tv.setBackgroundResource(R.drawable.course);
            tv.setTextColor(getResources().getColor(R.color.course_font_color));
            tv.setTextSize(12);
            // 将数据绑定到TextView上
            tv.setTag(course);
            tv.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    CourseBean tag = (CourseBean) v.getTag();
                    showCouseDetails(tag);
                }
            });

            // 设置TextView的位置
            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                    LayoutParams.MATCH_PARENT,
                    (int) (course.getStep() * mLeftHeight));
            // 说明这节课为第一节课
            if (perCourse == -1) {
                lp.setMargins(1,
                        (int) ((course.getMinCourse() - 1) * mLeftHeight), 1, 0);
                // useHeight = (int) ((course.getMaxCourse()-1) * mLeftHeight);
            } else {
                lp.setMargins(1, (course.getMinCourse() - perCourse - 1)
                        * (int) mLeftHeight, 1, 0);
                // useHeight = useHeight + (course.getMaxCourse() - perCourse -
                // 1)* (int) mLeftHeight;
            }
            perCourse = course.getMaxCourse();
            ll.addView(tv, lp);
        }
    }

    /**
     * 绘制当前周
     */
    private void drawNowWeek() {
        mChangeWeek.setText("第" + mNowWeek + "周");
    }

    /**
     * 重新绘制所有,不包括标题栏和星期几 在修改每天的节数后调用
     */
	/*private void redrawAll() {
		drawLeftNo();
		drawNowWeek();
		drawAllCourse();
	}*/

    /**
     * 绘制课程,用于周数切换以后
     */
    private void drawAllCourse() {
        drawCourse(mMonday, '一');
        drawCourse(mTuesday, '二');
        drawCourse(mWednesday, '三');
        drawCourse(mThursday, '四');
        drawCourse(mFirday, '五');
        drawCourse(mSaturday, '六');
        drawCourse(mWeekend, '日');
    }

    /**
     * 读取配置信息
     */
    private void readIniFile() {
        mShaerPreferences = getSharedPreferences("iniFile",
                Context.MODE_PRIVATE);
        mMaxCouese = mShaerPreferences.getInt("mMaxCouese", -1);
        mMaxWeek = mShaerPreferences.getInt("mMaxWeek", -1);
        mNowWeek = mShaerPreferences.getInt("mNowWeek", -1);

        Editor edit = mShaerPreferences.edit();
        // 默认12节课
        if (mMaxCouese == -1) {
            edit.putInt("mMaxCouese", 12);
        }

        // 默认20周
        if (mMaxWeek == -1) {
            edit.putInt("mMaxWeek", 17);
        }

        // 默认第一周
        if (mNowWeek == -1) {
            edit.putInt("mNowWeek", 15);
        }
        edit.commit();
    }

    /**
     * 解析来自strings.xml里面的Json课表数据
     */
    private void praseJson() {
        String json = getResources().getString(R.string.kb);
        Gson gson = new Gson();
        mCourse = gson.fromJson(json, new TypeToken<ArrayList<CourseBean>>() {
        }.getType());
    }

    /**
     * 弹出窗口,显示课程详细信息
     *
     */
    public void showCouseDetails(CourseBean bean) {
        AlertDialog.Builder builder = new Builder(this);
        AlertDialog dialog = builder.create();
        dialog.show();
        dialog.setContentView(R.layout.details_layout);
        TextView textView = (TextView) dialog.findViewById(R.id.name);
        textView.setText(bean.getCourse_name());
        textView = (TextView) dialog.findViewById(R.id.type);
        textView.setVisibility(View.GONE);
        textView.setText(bean.getCourse_type());
        textView = (TextView) dialog.findViewById(R.id.teacher);
        textView.setText(bean.getCourse_teacher());
        textView = (TextView) dialog.findViewById(R.id.address);
        textView.setText(bean.getCourse_address());
        textView = (TextView) dialog.findViewById(R.id.week);
        textView.setText(bean.getCourse_week());
    }

    /**
     * 显示切换当前周的窗口
     */
    public void showChangeWeekDlg(View v) {
        View view = View.inflate(this, R.layout.changweek_layout, null);
        ListView weekList = (ListView) view.findViewById(R.id.weekList);

        ArrayList<String> strList = new ArrayList<String>();
        for (int i = 1; i < mMaxWeek; i++) {
            strList.add("第" + i + "周");
        }

        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                R.layout.item, strList);

        weekList.setAdapter(adapter);
        view.measure(0, 0);
        final PopupWindow pop = new PopupWindow(view, 300, 500, true);
        pop.setBackgroundDrawable(new ColorDrawable(0x00000000));
        int xOffSet = -(pop.getWidth() - v.getWidth()) / 2;
        pop.showAsDropDown(v, xOffSet, 0);

        weekList.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> adapter, View view,
                                    int positon, long id) {
                mNowWeek = positon + 1;
                pop.dismiss();
                drawNowWeek();
                drawAllCourse();
            }
        });
    }

}
项目地址:https://github.com/Terrybthvi/HduStudyHelper







相关文章
|
1月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
166 4
|
1月前
|
Java 开发工具 Android开发
Android与iOS开发环境搭建全解析####
本文深入探讨了Android与iOS两大移动操作系统的开发环境搭建流程,旨在为初学者及有一定基础的开发者提供详尽指南。我们将从开发工具的选择、环境配置到第一个简单应用的创建,一步步引导读者步入移动应用开发的殿堂。无论你是Android Studio的新手还是Xcode的探索者,本文都将为你扫清开发道路上的障碍,助你快速上手并享受跨平台移动开发的乐趣。 ####
|
1月前
|
消息中间件 存储 缓存
十万订单每秒热点数据架构优化实践深度解析
【11月更文挑战第20天】随着互联网技术的飞速发展,电子商务平台在高峰时段需要处理海量订单,这对系统的性能、稳定性和扩展性提出了极高的要求。尤其是在“双十一”、“618”等大型促销活动中,每秒需要处理数万甚至数十万笔订单,这对系统的热点数据处理能力构成了严峻挑战。本文将深入探讨如何优化架构以应对每秒十万订单级别的热点数据处理,从历史背景、功能点、业务场景、底层原理以及使用Java模拟示例等多个维度进行剖析。
55 8
|
1月前
|
数据采集 自然语言处理 搜索推荐
基于qwen2.5的长文本解析、数据预测与趋势分析、代码生成能力赋能esg报告分析
Qwen2.5是一款强大的生成式预训练语言模型,擅长自然语言理解和生成,支持长文本解析、数据预测、代码生成等复杂任务。Qwen-Long作为其变体,专为长上下文场景优化,适用于大型文档处理、知识图谱构建等。Qwen2.5在ESG报告解析、多Agent协作、数学模型生成等方面表现出色,提供灵活且高效的解决方案。
166 49
|
25天前
|
存储 Linux API
深入探索Android系统架构:从内核到应用层的全面解析
本文旨在为读者提供一份详尽的Android系统架构分析,从底层的Linux内核到顶层的应用程序框架。我们将探讨Android系统的模块化设计、各层之间的交互机制以及它们如何共同协作以支持丰富多样的应用生态。通过本篇文章,开发者和爱好者可以更深入理解Android平台的工作原理,从而优化开发流程和提升应用性能。
|
21天前
|
安全 前端开发 Android开发
探索移动应用与系统:从开发到操作系统的深度解析
在数字化时代的浪潮中,移动应用和操作系统成为了我们日常生活的重要组成部分。本文将深入探讨移动应用的开发流程、关键技术和最佳实践,同时分析移动操作系统的核心功能、架构和安全性。通过实际案例和代码示例,我们将揭示如何构建高效、安全且用户友好的移动应用,并理解不同操作系统之间的差异及其对应用开发的影响。无论你是开发者还是对移动技术感兴趣的读者,这篇文章都将为你提供宝贵的见解和知识。
|
25天前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
25天前
|
XML JSON JavaScript
HttpGet 请求的响应处理:获取和解析数据
HttpGet 请求的响应处理:获取和解析数据
|
26天前
|
负载均衡 网络协议 算法
Docker容器环境中服务发现与负载均衡的技术与方法,涵盖环境变量、DNS、集中式服务发现系统等方式
本文探讨了Docker容器环境中服务发现与负载均衡的技术与方法,涵盖环境变量、DNS、集中式服务发现系统等方式,以及软件负载均衡器、云服务负载均衡、容器编排工具等实现手段,强调两者结合的重要性及面临挑战的应对措施。
63 3
|
4天前
|
安全 搜索推荐 数据挖掘
陪玩系统源码开发流程解析,成品陪玩系统源码的优点
我们自主开发的多客陪玩系统源码,整合了市面上主流陪玩APP功能,支持二次开发。该系统适用于线上游戏陪玩、语音视频聊天、心理咨询等场景,提供用户注册管理、陪玩者资料库、预约匹配、实时通讯、支付结算、安全隐私保护、客户服务及数据分析等功能,打造综合性社交平台。随着互联网技术发展,陪玩系统正成为游戏爱好者的新宠,改变游戏体验并带来新的商业模式。

热门文章

最新文章

推荐镜像

更多