posts - 8, comments - 7, trackbacks - 0, articles - 0
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

公告

2011年4月19日

一、几个关键概念
1、MessageQueue:是一种数据结构,见名知义,就是一个消息队列,存放消息的地方。每一个线程最多只可以拥有一个MessageQueue数据结构。
创建一个线程的时候,并不会自动创建其MessageQueue。通常使用一个Looper对象对该线程的MessageQueue进行管理。主线程创建时,会创建一
个默认的Looper对象,而Looper对象的创建,将自动创建一个Message Queue。其他非主线程,不会自动创建Looper,要需要的时候,通过调
用prepare函数来实现。
2、Message:消息对象,Message Queue中的存放的对象。一个Message Queue中包含多个Message。
Message实例对象的取得,通常使用Message类里的静态方法obtain(),该方法有多个重载版本可供选择;它的创建并不一定是直接创建一个新的实例,
而是先从Message Pool(消息池)中看有没有可用的Message实例,存在则直接取出返回这个实例。如果Message Pool中没有可用的Message实例,
则才用给定的参数创建一个Message对象。调用removeMessages()时,将Message从Message Queue中删除,同时放入到Message Pool中。除了上面这
种方式,也可以通过Handler对象的obtainMessage()获取一个Message实例。
3、Looper:
是MessageQueue的管理者。每一个MessageQueue都不能脱离Looper而存在,Looper对象的创建是通过prepare函数来实现的。同时每一个Looper对象
和一个线程关联。通过调用Looper.myLooper()可以获得当前线程的Looper对象
创建一个Looper对象时,会同时创建一个MessageQueue对象。除了主线程有默认的Looper,其他线程默认是没有MessageQueue对象的,所以,不能
接受Message。如需要接受,自己定义一个Looper对象(通过prepare函数),这样该线程就有了自己的Looper对象和MessageQueue数据结构了。
Looper从MessageQueue中取出Message然后,交由Handler的handleMessage进行处理。处理完成后,调用Message.recycle()将其放入Message Pool中。
4、Handler:
消息的处理者,handler负责将需要传递的信息封装成Message,通过调用handler对象的obtainMessage()来实现;
将消息传递给Looper,这是通过handler对象的sendMessage()来实现的。继而由Looper将Message放入MessageQueue中。
当Looper对象看到MessageQueue中含有Message,就将其广播出去。该handler对象收到该消息后,调用相应的handler对象的handleMessage()方法
对其进行处理。
二、线程之间的消息如何进行传递
1、主线程给自己发送Message
package test.message;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
    private Button btnTest;
    private TextView textView;
    private Handler handler;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btnTest = (Button)this.findViewById(R.id.btn_01);
        textView = (TextView)this.findViewById(R.id.view_01);
        btnTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                Looper looper = Looper.getMainLooper(); //主线程的Looper对象
                //这里以主线程的Looper对象创建了handler,
                //所以,这个handler发送的Message会被传递给主线程的MessageQueue。
                handler = new MyHandler(looper);
                handler.removeMessages(0);
                //构建Message对象
                //第一个参数:是自己指定的message代号,方便在handler选择性地接收
                //第二三个参数没有什么意义
                //第四个参数需要封装的对象
                Message msg = handler.obtainMessage(1,1,1,"主线程发消息了");
                handler.sendMessage(msg); //发送消息
            }
        });
    }
    class MyHandler extends Handler{
        public MyHandler(Looper looper){
            super(looper);
        }
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            textView.setText("我是主线程的Handler,收到了消息:"+(String)msg.obj);
        }
    }
}
2、其他线程给主线程发送Message
package test.message;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
    private Button btnTest;
    private TextView textView;
    private Handler handler;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btnTest = (Button)this.findViewById(R.id.btn_01);
        textView = (TextView)this.findViewById(R.id.view_01);
        btnTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                //可以看出这里启动了一个线程来操作消息的封装和发送的工作
                //这样原来主线程的发送就变成了其他线程的发送,简单吧?呵呵
                new MyThread().start();    
            }
        });
    }
    class MyHandler extends Handler{
        public MyHandler(Looper looper){
            super(looper);
        }
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            textView.setText("我是主线程的Handler,收到了消息:"+(String)msg.obj);
        }
    }
    //加了一个线程类
    class MyThread extends Thread{
        public void run(){
            Looper looper = Looper.getMainLooper(); //主线程的Looper对象
            //这里以主线程的Looper对象创建了handler,
            //所以,这个handler发送的Message会被传递给主线程的MessageQueue。
            handler = new MyHandler(looper);
            //构建Message对象
            //第一个参数:是自己指定的message代号,方便在handler选择性地接收
            //第二三个参数没有什么意义
            //第四个参数需要封装的对象
            Message msg = handler.obtainMessage(1,1,1,"其他线程发消息了");
            handler.sendMessage(msg); //发送消息            
        }
    }
}
3、主线程给其他线程发送Message
package test.message;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
    private Button btnTest;
    private TextView textView;
    private Handler handler;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btnTest = (Button)this.findViewById(R.id.btn_01);
        textView = (TextView)this.findViewById(R.id.view_01);
        //启动线程
        new MyThread().start();    
        btnTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                //这里handler的实例化在线程中
                //线程启动的时候就已经实例化了
                Message msg = handler.obtainMessage(1,1,1,"主线程发送的消息");
                handler.sendMessage(msg);
            }
        });
    }
    class MyHandler extends Handler{
        public MyHandler(Looper looper){
            super(looper);
        }
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            textView.setText("我是主线程的Handler,收到了消息:"+(String)msg.obj);
        }
    }
    class MyThread extends Thread{
        public void run(){
            Looper.prepare(); //创建该线程的Looper对象,用于接收消息
            //注意了:这里的handler是定义在主线程中的哦,呵呵,
            //前面看到直接使用了handler对象,是不是在找,在什么地方实例化的呢?
            //现在看到了吧???呵呵,开始的时候实例化不了,因为该线程的Looper对象
            //还不存在呢。现在可以实例化了
            //这里Looper.myLooper()获得的就是该线程的Looper对象了
            handler = new ThreadHandler(Looper.myLooper());
            //这个方法,有疑惑吗?
            //其实就是一个循环,循环从MessageQueue中取消息。
            //不经常去看看,你怎么知道你有新消息呢???
            Looper.loop(); 
        }
        //定义线程类中的消息处理类
        class ThreadHandler extends Handler{
            public ThreadHandler(Looper looper){
                super(looper);
            }
            public void handleMessage(Message msg){
                //这里对该线程中的MessageQueue中的Message进行处理
                //这里我们再返回给主线程一个消息
                handler = new MyHandler(Looper.getMainLooper());
                Message msg2 = handler.obtainMessage(1,1,1,"子线程收到:"+(String)msg.obj);
                handler.sendMessage(msg2);
            }
        }
    }
}
4、其他线程给自己发送Message 
package test.message;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
    private Button btnTest;
    private TextView textView;
    private Handler handler;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btnTest = (Button)this.findViewById(R.id.btn_01);
        textView = (TextView)this.findViewById(R.id.view_01);
        btnTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                //启动线程
                new MyThread().start();    
            }
        });
    }
    class MyHandler extends Handler{
        public MyHandler(Looper looper){
            super(looper);
        }
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            textView.setText((String)msg.obj);
        }
    }    
    class MyThread extends Thread{
        public void run(){
            Looper.prepare(); //创建该线程的Looper对象
            //这里Looper.myLooper()获得的就是该线程的Looper对象了
            handler = new ThreadHandler(Looper.myLooper());
            Message msg = handler.obtainMessage(1,1,1,"我自己");
            handler.sendMessage(msg);
            Looper.loop(); 
        }
        //定义线程类中的消息处理类
        class ThreadHandler extends Handler{
            public ThreadHandler(Looper looper){
                super(looper);
            }
            public void handleMessage(Message msg){
                //这里对该线程中的MessageQueue中的Message进行处理
                //这里我们再返回给主线程一个消息
                //加入判断看看是不是该线程自己发的信息
                if(msg.what == 1 && msg.obj.equals("我自己")){
                    handler = new MyHandler(Looper.getMainLooper());
                    Message msg2 = handler.obtainMessage(1,1,1,"禀告主线程:我收到了自己发给自己的Message");
                    handler.sendMessage(msg2);                
                }
            }
        }
    }
}
附注:
上面四个例子的布局文件是同一个文件main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:rientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  android:id="@+id/view_01"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"
    />
