2013年1月31日星期四

关于Android写LOG日志到SD卡文件之microlog4android使用


最近在搞andoird项目时,经常碰到客户那边机器型号不一样,导致程序有BUG问题,而我们这边又无法定位这个BUG的确切位置(因为没有LOG文件)。

因此找了一下把程序日志写在SD卡的相关资料,就像WEB的log4j一样,生成一个日志文件到SD卡。
找了半天,没有找到一个满意的开源软件,就找到了microlog4android,用起来虽然不大满意,不过也能满足大部分需求了。
具体使用如下:
1、下载
http://code.google.com/p/microlog4android/downloads/list 下载microlog4android-1.0.0.jar和microlog.properties文件
2、建立使用logger对象
private static final Logger logger = LoggerFactory.getLogger(main.class);
3、在程序的第一个activity的oncreate方法里初始化方法
PropertyConfigurator.getConfigurator(this).configure();
4、把microlog.properties文件放到assets文件夹里
注意:assets文件夹是与res文件夹平级的
然后更改microlog.properties文件为以下内容:
microlog.level=DEBUG
microlog.appender=LogCatAppender;FileAppender
microlog.formatter=PatternFormatter
microlog.formatter.PatternFormatter.pattern=%c [%P] %m %T
5、写日志记录
logger.debug("这是debug信息");
6、在AndroidManifest.xml 添加写sd卡的权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

运行程序,然后到SD卡根目录,可以发现有一个microlog.txt的文件,里面就是我们的日志了。
后续:
有朋友问如何更改日志文件的路径和名称,在网上找了一通的资料,没找到答案,只好到https://github.com/johanlkarlsson/microlog4android 下载源代码,经过查看源代码的PropertyConfigurator类,发现源代码里有这么一个配置参数microlog.appender.FileAppender.File,这样应该就可以更改日志文件的路径和名称了。
配置文件如下:
microlog.level=DEBUG
microlog.appender=FileAppender;LogCatAppender
microlog.appender.FileAppender.File=mylog.txt
microlog.formatter=PatternFormatter
microlog.formatter.PatternFormatter.pattern=%c [%P] %m %T
运行程序,发现日志文件还是叫microlog.txt,更改名称无效,找了各种原因都无法解决,只好反编译我们之前下载的microlog4android-1.0.0.jar包,发现PropertyConfigurator这个类和刚刚从GIT下载的源代码PropertyConfigurator类不一样,microlog4android-1.0.0.jar包里的PropertyConfigurator类没有这样的一个参数microlog.appender.FileAppender.File,只好把从GIT下载下来的源代码,重新打个包,暂时打成microlog4android-1.1.jar,然后重新运行程序,OK,搞定,日志文件名称变成了我们配置的mylog.txt。

android httprequest java.net.UnknownHostException


Check the emulator log messages. There's a good chance you just aren't asking for the INTERNET permission in your app manifest

this is what i am using: ... <uses-permission android:name="android.permission.INTERNET"></uses-permission> </manifest>

AndroidGUI27:findViewById返回null的解决办法


在用Eclipse进行Android的界面开发,通过findViewById试图获取界面元素对象时,该方法有时候返回null,造成这种情况主要有以下两种情形。
第一种情形是最普通的。比如main.xml如下,其中有一个ListView,其id为lv_contactbook

<?xml version="1.0"encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

    <EditText android:id="@+id/et_search"

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    android:text=""

    />



         <ListView android:id="@+id/lv_contactbook"

                   android:layout_width="fill_parent"

                   android:layout_height="wrap_content"

         />

</LinearLayout>

如果在Activity对应的代码中,是这样的写的:

@Override

public void onCreate(BundlesavedInstanceState)

{

         super.onCreate(savedInstanceState);

         ListViewlv = (ListView)findViewById(R.id.lv_contactbook);

         setContentView(R.layout.main);

         //…

}

即在setContentView调用之前,调用了findViewById去找main布局中的界面元素lv_contactbook,那么所得到的lv一定是null。正确的做法是将上面代码中加粗的哪一行,挪至setContentView方法调用之后。

修改Linux SSH默认22端口


