Android_聊天_表情

接下来就进入聊天界面了,我的界面效果如下几个图所示:

这里写图片描述
这里写图片描述
这里写图片描述
这其中包括两个点:仿微信按住说话功能,表情管理
第一个,按住说话 按钮的功能,通过重写Button完成,
/**
* 控制录音Button
* 1、重写onTouchEvent;(changeState方法、wantToCancel方法、reset方法);
* 2、编写AudioDialogManage、并与该类AudioRecorderButton进行整合;
* 3、编写AudioManage、并与该类AudioRecorderButton进行整合;
*/

package com.ppl.myvoice.save;

import android.content.Context;
import android.os.Environment;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;

import com.ppl.get_loc.R;
import com.ppl.myvoice.save.AudioManage.AudioStateListenter;
/**
 * 控制录音Button
 * 1、重写onTouchEvent;(changeState方法、wantToCancel方法、reset方法);
 * 2、编写AudioDialogManage、并与该类AudioRecorderButton进行整合;
 * 3、编写AudioManage、并与该类AudioRecorderButton进行整合;
 */
public class AudioRecordrButton extends Button implements AudioStateListenter{
    /**
     * AudioRecorderButton的三个状态
     */
    private static final int STATE_NORMAL = 1;           //默认状态
    private static final int STATE_RECORDERING = 2;      //录音状态
    private static final int STATE_WANT_TO_CALCEL = 3;   //取消状态

    private int mCurState = STATE_NORMAL;    // 当前录音状态
    private boolean isRecordering = false;   // 是否已经开始录音
    private boolean mReady;    // 是否触发onLongClick

    private static final int DISTANCE_Y_CANCEL = 50;

    private AudioDialogManage audioDialogManage;

    private AudioManage mAudioManage;

    /**
     * 正常录音完成后的回调
     * @author songshi
     *
     */
    public interface AudioFinishRecorderListenter{
        void onFinish(float seconds, String FilePath);
    }

    private AudioFinishRecorderListenter mListenter;

    public void setAudioFinishRecorderListenter(AudioFinishRecorderListenter listenter){
        this.mListenter=listenter;
    }
    //构造方法
    public AudioRecordrButton(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }
    public AudioRecordrButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        audioDialogManage = new AudioDialogManage(getContext());

        String dir = Environment.getExternalStorageDirectory()
                + "/VoiceRecorder";                             // 此处需要判断是否有存储卡(外存)
        mAudioManage = AudioManage.getInstance(dir);
        mAudioManage.setOnAudioStateListenter(this);