<Button android:id="@+id/btn_01" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="测试消息" />
</LinearLayout>

-----------------------------------------------------------------------------------------------------------------------------------------

原文地址:http://tanghaibo001.blog.163.com/blog/static/9068612020111287218197/

posted @ 2011-04-19 15:39 livesoft 阅读(2104) 评论(1) 编辑

2011年2月13日

TextView title=(TextView)tabHost.getTabWidget().getChildAt(TAB顺序).findViewById(android.R.id.title);
title.setText(“值”);

posted @ 2011-02-13 14:08 livesoft 阅读(241) 评论(0) 编辑

2011年2月12日

在Android软件设计与实现中我们通常都会使用到ListView这个控件,系统有一些预置的Adapter可以使用,例如SimpleAdapter和ArrayAdapter,但是总是会有一些情况我们需要通过自定义ListView来实现一些效果,那么在这个时候,我们通常会碰到自定义ListView无法选中整个ListViewItem的情况,也就是无法响应ListView的onItemClickListener中的onItemClick()方法,究竟是为什么呢?我之前也在网上查过不少的资料,但是没有发现什么有价值的文章,有一些是建议在Adapter的getView方法中对自己需要响应单击事件的控件进行设置。但是最终的效果并不是特别理想,而且我认为这是一种取巧的方式,并不推荐。之后自己查看了一下ViewGroup的源码,发现了以下的一段常量声明:

/**

* This view will get focus before any of its descendants.

*/

public static final int FOCUS_BEFORE_DESCENDANTS = 0×20000;

/**

* This view will get focus only if none of its descendants want it.

*/

public static final int FOCUS_AFTER_DESCENDANTS = 0×40000;

/**

* This view will block any of its descendants from getting focus, even

* if they are focusable.

*/

public static final int FOCUS_BLOCK_DESCENDANTS = 0×60000;

/**     * This view will get focus before any of its descendants.     */

public static final int FOCUS_BEFORE_DESCENDANTS = 0×20000;
/**     * This view will get focus only if none of its descendants want it.     */

public static final int FOCUS_AFTER_DESCENDANTS = 0×40000;
/**     * This view will block any of its descendants from getting focus, even     * if they are focusable.     */

public static final int FOCUS_BLOCK_DESCENDANTS = 0×60000;

我们看到了一行代码定义的变量的意思是“当前View将屏蔽他所有子控件的Focus状态,即便这些子控件是可以Focus的”,其实这段话的意思就是这个变量代表着当前的View将不顾其子控件是否可以Focus自身接管了所有的Focus,通常默认能获得focus的控件有Button,Checkable继承来的所有控件,这就意味着如果你的自定义ListViewItem中有Button或者Checkable的子类控件的话,那么默认focus是交给了子控件,而ListView的Item能被选中的基础是它能获取Focus,也就是说我们可以通过将ListView中Item中包含的所有控件的focusable属性设置为false,这样的话ListView的Item自动获得了Focus的权限,也就可以被选中了,也就会响应onItemClickListener中的onItemClick()方法,然而将ListView的Item Layout的子控件focusable属性设置为false有点繁琐,我们可以通过对Item Layout的根控件设置其android:descendantFocusability=”blocksDescendants”即可,这样Item Layout就屏蔽了所有子控件获取Focus的权限,不需要针对Item Layout中的每一个控件重新设置focusable属性了,如此就可以顺利的响应onItemClickListener中的onItemClick()方法了。

原文--http://www.7dot9.com/2010/09/android%E4%B8%AD%E8%87%AA%E5%AE%9A%E4%B9%89listview%E6%97%A0%E6%B3%95%E5%93%8D%E5%BA%94onitemclicklistener%E4%B8%AD%E7%9A%84onitemclick%E6%96%B9%E6%B3%95%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3%E6%96%B9/

posted @ 2011-02-12 00:32 livesoft 阅读(3833) 评论(1) 编辑

2010年12月9日