首先修改配置文件
  vi /etc/ssh/sshd_config

  找到#Port 22一段,这里是标识默认使用22端口,修改为如下:

  Port 22
  Port 50000
  然后保存退出

  执行/etc/init.d/sshd restart
  这样SSH端口将同时工作与22和50000上。

  现在编辑防火墙配置:vi /etc/sysconfig/iptables

  启用50000端口。
  执行/etc/init.d/iptables restart

  现在请使用ssh工具连接50000端口,来测试是否成功。如果连接成功了,则再次编辑sshd_config的设置,将里边的Port22删除,即可。

  之所以先设置成两个端口,测试成功后再关闭一个端口,是为了方式在修改conf的过程中,万一出现掉线、断网、误操作等未知情况时候,还能通过另外一个端口连接上去调试以免发生连接不上必须派人去机房,导致问题更加复杂麻烦。

Eclipse 自动提示功能配置


配置步骤:
1  Window > Preferences > Java > Editor > Content Assist
2  “Auto Activation triggers for java”这个选项就是指触发代码提示的的选项,
     把“.”修改成".abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
     意思就是指遇到26个字母的大小写和.(这些符号就触发代码提示功能了)

配置截图:


Android开发学习笔记:Button事件实现方法的总结


下面介绍Button事件实现的两种方法
main.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

<TextView  

    android:layout_width="fill_parent"  

    android:layout_height="wrap_content"  

    android:text="@string/hello"

    />

<Button  

    android:id="@+id/myButton1"

    android:text=" 按钮1 "

    android:layout_width="wrap_content"  

    android:layout_height="wrap_content"  

    />

<Button  

    android:id="@+id/myButton2"

    android:text=" 按钮2 "

    android:layout_width="wrap_content"  

    android:layout_height="wrap_content"  

    />

</LinearLayout>


strings.xml

<?xml version="1.0" encoding="utf-8"?>

<resources>

    <string name="hello">Hello World, ButtonDemoActivity!</string>

    <string name="app_name">ButtonDemo</string>

</resources>


第一种:
ButtonDemoActivity.java

package com.android.ButtonDemo.activity;



import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.Toast;



public class ButtonDemoActivity extends Activity {

    Button myButton1,myButton2;

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

         

        myButton1=(Button)findViewById(R.id.myButton1);

        myButton2=(Button)findViewById(R.id.myButton2);

         

        //使用匿名类注册Button事件

        myButton1.setOnClickListener(new OnClickListener()

        {        

            public void onClick(View v)

            {

                Toast.makeText(ButtonDemoActivity.this, "你点击了按钮1",Toast.LENGTH_LONG).show();

            }

        });

        myButton2.setOnClickListener(new OnClickListener()

        {        

            public void onClick(View v)

            {

                Toast.makeText(ButtonDemoActivity.this, "你点击了按钮2",Toast.LENGTH_LONG).show();

            }

        });

    }

}


第二种:
ButtonDemoActivity.java

package com.android.ButtonDemo.activity;



import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.Toast;



public class ButtonDemoActivity extends Activity {

    Button myButton1,myButton2;

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

         

        myButton1=(Button)findViewById(R.id.myButton1);

        myButton2=(Button)findViewById(R.id.myButton2);

        myButton1.setOnClickListener(new ButtonClick());

        myButton2.setOnClickListener(new ButtonClick());

         

    }

    //创建一个类,来响应OnClickListener

    class ButtonClick implements OnClickListener

    {

        public void onClick(View v)

        {

            switch (v.getId()) {

            case R.id.myButton1:

                Toast.makeText(ButtonDemoActivity.this, "你点击了按钮1",Toast.LENGTH_LONG).show();

                break;

            case R.id.myButton2:

                Toast.makeText(ButtonDemoActivity.this, "你点击了按钮2",Toast.LENGTH_LONG).show();

                break;

            default:

                break;

            }

        }        

    }

}



android: 服务器通信(GET,POST)




Android应用经常会和服务器端交互,这就需要手机客户端发送网络请求,下面介绍四种常用网络请求方式,
java.net包中的HttpURLConnection类

Get方式:

// Get方式请求
public static void requestByGet() throws Exception {
    String path = "https://reg.163.com/logins.jsp?id=helloworld&pwd=android";
    // 新建一个URL对象
    URL url = new URL(path);
    // 打开一个HttpURLConnection连接
    HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
    // 设置连接超时时间
    urlConn.setConnectTimeout(5 * 1000);
    // 开始连接
    urlConn.connect();
    // 判断请求是否成功
    if (urlConn.getResponseCode() == HTTP_200) {
        // 获取返回的数据
        byte[] data = readStream(urlConn.getInputStream());
        Log.i(TAG_GET, "Get方式请求成功,返回数据如下:");
        Log.i(TAG_GET, new String(data, "UTF-8"));
    } else {
        Log.i(TAG_GET, "Get方式请求失败");
    }
    // 关闭连接
    urlConn.disconnect();
}