        setOnLongClickListener(new OnLongClickListener() {

            @Override
            public boolean onLongClick(View v) {
                mReady = true;
                // 真正显示应该在audio end prepared以后
                mAudioManage.prepareAudio();
                //return true;
                return false;
            }
        });
    }
    /* 
     * 复写onTouchEvent
     * @see android.widget.TextView#onTouchEvent(android.view.MotionEvent)
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        int action = event.getAction();   //获取当前Action

        int x = (int) event.getX();       //获取当前的坐标
        int y = (int) event.getY();

        switch (action) {

        case MotionEvent.ACTION_DOWN:
            changeState(STATE_RECORDERING);
            break;

        case MotionEvent.ACTION_MOVE:

            // 已经开始录音状态时,根据X、Y的坐标,判断是否想要取消
            if (isRecordering) {
                if (wantToCancel(x, y)) {
                    changeState(STATE_WANT_TO_CALCEL);
                } else {
                    changeState(STATE_RECORDERING);
                }
            }
            break;

        case MotionEvent.ACTION_UP:
            if (!mReady) {   //没有触发onLongClick
                reset();
                return super.onTouchEvent(event);
            }

            if (!isRecordering || mTime < 0.7f) {  //录音时间过短
                audioDialogManage.tooShort();
                mAudioManage.cancel();
                mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS, 1300);// 延迟,1.3秒以后关闭“时间过短对话框”
            } 

            else if (mCurState == STATE_RECORDERING) { //正常录制结束
                audioDialogManage.dimissDialog();
                // release
                mAudioManage.release();
                // callbackToAct
                // 正常录制结束,回调录音时间和录音文件完整路径——在播放的时候需要使用
                if(mListenter!=null){
                    mListenter.onFinish(mTime, mAudioManage.getCurrentFilePath());
                }               

            } else if (mCurState == STATE_WANT_TO_CALCEL) {
                // cancel
                audioDialogManage.dimissDialog();
                mAudioManage.cancel();
            }

            reset();
            break;
        }
        return super.onTouchEvent(event);
    }

    /**
     * 恢复状态以及一些标志位
     */
    private void reset() {
        isRecordering = false;
        mReady = false;                 //是否触发onLongClick
        mTime = 0;
        changeState(STATE_NORMAL);
    }

    private boolean wantToCancel(int x, int y) {
        // 判断手指的滑动是否超出范围
        if (x < 0 || x > getWidth()) {
            return true;
        }
        if (y < -DISTANCE_Y_CANCEL || y > getHeight() + DISTANCE_Y_CANCEL) {
            return true;
        }
        return false;
    }

    /**
     * 改变Button的背景和文本、展示不同状态的录音提示对话框
     * @param state
     */
    private void changeState(int state) {
        if (mCurState != state) {
            mCurState = state;
            switch (state) {
            case STATE_NORMAL:
                setBackgroundResource(R.drawable.btn_recorder_normal);
                setText(R.string.str_recorder_normal);
                break;

            case STATE_RECORDERING:
                setBackgroundResource(R.drawable.btn_recorder_recordering);
                setText(R.string.str_recorder_recording);
                if (isRecordering) {
                    // 更新Dialog.recording()
                    audioDialogManage.recording();
                }
                break;

            case STATE_WANT_TO_CALCEL:
                setBackgroundResource(R.drawable.btn_recorder_recordering);
                setText(R.string.str_recorder_want_cancel);
                // 更新Dialog.wantCancel()
                audioDialogManage.wantToCancel();
                break;
            }
        }
    }

    /* 
     * 实现“准备完毕”接口
     * (non-Javadoc)
     * @see songshi.voicenotes.recorder.AudioManage.AudioStateListenter#wellPrepared()
     */
    @Override
    public void wellPrepared() {
        // TODO Auto-generated method stub
        mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);
    }

    private static final int MSG_AUDIO_PREPARED = 0x110;   //准备完全
    private static final int MSG_VOICE_CHANGE = 0x111;     //声音改变
    private static final int MSG_DIALOG_DIMISS = 0x112;    //销毁对话框

    /**
     * 接收子线程数据,并用此数据配合主线程更新UI
     * Handler运行在主线程(UI线程)中,它与子线程通过Message对象传递数据。
     * Handler接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,把这些消息放入主线程队列中,配合主线程进行更新UI。
     */
    private Handler mHandler = new Handler() {

        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case MSG_AUDIO_PREPARED:        //216:mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);
                audioDialogManage.showRecorderingDialog();
                isRecordering = true;
                //已经在录制,同时开启一个获取音量、并且计时的线程
                new Thread(mGetVoiceLevelRunnable).start();
                break;

            case MSG_VOICE_CHANGE:          //265:mHandler.sendEmptyMessage(MSG_VOICE_CHANGE);
                audioDialogManage.updateVoiceLevel(mAudioManage
                        .getVoiceLevel(7));
                break;

                //这里在Handler里面处理DIALOG_DIMISS,是因为想让该对话框显示一段时间,延迟关闭,——详见125行
            case MSG_DIALOG_DIMISS:         //125:mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS, 1300);
                audioDialogManage.dimissDialog();
                break;
            }
        };
    };

    private float mTime;  //开始录音时,计时;(在reset()中置空)
    /**
     * 获取音量大小的Runnable
     */
    private Runnable mGetVoiceLevelRunnable = new Runnable() {

        @Override
        public void run() {

            while (isRecordering) {

                try {
                    Thread.sleep(100);
                    mTime += 0.1f;
                    mHandler.sendEmptyMessage(MSG_VOICE_CHANGE);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }
        }
    };
}

上面即可完成 按住说话 的功能。

下面介绍表情的显示;效果如下图:
这里写图片描述
表情包括可选表情和表情导航,
方法 GridView+ViewPager
XML代码如下:

<android.support.v4.view.ViewPager
                android:id="@+id/vp_emjo"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:layout_marginBottom="5dip"
                android:gravity="center_horizontal"
                android:orientation="horizontal"
                android:padding="2dip" >

                <ImageView
                    android:id="@+id/iv_e1"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@drawable/login_point" />

                <ImageView
                    android:id="@+id/iv_e2"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@drawable/login_point" />

                <ImageView
                    android:id="@+id/iv_e3"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@drawable/login_point" />

                <ImageView
                    android:id="@+id/iv_e4"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@drawable/login_point" />

                <ImageView
                    android:id="@+id/iv_e5"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@drawable/login_point" />

                <ImageView
                    android:id="@+id/iv_e6"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@drawable/login_point" />
            </LinearLayout>

接下来 介绍 表情的显示,如何让表情在输入框 与 聊天对话框中显示,先介绍两个Java的小知识点,我本身是做C和VC++的,因为要做Android才知道一点点Java的,闲话少叙上干货,Pattern 与 Matcher
这俩是Java的正则表达式 功能是用正则表达式所定制的模式来对字符串进行匹配工作。
下面是表情显示的代码:

package com.ppl.get_loc.chat.emos;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.ImageSpan;

public class FaceTextUtils {
    public static List<FaceText> faceTexts = new ArrayList<FaceText>();