1.配置AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="ly.excrcise"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
         <uses-library android:name="android.test.runner" />"<!--加这句-->
        <activity android:name=".ActivityMain"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
    <uses-sdk android:minSdkVersion="3" />
    <!--加下面两句-->
	<uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />"
	<instrumentation android:name="android.test.InstrumentationTestRunner" 
	android:targetPackage="ly.exercise"
	android:label="Test for my app"/>"
</manifest> 

2.编写单元测试代码:必须继承AndroidTestCase
package ly.exercise;

import junit.framework.Assert;
import android.test.AndroidTestCase;

public class AndroidTest extends AndroidTestCase {
	public void test(){
		int i=4+8;
		Assert.assertEquals(12,i);
	}
}


posted @ 2010-12-09 20:42 livesoft 阅读(639) 评论(0) 编辑

要使用手机短信服务,在AndroidManifest.xml中必须添加短信服务权限

AndroidManifest.xml

<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.me.sendsms">
    <application>
         <activity android:name=".MainActivity" android:label="MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
    <uses-sdk android:minSdkVersion="3"/>
    <uses-permission android:name="android.permission.SEND_SMS"/><!--添加权限-->
</manifest>

MainActivity.java

 

package org.me.sendsms;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.gsm.SmsManager;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import java.util.List;

public class MainActivity extends Activity {

    private EditText txtNo;
    private EditText txtContent;
    private Button btnSend;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);
        txtNo = (EditText) findViewById(R.id.txtNo);
        txtContent = (EditText) findViewById(R.id.txtContent);
        btnSend = (Button) findViewById(R.id.btnSend);

        btnSend.setOnClickListener(new View.OnClickListener()  {

            @Override
            public void onClick(View v) {
                String strNo = txtNo.getText().toString();
                String strContent = txtContent.getText().toString();
                SmsManager smsManager = SmsManager.getDefault();
                PendingIntent sentIntent = PendingIntent.getBroadcast(MainActivity.this, 0, new Intent(), 0);
                //如果字数超过70,需拆分成多条短信发送
                if (strContent.length() > 70) {
                    List<String> msgs = smsManager.divideMessage(strContent);
                    for (String msg : msgs) {
                        smsManager.sendTextMessage(strNo, null, msg, sentIntent, null);                        
                    }
                } else {
                    smsManager.sendTextMessage(strNo, null, strContent, sentIntent, null);
                }
                Toast.makeText(MainActivity.this, "短信发送完成", Toast.LENGTH_LONG).show();
            }
        });
    }
}

posted @ 2010-12-09 20:41 livesoft 阅读(6004) 评论(0) 编辑

2010年12月7日

使用系统拔号服务必须在AndroidManifest.xml中添加电话服务权限

AndroidManifest.xml

<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.me.callphone">
    <application>
         <activity android:name=".MainActivity" android:label="MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
    <uses-sdk android:minSdkVersion="3" />
    <uses-permission android:name="android.permission.CALL_PHONE"/><!--加入权限-->
</manifest>

MainActivity.java

package org.me.callphone;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity {

    private EditText txtNo;
    private Button btnCall;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);
        
        txtNo=(EditText)findViewById(R.id.txtNo);
        btnCall=(Button)findViewById(R.id.btnCall);
        btnCall.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v){
               Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+txtNo.getText()));//拔打电话Intent
	       MainActivity.this.startActivity(intent);
            }
        });
    }
}

posted @ 2010-12-07 00:43 livesoft 阅读(321) 评论(2) 编辑

2010年12月1日

摘要: 1.通过XML布局添加菜单 首先在项目目录res下建立文件夹menu,然后在新建的menu文件夹下添加 menu.xml [代码]在ActivityMain中添加菜单ACtivityMain.java [代码] 2.通过Menu.add方法添加菜单在ActivityMain中添加菜单ACtivityMain.java [代码]阅读全文

posted @ 2010-12-01 23:46 livesoft 阅读(3113) 评论(3) 编辑

2010年11月28日

摘要: ActivityMain.java [代码]SecActivity.java[代码]阅读全文

posted @ 2010-11-28 23:35 livesoft 阅读(533) 评论(0) 编辑