android4.0以上访问网络不能在主线程中进行以及在线程中操作UI的解决方法

MONO 调用一个线程操作UI 然后报Only the original thread that created a view hierarchy can touch its views。错误 google了一下说UI的操作还是需要到主线程,看了些java的例子 java中是使用了Handler 但是在MONO中需要怎么实现?

一.

RunOnUiThread(()=>执行语句  );

demo:

this.RunOnUiThread(() => tv.Text = "records: " + twt.Count.ToString());

二.

Handler实现也是可以的,关键代码
        private Handler handler = new Handler();
        Java.Lang.Runnable rb;
protected override void OnCreate(Bundle bundle){
                        rb = new Java.Lang.Runnable(() => {
                            button.Text = string.Format("{0} Runnable!", count++);
                            handler.PostDelayed(rb, 1000);
                        });
                        handler.PostDelayed(rb, 1000);}

三.其他方式

 

 

 

刚刚上手android,在写一个利用Socket与服务器端进行通信的Demo时候报了一个android.os.NetworkOnMainThreadException的异常:

服务器端:

public class SimpleServer {

public static void main(String[] args){

try {

ServerSocket ss=new ServerSocket(40000);

System.out.println("等待连接......");

while(true){

Socket s=ss.accept();

OutputStream os=s.getOutputStream();

os.write("hello".getBytes("utf-8"));

os.close();

s.close();

}

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

求助度娘后发现是SDK的版本问题,android4.0中访问网络不能在主程序中进行,行吧,那就老老实实的重新开启一个线程:

new Thread(){

public void run(){

try {

Socket s=new Socket("172.22.16.26", 40000);

BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));

String line=br.readLine();

show.setText("服务器说:"+line);

br.close();

s.close();

} catch (UnknownHostException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}.start();

结果又报了异常:

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

相信各位已经看出了在下犯了一个很低级的错误:在新启的线程中操作UI,UI线程是非线程安全的,Android平台不允许Activity新启动的线程访问该Activity里的界面组件,这时就要借助Handler的消息传递机制了:

new Thread(){

public void run(){

try {

Socket s=new Socket("172.18.6.26",40000);

BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));

String line=br.readLine();

//System.out.println("服务器说:"+line);

Message msg=new Message();

msg.what=0x123;

msg.obj=line;

myhandler.sendMessage(msg);

br.close();

s.close();

} catch (UnknownHostException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}.start();

然后重写handlerMessage方法获取消息:

final Handler myhandler=new Handler(){

public void handleMessage(Message msg){

if(msg.what==0x123){

System.out.println("--------------->"+msg.obj);

show2.setText((String)msg.obj);

}

}

};

当新线程发送消息时,该方法自动被调用,handlerMessage(Message msg)方法依旧位于主线程中,所以可以动态的修改UI组件。

 

 

网络连接不能放在主线程
       android 4.0 以上    网络连接不能放在主线程
       4.0 以下 好像可以

RLZH~UWUX47AJ%ZY1~QPC_T

Q$0TQ)}A@~O3WL)MSS~D)GV

 

 

 

在Android4.0以后,会发现,只要是写在主线程(就是Activity)中的HTTP请求,运行时都会报错,这是因为Android在4.0以后为了防止应用的ANR(aplication Not Response)异常,即使这里表达不是很清晰,大家应该都明白吧,哈哈

就针对此问题有两种解决的方法:

1.可以再Activity的onCreate()方法中加入这样一段代码,如下:

JAVA

if (Build.VERSION.SDK_INT >= 11) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads  ().detectDiskWrites().detectNetwork().penaltyLog().build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().detectLeakedClosableObjects().penaltyLog().penaltyDeath().build());
}

 

Mono 版

if (Build.VERSION.SdkInt.GetHashCode()>=11)
            {
                StrictMode.SetThreadPolicy(new StrictMode.ThreadPolicy.Builder().DetectDiskReads().DetectDiskWrites().DetectNetwork().PenaltyLog().Build());
                StrictMode.SetVmPolicy(new StrictMode.VmPolicy.Builder().DetectLeakedSqlLiteObjects().DetectLeakedClosableObjects().PenaltyLog().PenaltyDeath().Build());
            }


后就可以在主线程中进行网络操作了

2.一般情况我们应该这样做

启动一条子线程进行你的网络请求。

当然,如果你的应用程序执行的网络请求数据量很小的话,可以使用第一种方案

posted @ 2013-09-30 11:26  寒殇  阅读(2924)  评论(0编辑  收藏  举报