    static {
        faceTexts.add(new FaceText("\\face_0"));
        faceTexts.add(new FaceText("\\face_1"));
        faceTexts.add(new FaceText("\\face_2"));
        faceTexts.add(new FaceText("\\face_3"));
        faceTexts.add(new FaceText("\\face_4"));
        faceTexts.add(new FaceText("\\face_5"));
        faceTexts.add(new FaceText("\\face_6"));
        faceTexts.add(new FaceText("\\face_7"));
        faceTexts.add(new FaceText("\\face_8"));
        faceTexts.add(new FaceText("\\face_9"));
        faceTexts.add(new FaceText("\\face_10"));
        faceTexts.add(new FaceText("\\face_11"));
        faceTexts.add(new FaceText("\\face_12"));
        faceTexts.add(new FaceText("\\face_13"));
        faceTexts.add(new FaceText("\\face_14"));
        faceTexts.add(new FaceText("\\face_15"));
        faceTexts.add(new FaceText("\\face_16"));
        faceTexts.add(new FaceText("\\face_17"));
        faceTexts.add(new FaceText("\\face_18"));
        faceTexts.add(new FaceText("\\face_19"));
        faceTexts.add(new FaceText("\\face_20"));
        faceTexts.add(new FaceText("\\face_21"));
        faceTexts.add(new FaceText("\\face_22"));
        faceTexts.add(new FaceText("\\face_23"));
        faceTexts.add(new FaceText("\\face_24"));
        faceTexts.add(new FaceText("\\face_25"));
        faceTexts.add(new FaceText("\\face_26"));
        faceTexts.add(new FaceText("\\face_27"));
        faceTexts.add(new FaceText("\\face_28"));
        faceTexts.add(new FaceText("\\face_29"));
        faceTexts.add(new FaceText("\\face_30"));
        faceTexts.add(new FaceText("\\face_31"));
        faceTexts.add(new FaceText("\\face_32"));
        faceTexts.add(new FaceText("\\face_33"));
        faceTexts.add(new FaceText("\\face_34"));
        faceTexts.add(new FaceText("\\face_35"));
        faceTexts.add(new FaceText("\\face_36"));
        faceTexts.add(new FaceText("\\face_37"));
        faceTexts.add(new FaceText("\\face_38"));
        faceTexts.add(new FaceText("\\face_39"));
        faceTexts.add(new FaceText("\\face_40"));
        faceTexts.add(new FaceText("\\face_41"));
        faceTexts.add(new FaceText("\\face_42"));
        faceTexts.add(new FaceText("\\face_43"));
        faceTexts.add(new FaceText("\\face_44"));
        faceTexts.add(new FaceText("\\face_45"));
        faceTexts.add(new FaceText("\\face_46"));
        faceTexts.add(new FaceText("\\face_47"));
        faceTexts.add(new FaceText("\\face_48"));
        faceTexts.add(new FaceText("\\face_49"));
        faceTexts.add(new FaceText("\\face_50"));
        faceTexts.add(new FaceText("\\face_51"));
        faceTexts.add(new FaceText("\\face_52"));
        faceTexts.add(new FaceText("\\face_53"));
        faceTexts.add(new FaceText("\\face_54"));
        faceTexts.add(new FaceText("\\face_55"));
        faceTexts.add(new FaceText("\\face_56"));
        faceTexts.add(new FaceText("\\face_57"));
        faceTexts.add(new FaceText("\\face_58"));
        faceTexts.add(new FaceText("\\face_59"));
        faceTexts.add(new FaceText("\\face_60"));
        faceTexts.add(new FaceText("\\face_61"));
        faceTexts.add(new FaceText("\\face_62"));
        faceTexts.add(new FaceText("\\face_63"));
        faceTexts.add(new FaceText("\\face_64"));
        faceTexts.add(new FaceText("\\face_65"));
        faceTexts.add(new FaceText("\\face_66"));
        faceTexts.add(new FaceText("\\face_67"));
        faceTexts.add(new FaceText("\\face_68"));
        faceTexts.add(new FaceText("\\face_69"));
        faceTexts.add(new FaceText("\\face_70"));
        faceTexts.add(new FaceText("\\face_71"));
        faceTexts.add(new FaceText("\\face_72"));
        faceTexts.add(new FaceText("\\face_73"));
        faceTexts.add(new FaceText("\\face_74"));
        faceTexts.add(new FaceText("\\face_75"));
        faceTexts.add(new FaceText("\\face_76"));
        faceTexts.add(new FaceText("\\face_77"));
        faceTexts.add(new FaceText("\\face_78"));
        faceTexts.add(new FaceText("\\face_79"));
        faceTexts.add(new FaceText("\\face_80"));
        faceTexts.add(new FaceText("\\face_81"));
        faceTexts.add(new FaceText("\\face_82"));
        faceTexts.add(new FaceText("\\face_83"));
        faceTexts.add(new FaceText("\\face_84"));
        faceTexts.add(new FaceText("\\face_85"));
        faceTexts.add(new FaceText("\\face_86"));
        faceTexts.add(new FaceText("\\face_87"));
        faceTexts.add(new FaceText("\\face_88"));
        faceTexts.add(new FaceText("\\face_89"));
        faceTexts.add(new FaceText("\\face_90"));
        faceTexts.add(new FaceText("\\face_91"));
        faceTexts.add(new FaceText("\\face_92"));
        faceTexts.add(new FaceText("\\face_93"));
        faceTexts.add(new FaceText("\\face_94"));
        faceTexts.add(new FaceText("\\face_95"));
        faceTexts.add(new FaceText("\\face_96"));
        faceTexts.add(new FaceText("\\face_97"));
        faceTexts.add(new FaceText("\\face_98"));
        faceTexts.add(new FaceText("\\face_99"));
        faceTexts.add(new FaceText("\\face_100"));
        faceTexts.add(new FaceText("\\face_101"));
        faceTexts.add(new FaceText("\\face_102"));
        faceTexts.add(new FaceText("\\face_103"));
        faceTexts.add(new FaceText("\\face_104"));
        faceTexts.add(new FaceText("\\face_105"));
        faceTexts.add(new FaceText("\\face_106"));
        faceTexts.add(new FaceText("\\face_107"));
        faceTexts.add(new FaceText("\\face_108"));
        faceTexts.add(new FaceText("\\face_109"));
        faceTexts.add(new FaceText("\\face_110"));
        faceTexts.add(new FaceText("\\emotion_del_normal"));
        faceTexts.add(new FaceText("\\emotion_del_down"));
    }

    public static String parse(String s) {
        for (FaceText faceText : faceTexts) {
            s = s.replace("\\" + faceText.text, faceText.text);
            s = s.replace(faceText.text, "\\" + faceText.text);
        }
        return s;
    }

