Android-nslookup域名转换为ip总结

这一段时间在给项目新增一个NsLookup功能并且学习了一些东西,已经有两周没有写博客了,正好有时间来做个总结。先说一下这个功能:该功能是可以让用户输入一个域名然后显示它 的ip地址,并且在右上角菜单有可以查看历史记录的menu菜单,其中主要用到了一些知识例如网络请求,线程,以及dns等。

域名解析(功能主函数)

其中用到了该java类import org.xbill.DNS.*
nslookup有很多种查询种类如下
A 地址记录
AAAA 地址记录
AFSDB Andrew文件系统数据库服务器记录
ATMA ATM地址记录
CNAME 别名记录
HINFO 硬件配置记录,包括CPU、操作系统信息
ISDN 域名对应的ISDN号码
MB 存放指定邮箱的服务器
MG 邮件组记录
MINFO 邮件组和邮箱的信息记录
MR 改名的邮箱记录
MX 邮件服务器记录
NS 名字服务器记录
PTR 反向记录
RP 负责人记录
RT 路由穿透记录
SRV TCP服务器信息记录
TXT 域名对应的文本信息
X25 域名对应的X.25地址记录
种类非常的多,但是最常用的还是A类查询功能主函数如下

 public String showDnsIp(String s)
            throws UnknownHostException, TextParseException {
        String ip=null;
//            String address = InetAddress.getByName(s).getHostAddress();
//            System.out.println(address);

        //查询类型为A类查询
        Lookup mlookup = new Lookup(s, Type.A);
        mlookup.run();
        //查询失败则返回错误信息
        if (mlookup.getResult() != Lookup.SUCCESSFUL) {
            System.out.println("ERROR: " + mlookup.getErrorString());
            ip = "Error:" + mlookup.getErrorString();
            return ip;
        }
        //获取结果
        Record[] answers = mlookup.getAnswers();
        for (Record rec : answers) {
            System.out.println(rec.toString());
            ip = rec.toString();

        }
        return ip;
    }

AsyncTask的使用

Android中对网络的请求需要把功能函数放到线程中去实现,从而不会导致整个主线程受到影响,可以选择用Android封装的线程类AsyncTask。AsyncTask是Android中的一个抽象类,需要去继承它然后使用,该类可以设置三个泛型参数
当我们子类继承一个AsyncTask时,至少要重写一个方法那就是(doInBackground(Params…)需要在线程中完成的事情,同类型参数而且可以传入多个)。通常也会实现这个方法(onPostExecute(Result)将结果返回给主线程,参数可以是doInBackground的返回值)。
这是官方给出的源码

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }
一旦创建了任务需要在主线程中去调用
new DownloadFilesTask().execute(url1, url2, url3);

AsyncTask

最终在界面实现方式可以是这样
   class MyNsTask extends AsyncTask<String, Void, String> {

        @Override
        protected String doInBackground(String... strings) {
            try {
                address = showDnsIp(mEdiText.getText().toString());
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (TextParseException e) {
                e.printStackTrace();
            }
            return address;
        }

        @Override
        protected void onPostExecute(String address) {
            super.onPostExecute(address);
            mTextView.setText(address);
        }


        /**
         * 查询时等待界面(可添加loading..)
         */
//    @Override
//    protected void onPreExecute() {
            mTextView.setText("Wait while loading...");
//        super.onPreExecute();
//    }

}
调用函数并将结果显示在Textview中
   /**
         * 搜素按钮的点击事件
         * 点击时执行线程
         */
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mEdiText.getText().toString().trim().equals("") ) {
                    mTextView.setText("Please enter domain name");
                } else {
//调用线程1
                    MyNsTask nsTask=new MyNsTask();
                    Log.d("--------"+mEdiText.getText().toString());
                    nsTask.execute(mEdiText.getText().toString());

                }

            }
        });

界面

ns--page.png
这个界面很简单,可以自己设计。

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/nslookup_layout"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:layout_marginTop="20dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:id="@+id/edit_nslookup"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="Enter domain name"
            android:lines="1"
            android:singleLine="true"
            android:layout_width="match_parent" />
        <Button
            android:id="@+id/btn_ns_clear"
            android:background="@drawable/ic_btn_clear"
            android:layout_width="25dp"
            android:layout_height="25dp"
            android:visibility="gone"/>

    </LinearLayout>
    <LinearLayout

        android:layout_marginTop="10dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <Button
            android:layout_marginBottom="10dp"
            android:layout_gravity="center"
            android:gravity="center"
            android:id="@+id/btn_nslookup"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:text="lookup" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:gravity="center_vertical"
            android:text="Search result:"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/text_showip"
            android:layout_width="match_parent"
            android:layout_height="122dp"
            android:background="#5e2929"
            android:textIsSelectable="true"
            android:textSize="24sp" />


    </LinearLayout>

</LinearLayout>

设置可以查看搜索历史记录的menu

大致情况就是 查询时如果访问成功,则将域名用sharedpreferences存起来,利用一个符号比如逗号将每个域名连接起来拼成长字符串,之后在以逗号切割成一个个item放入dialog中。
实现的一个效果大概这样
ns--item1.png
点击右上角可以弹出菜单
ns--item2.png
点击按钮会弹出一个dialog显示搜索的记录(搜索失败,或者域名不对不会出现在历史记录)
nx--item3.png