Post方式:

// Post方式请求
public static void requestByPost() throws Throwable {
    String path = "https://reg.163.com/logins.jsp";
    // 请求的参数转换为byte数组
    String params = "id=" + URLEncoder.encode("helloworld", "UTF-8")
            + "&pwd=" + URLEncoder.encode("android", "UTF-8");
    byte[] postData = params.getBytes();
    // 新建一个URL对象
    URL url = new URL(path);
    // 打开一个HttpURLConnection连接
    HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
    // 设置连接超时时间
    urlConn.setConnectTimeout(5 * 1000);
    // Post请求必须设置允许输出
    urlConn.setDoOutput(true);
    // Post请求不能使用缓存
    urlConn.setUseCaches(false);
    // 设置为Post请求
    urlConn.setRequestMethod("POST");
    urlConn.setInstanceFollowRedirects(true);
    // 配置请求Content-Type
    urlConn.setRequestProperty("Content-Type",
            "application/x-www-form-urlencode");
    // 开始连接
    urlConn.connect();
    // 发送请求参数
    DataOutputStream dos = new DataOutputStream(urlConn.getOutputStream());
    dos.write(postData);
    dos.flush();
    dos.close();
    // 判断请求是否成功
    if (urlConn.getResponseCode() == HTTP_200) {
        // 获取返回的数据
        byte[] data = readStream(urlConn.getInputStream());
        Log.i(TAG_POST, "Post请求方式成功,返回数据如下:");
        Log.i(TAG_POST, new String(data, "UTF-8"));
    } else {
        Log.i(TAG_POST, "Post方式请求失败");
    }
}


 org.apache.http包中的HttpGet和HttpPost类

Get方式:

// HttpGet方式请求
public static void requestByHttpGet() throws Exception {
    String path = "https://reg.163.com/logins.jsp?id=helloworld&pwd=android";
    // 新建HttpGet对象
    HttpGet httpGet = new HttpGet(path);
    // 获取HttpClient对象
    HttpClient httpClient = new DefaultHttpClient();
    // 获取HttpResponse实例
    HttpResponse httpResp = httpClient.execute(httpGet);
    // 判断是够请求成功
    if (httpResp.getStatusLine().getStatusCode() == HTTP_200) {
        // 获取返回的数据
        String result = EntityUtils.toString(httpResp.getEntity(), "UTF-8");
        Log.i(TAG_HTTPGET, "HttpGet方式请求成功,返回数据如下:");
        Log.i(TAG_HTTPGET, result);
    } else {
        Log.i(TAG_HTTPGET, "HttpGet方式请求失败");
    }
}

Post方式:

view plain
// HttpPost方式请求
public static void requestByHttpPost() throws Exception {
    String path = "https://reg.163.com/logins.jsp";
    // 新建HttpPost对象
    HttpPost httpPost = new HttpPost(path);
    // Post参数
    List<NameValuePair> params = new ArrayList<NameValuePair>();
    params.add(new BasicNameValuePair("id", "helloworld"));
    params.add(new BasicNameValuePair("pwd", "android"));
    // 设置字符集
    HttpEntity entity = new UrlEncodedFormEntity(params, HTTP.UTF_8);
    // 设置参数实体
    httpPost.setEntity(entity);
    // 获取HttpClient对象
    HttpClient httpClient = new DefaultHttpClient();
    // 获取HttpResponse实例
    HttpResponse httpResp = httpClient.execute(httpPost);
    // 判断是够请求成功
    if (httpResp.getStatusLine().getStatusCode() == HTTP_200) {
        // 获取返回的数据
        String result = EntityUtils.toString(httpResp.getEntity(), "UTF-8");
        Log.i(TAG_HTTPGET, "HttpPost方式请求成功,返回数据如下:");
        Log.i(TAG_HTTPGET, result);
    } else {
        Log.i(TAG_HTTPGET, "HttpPost方式请求失败");
    }
}