    /** 
      * toSpannableString
      * @return SpannableString
      * @throws
      */
    public static SpannableString toSpannableString(Context context, String text) {
        if (!TextUtils.isEmpty(text)) {
            SpannableString spannableString = new SpannableString(text);
            int start = 0;
            Pattern pattern = Pattern.compile("\\\\face_[0-9]{1,3}", Pattern.CASE_INSENSITIVE);
            Matcher matcher = pattern.matcher(text);
            while (matcher.find()) {
                String faceText = matcher.group();
                String key = faceText.substring(1);
                BitmapFactory.Options options = new BitmapFactory.Options();
                Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),
                        context.getResources().getIdentifier(key, "drawable", context.getPackageName()), options);
                ImageSpan imageSpan = new ImageSpan(context, bitmap);
                int startIndex = text.indexOf(faceText, start);
                int endIndex = startIndex + faceText.length();
                if (startIndex >= 0)
                    spannableString.setSpan(imageSpan, startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                start = (endIndex - 1);
            }

            return spannableString;
        } else {
            return new SpannableString("");
        }
    }

    public static SpannableString toSpannableString(Context context, String text, SpannableString spannableString) {

        int start = 0;
        Pattern pattern = Pattern.compile("\\\\ue[a-z0-9]{3}", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(text);
        while (matcher.find()) {
            String faceText = matcher.group();
            String key = faceText.substring(1);
            BitmapFactory.Options options = new BitmapFactory.Options();
//          options.inSampleSize = 2;
            Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), context.getResources()
                    .getIdentifier(key, "drawable", context.getPackageName()), options);
            ImageSpan imageSpan = new ImageSpan(context, bitmap);
            int startIndex = text.indexOf(faceText, start);
            int endIndex = startIndex + faceText.length();
            if (startIndex >= 0)
                spannableString.setSpan(imageSpan, startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            start = (endIndex - 1);
        }

        return spannableString;
    }
}

向聊天框里输入表情的代码如下:

EmoteAdapter emoAdapter = (EmoteAdapter) itemAdapter;
                if(position == emoAdapter.getCount() - 1){
                    //点击  删除 按钮
                    et_input.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL));
                }else{
                    //点击了表情,则添加到输入框中
                    sendText = et_input.getText().toString();
                    FaceText name = (FaceText) gridAdapter.getItem(position);
                    String key = name.text.toString();

                    int start = et_input.getSelectionStart();
                    SpannableString aps = FaceTextUtils.toSpannableString(getApplicationContext(), sendText + key);
                    et_input.setText(aps);
                    // 定位光标位置
                    CharSequence info = et_input.getText();
                    if (info instanceof Spannable) {
                        Spannable spanText = (Spannable) info;
                        Selection.setSelection(spanText,
                                start + key.length());
                    }
                }

在发送框里显示的代码如下:

SpannableString spS = FaceTextUtils.toSpannableString(mContext, item.getContent());
        viewHolder.tv_message.setText(spS);

最终效果如下图所示:
这里写图片描述

至此,完成 聊天中,表情添加与显示。

本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。

JAVA 面向对象 隐藏和封装 - 2016-07-23 17:07:20