活动中设置menu菜单

设置菜单比较简单就不多说了主要这三个方法

 /**
      *  创建菜单
      **/
    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.menu_nslookup_history,menu);
        super.onCreateOptionsMenu(menu, inflater);

    }

    @Override
    public void onPrepareOptionsMenu(Menu menu) {
        super.onPrepareOptionsMenu(menu);
    }

    /**
     * 设置菜单中的history按钮
     * @param item
     * @return
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        Log.i("NsLookupFragment onOptionsItemSelected");
        switch (item.getItemId()){
            case R.id.item_ns_history:
                //显示对话框
                showHistoryDialog();
                break;
                default:break;
        }
        return super.onOptionsItemSelected(item);
    }

设置item布局文件

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/item_ns_history"
        android:title="history"
        />
</menu>

点击菜单弹出对话框,点击clear可以清除历史记录

下面是dialog生成方式和实现history的方法放在了一起,主要用到的方法是setHistory()首先是生成dialog 的方法放在了上面onOptionsItemSelected(MenuItem item)的方法中
下面贴上代码

/**
     * 显示域名历史记录的dialog
     */
    public void showHistoryDialog(){
        mAllActivity=getActivity();
        AlertDialog.Builder mDialog=new AlertDialog.Builder(getActivity());
        /**
         * 设置列表内容(将从sp中取出的字符串以","分割成字符串数组)
         * 点击item时在输入框填入对应值
         * 点击clear时清空dialog
         */
        final String[] arrayOfString = this.getHistory().split(",");
        AlertDialog.Builder setItemsBuilder =
                mDialog.setItems(arrayOfString, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                setEditText(arrayOfString[which]);
            }
        });
        mDialog.setTitle("History").setPositiveButton
                ("Clear", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                setHistoryNull();
            }
        });
        mDialog.create();
        mDialog.show();
    }

保存历史到sharedpreferences中,因为要保存的数据也不会太多,所以没有使用数据库而是采用了轻量级的存储方案那就是sp,键值对,让数据对应history
首先是将搜到的域名以长字符串连接起来

private SharedPreferences mSharedPreferences;

 /**
     * 判断并将域名存入sp(以","为间隔将字符串拼接成长字符串)
     * @param domainName
     * @return
     */
    public void setHistory(String domainName) {
        SharedPreferences.Editor localEditor;
        String nsString = this.mSharedPreferences.getString("history", "");
        //判断字符串是否为空
        if (nsString==""){
            nsString = domainName;
            localEditor = this.mSharedPreferences.edit();
            localEditor.putString("history", nsString);
            localEditor.commit();
        }
        //判断字符串是否含有搜索过的的域名
        if (!nsString.contains(domainName)) {
            nsString = nsString + "," + domainName;
            localEditor = this.mSharedPreferences.edit();
            localEditor.putString("history", nsString);
            localEditor.commit();
        }
    }

该函数放在查询功能中加一个判断
放在之前的主函数中即可

  //查询成功则将域名传入sp
        if (mlookup.getResult()==Lookup.SUCCESSFUL){
            setHistory(s);
            Log.d("--------调试sp-------");
            System.out.print(mSharedPreferences.getString("history",""));
        }

之后是关于clear清空按钮的函数以及sp获取方法等

/**
     * 从sp中获取数据
     */
    public String getHistory()
    {
        return this.mSharedPreferences.getString("history", "");
    }


    /**
     * 清空dialog
     */
    public void setHistoryNull()
    {
        SharedPreferences.Editor localEditor = this.mSharedPreferences.edit();
        localEditor.putString("history", null);
        localEditor.commit();
    }


    /**
     * 设置输入框数据
     * @param paramString
     */
    public void setEditText(String paramString)
    {
        this.mEdiText.setText(paramString);
    }

做一个文本框清除按钮

ns--clear.png
思路也很清晰将按钮放在文本框末端并且设置成隐藏,与文本框的焦点获取绑定到一起即可

 android:visibility="gone"

那么之后在文件夹中添加一个图片类似于叉号的都可以
在drawable文件夹右键→new→image asset
imageassert.png

imageassert1.png
google提供了很多Android原生按钮,样式背景以及颜色都可以自己实设置之后点击next然后添加到文件夹即可
然后实现代码

mClearButton=(Button) mNslookupView.findViewById(R.id.btn_ns_clear);
        mClearButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //点击按钮清空输入框
                mEdiText.getText().clear();
            }
        });
        mTextView = (TextView) mNslookupView.findViewById(R.id.text_showip);
        //输入框
        mEdiText = (EditText) mNslookupView.findViewById(R.id.edit_nslookup);
        //用户触摸EditText得到焦点
        mEdiText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus){
                    //得到焦点时显示清除按钮
                    mClearButton.setVisibility(View.VISIBLE);
                }else {
                    //失去焦点时隐藏清除按钮
                    mClearButton.setVisibility(View.GONE);
                }
            }

        });

大概就完成了这么多,之后还会添加一些东西例如回车键绑定搜索按键,点击按钮直接copy显示出的ip,还有更好的设计模式例如material design设计模式,Android目前还在学习中在这里做点小总结,希望以后坚持下去,每天收获一点东西,厚积薄发。最后贴上一张偶像照片。
王力宏《无问西东》饰演热血飞行员沈光耀.jpg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值