Android之线程处理

初入Android可谓是举步维艰,当涉及到使用后台的接口获取信息并更新UI,我便遇到了处理多线程的许多问题,经过两个月的实践以及精细的打磨,学到了线程处理的一些知识,接下来我将详细的阐述有关Android的线程处理方面的知识,如有理解错误的,敬请指正!

 

首先,我们要明确一点Android的耗时操作是绝对不允许在主线程(Main Tread)里面执行的!这些耗时操作,比如下载或上传图片、获取或上传大量的字符串、视频的传输等等。当一个控件的点击事件涉及到这些耗时操作时,那么意味着控件的响应将变得很慢,当然这只是理想状态的,而实际上,当出现这种情况时,程序是会出现ANR(程序不响应)的,那么程序会崩溃掉。Android的主线程基本上是用来响应控件的点击事件而更新UI的,所以我们的耗时操作是需要放到子线程执行的,这里我再添加一点,严格意义上讲Anroid的子线程是不能够更新UI的,具体见(http://blog.csdn.net/zhao_csdn_8/article/details/64126195)。

 

接下来,我们借两张图来了解一下Handler机制:

Handler机制包括三个部分:HandlerLooperMessageQueue,这三个部分构成一个处理循环,Handler即处理,Looper是一个死循环,MessageQueue是消息队列,如下:

 

这里边就有着许多步骤:

>>Handler回调用sendxxx方法将延时操作所获取的数据发送出去。

>>然后Handler再调用enqueueMessage(Message msg, long when)方法将消息入队列。

>>looper轮询到消息时,Looper调用next() ,将消息移出队列。

>>然后Looper回调HandlerdispatchMessage方法将消息分发给Handler的实例去处理。

 

Handler有如下的处理方法……

 

 

方法一:new Handler().sendMessage()

……

//如下是一个实现异步加载图片的实例……

private Handler handler=new Handler(){//处理消息

        @Override

        public void handleMessage(Message msg) {

            switch (msg.what)

            {

                case 0:

                    getc.setImageBitmap((Bitmap)msg.obj);

       //设置图片显示

                    break;

      default:

        break;

    }

            super.handleMessage(msg);

        }

    };

 

 

public void getIdentifyingCode(){//显示验证码

new Thread(){

            @Override

            public void run() {

                super.run();

                Bitmap bitmap=LoadBitmap();//延时操作

                Message msg=Message.obtain();

                msg.what=0;

                msg.obj=bitmap;

                handler.sendMessage(msg);

            }

        }.start();

    }

    public Bitmap LoadBitmap(){//异步线程加载验证码的图片

        Bitmap bitmap=null;

        String urlString="获取图片的URL地址";

        URLConnection con= null;

        try {

   con = new URL(urlString).openConnection();

   InputStream is=new BufferedInputStream(con.getInputStream());

   bitmap= BitmapFactory.decodeStream(is);

   is.close();

        } catch (IOException e) {

            e.printStackTrace();}

        if(bitmap==null) Toast.makeText(Login.this,"服务器连接错误,无法获取验证码",Toast.LENGTH_LONG); return bitmap;}

 

另外,我在用此方法实现账号登录供能的时候,我在OnClick()里实现一段如下:

public class MainActivity extends Activity {

protected String jsonData;

……

Handler handler=new Handler(){

@Override

public void handMessage(Object msg){

……

jsonData=msg.toString();

}

}

……

case R.id.login:

getLoginData();//此函数里面开启线程获取数据

If(jsonData做出响应的判断)

执行相应的操作

break;

……

}

然后会在if判断处报出空指针错误,原因是:其实在getLogin()执行时,执行了thread.start(); 但是handler并不是马上执行(相对而言的),而是在执行完case R.id.login:……这一代码块,handler才会执行,即主线程是优先执行的,所以在使用全局变量jsonData作为条件判断时,这个字符串根本就没有被赋值,所以会报出空指针错误。

于是就只能将getLoginData()后面的操作放到handler里面执行。

 

方法二:使用Runable

//使用runOnUiThread

public class MainActivity extends Activity {

private TextView tv;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

tv = (TextView) findViewById(R.id.tv);

new Thread(){

public void run() {

runOnUiThread(new Runnable() {

public void run() {

//此处可执行一般的耗时操作(小于5秒)

tv.setText("你好!!!");

}

});

};

}.start();

}

}

//使用handler.post(……)

public class MainActivity extends Activity {

private TextView tv;

private Handler handler=new Handler();

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

tv = (TextView) findViewById(R.id.tv);

new Thread(){

public void run() {

Handler.post(new Runnable() {

public void run() {

//此处可执行一般的耗时操作(小于5秒)

tv.setText("你好!!!");

}

});

};

}.start();

}

}

 

 

//继承Runable接口(postDelayed方法)

public class MainActivity extends Activity {

private Imageview im;

Private int images[]={R.drawable.image1,R.drawable.image2,

R.drawable.image2,};

private int index;

private MyRunable myRunable=new MyRunable();

private Handler handler=new Handler();

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

im = (ImageView) findViewById(R.id.im);

hander.postDelayed(myRunable,1000);//过一秒执行……

}

class MyRunable implements Runable{

@Override

public void run(){

index++;

Index=index%3//实现三张图片的轮流播放

im.setImageResource(images[index]);

hander.postDelayed(myRunable,1000);//采用递归 达到循环的效果

}

}

}

这三种方式的基本差不多,只是用到了不同的函数,不同的函数在底层调用的sendxxx方法和postxxx方法有所不同,本人还没学的那么深入,见谅。

对于异步处理,AsyncTask是一个比较好的选择,适合初学者使用,结构明朗易懂,只要是三个函数 onPre(),onPost()以及doback()等等(简略的写),下面为AsyncTask的基本结构:

 

class getDeptList extends AsyncTask<String,Void,JSONArray>{

              @Override

        protected void onPreExecute() {

            super.onPreExecute();

        }

        @Override

        protected JSONArray doInBackground(String... params) {

String data=getDeptlData(params[0]);//延时操作

try {

      JSONObject jsonObject=new JSONObject(data);

       dataArray=new JSONArray(jsonObject.getString("data"));

       return dataArray;

   } catch (JSONException e) {

       e.printStackTrace();

   }

    return null;

 }

@Override

protected void onPostExecute(JSONArray jsonArray) {

   super.onPostExecute(jsonArray);

   if(jsonArray==null){

     Toast.makeText(DeptList.this,"部门列表为空……",Toast.LENGTH_LONG).show();

   }

   else{

       //适配

DeptListAdapter deptListAdapter=newDeptListAdapter

(DeptList.this,jsonArray);

      mList.setAdapter(deptListAdapter);

            }

        }

    }

onPre()用于前期的处理,doBack()用于开启异步线程,此

数可将所得结果返回出去并由onPost()接收进行UI的更新。AsyncTask<argc1,argc2,argc3>类有三个传入参数类型,argc1起始传入参数,argc2为中间量的返回参数类型,一般用于耗时操作进度的记录,argc3doBack()的返回值类型,AsyncTask<String,Void,JSONArray>

表示传入一个String类型的数据,不反回中间值,doBack()返回一个json数组,用 new MyAsyncTask().excute(传入参数) 启动异步线程。

 

转载于:https://www.cnblogs.com/jaychen/p/6749134.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值