本页面更新日期: 2016年07月22日 前言 在前面程序中,经常出现通过 某个对象直接访问其成员变量的情况. 这可能引起一些潜在问题,比如将某个 Person 的 age 成员变量直接设为 1000. 这在语法上没有任何问题, 但显然违背了当前的自然规律. 人怎么可能活到 1000岁 - - . (就现在的科学来讲) Java也考虑到了这种情况, 为你提供了 类和对象的成员变量 进行封装的方法,来保护成员变量不被恶意修改. 理解封装 封装(Encapsulation) 是面向对象的三大特征之一.(另外两
上一篇文章分析过DroidPlugin对Activity的处理过程,不得不为对DroidPlugin的工程师们钦佩不已,那么是不是Service可以像Activity的处理过程一样来处理呢?前面讲过每一个代理进程只是预定义了一个Service,如果某一个插件中有多个Service,那岂不是某一个时刻只能有一个Service运行呢?由此可以判定可能Service的处理和Activity不一样。 一方面:平时使用Activity主要是用于展示界面和用户交互,Activity的生命周期可能受用户控制,当用户操作

IntentService使用及源码分析 - 2016-07-23 14:07:58

IntentService使用及源码分析 转载请注明 原博客地址: http://blog.csdn.net/gdutxiaoxu/article/details/52000680 本篇博客主要简介一下三个问题: 什么是IntentService? 怎样使用IntentService IntentSerice()源码分析 1)什么是IntentService? 我们知道Service和Activity一样是Android的四大组件之一,Service简称为后台服务,具有较高的优先级别。我们平时在Activ

Android——ListView控件 - 2016-07-23 14:07:54

本篇介绍ListView控件,这是Android中比较重要也比较复杂的控件,这里只谈到使用ViewHolder机制优化即可。 一、ListView简介 ListView是Android系统中显示列表的控件,每个ListView都可以包含很多个列表项。 二、ListView的使用 概念不多说,直接来介绍使用方法。 ListView中比较复杂的是数据适配器,其作用是把复杂的数据(数组、链表、数据库、集合等)填充在指定视图界面,是连接数据源和视图界面的桥梁。常见的Android原生的适配器有ArrayAdapt
HTTP请求报文: 一个HTTP请求报文由四个部分组成:请求行、请求头部、空行、请求数据 1.请求行   请求行由请求 方法字段、URL字段和HTTP协议版本字段 3个字段组成,它们用空格分隔。比如 GET /data/info.html HTTP/1.1 方法字段就是HTTP使用的请求方法,比如常见的GET/POST 其中HTTP协议版本有两种:HTTP1.0/HTTP1.1 可以这样区别: HTTP1.0对于每个连接都的建立一次连接一次只能传送一个请求和响应,请求就会关闭,HTTP1.0没有Host字

gradle多渠道打包 - 2016-07-23 14:07:48

E文不好的童鞋,例如我,翻译文章的过程里没有愉悦的感受,只有2行老泪;但最终有一丝成就感也算是安慰了。所以我会去尊重那些翻译IT技术文章的大拿们,他们就是千千万万个亚里士多德和吴启明,他们是E文不好的童鞋的传教士,阿门,当然我不是大拿。 废话少说,先看一篇例子:在 http://ghui.me/post/2015/03/create-several-variants/  。 然后来看这篇翻译,扫清例子中一部分未知的知识。原文在 http://tools.android.com/tech-docs/new-b
前言 本文主要讲解Telephony中Phone相关的知识,主要想讲明白三件事情: Phone是什么? Phone从哪里来? Phone有什么作用? 1. Phone是什么 1.1 Phone是一个接口 Phone.java (frameworks\opt\telephony\src\java\com\android\internal\telephony) public interface Phone { //包含了大量的register/unregister的方法。(监听能力) void registe

Android混淆心得 - 2016-07-23 14:07:36

最近在做Android应用的混淆,踩了一些坑,这里记录分享下个人的心得。 混淆介绍 首先先简单说一下什么是混淆和混淆的作用,其实这个搜索下可以找到一堆官方的说法等等,这里简单口语叙述一下,混淆就是把代码替换成a、b、c基本字母组成的代码,比如一个方法名为:function(),混淆后可能会被替换成a()。 混淆的好处: 代码混淆后阅读性降低,反编译后破译程序难度提高 混淆后字节数减少,减少了应用了体积 前者只能说有一点作用,后者则需要看代码的数量 当然不能忽视混淆的缺点: 混淆后,测试不充分可能导致某些功
[编写高质量iOS代码的52个有效方法](二)对象 参考书籍:《Effective Objective-C 2.0》 【英】 Matt Galloway 先睹为快 6.理解“属性”这一概念 7.在对象内部尽量直接访问实例变量 8.理解“对象等同性”这一概念 9.以“类簇模式”隐藏实现细节 10.在既有类中使用关联对象存放自定义数据 目录 编写高质量iOS代码的52个有效方法二对象 先睹为快 目录 第6条理解属性这一概念 第7条在对象内部尽量直接访问实例变量 第8条理解对象等同性这一概念 第9条以类簇模式隐
插件其实是Apk安装包,如果要使用必须先要安装和解析,以便知道插件Apk的相关信息。而从Demo中我们知道插件的安装和卸载是通过调用PluginManager的installPackage()和deletePackage()来实现的。就先从PluginManager.installPackage()开始分析插件Apk的安装过程。 第一步:PluginManager. getInstance().installPackage(apkPath,flag); 此函数中只是调用了mPluginManager.in