anr产生的原理&如何避免
ANR : application not response 应用程序无响应
ANR产生的原因 :
主线程需要做很多重要的事情,如响应点击事件,更新ui
如果在主线程里边阻塞过久的时间,应用程序就会无响应
为了避免出现ANR,所有耗时的操作都应该放在子线程里边执行
public void watch(View view) {
final String path = this.et_path.getText().toString().trim();
if (TextUtils.isEmpty(path)) {
Toast.makeText(this, "路径不能为空", 0).show();
} else {
new Thread() {
@Override
public void run() {
try {
URL url = new URL(path);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
// 设置请求方式
connection.setRequestMethod("GET");
// 设置超时时间
connection.setConnectTimeout(10000);
// connection.setRequestProperty(field, newValue)
int code = connection.getResponseCode();
if (code == 200) {
InputStream is = connection.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(is);
iv_beauty.setImageBitmap(bitmap);
} else {
Toast.makeText(MainActivity.this, "获取图片失败", 0).show();
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(MainActivity.this, "读取图片失败", 0).show();
}
}
}.start();
}
}
此时程序有抛出了异常:
android.view.ViewRootImpl$CalledFromWrongThreadException:
Only the original thread that created a view hierarchy can touch its views.
说白了,谁创建的view对象,谁才能动它
在安卓系统中,只有主线程才能修改veiw对象
内部实现:更改界面的时候做一个检查,检查这个更新操作是否在主线程的代码执行的,
如果是,没有任何问题
不过不是,立刻抛出一个运行时异常 ViewRootImpl$CalledFromWrongThreadException
通过消息机制来解决这个问题
android消息机制入门
public class MainActivity extends Activity {
protected static final int UPDATE_UI = 1;
protected static final int ERROR = 2;
private ImageView iv_beauty;
private EditText et_path;
// 主线程创建消息处理器
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if(msg.what == UPDATE_UI) {
iv_beauty.setImageBitmap((Bitmap)msg.obj);
} else {
Toast.makeText(getApplicationContext(), "图片获取失败!", 0).show();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.iv_beauty = (ImageView) this.findViewById(R.id.iv_beauty);
this.et_path = (EditText) this.findViewById(R.id.et_path);
}
public void watch(View view) {
final String path = this.et_path.getText().toString().trim();
if (TextUtils.isEmpty(path)) {
Toast.makeText(this, "路径不能为空", 0).show();
} else {
new Thread() {
@Override
public void run() {
try {
URL url = new URL(path);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
// 设置请求方式
connection.setRequestMethod("GET");
// 设置超时时间
connection.setConnectTimeout(10000);
// connection.setRequestProperty(field, newValue)
int code = connection.getResponseCode();
if (code == 200) {
InputStream is = connection.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(is);
// 告诉主线程一个消息,帮我更新ui,内容:bitmap
Message msg = new Message();
msg.what = UPDATE_UI;
msg.obj = bitmap;
handler.sendMessage(msg);
} else {
Message msg = new Message();
msg.what = ERROR;
handler.sendMessage(msg);
}
} catch (Exception e) {
e.printStackTrace();
Message msg = new Message();
msg.what = ERROR;
handler.sendMessage(msg);
}
}
}.start();
}
}
}
提交数据到服务器
1.布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<EditText
android:id="@+id/et_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入用户名" />
<EditText
android:id="@+id/et_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入密码"
android:inputType="textPassword" />
<Button
android:onClick="get"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="get请求登录" />
<Button
android:onClick="post"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="post请求登录" />
<Button
android:onClick="clientGet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="client get请求登录" />
<Button
android:onClick="clientPost"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="client post请求登录" />
</LinearLayout>
2.Activity
public class MainActivity extends Activity {
private EditText et_userName;
private EditText et_password;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.et_userName = (EditText) this.findViewById(R.id.et_username);
this.et_password = (EditText) this.findViewById(R.id.et_password);
}
public void get(View view) {
final String userName = this.et_userName.getText().toString().trim();
final String password = this.et_password.getText().toString().trim();
new Thread() {
public void run() {
final String result = LoginService.loginByGet(userName,
password);
if (result != null) {
/*
* Runs the specified action on the UI thread. If the
* current thread is the UI thread, then the action is
* executed immediately. If the current thread is not the UI
* thread, the action is posted to the event queue of the UI
* thread.
*/
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, result, 0).show();
}
});
} else {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "请求失败。。。。", 0)
.show();
}
});
}
};
}.start();
}
public void post(View view) {
final String userName = this.et_userName.getText().toString().trim();
final String password = this.et_password.getText().toString().trim();
new Thread() {
public void run() {
final String result = LoginService.loginByPost(userName,
password);
if (result != null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, result, 0).show();
}
});
} else {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "请求失败。。。。", 0)
.show();
}
});
}
};
}.start();
}
public void clientGet(View view) {
final String userName = this.et_userName.getText().toString().trim();
final String password = this.et_password.getText().toString().trim();
new Thread() {
public void run() {
final String result = LoginService.loginByClientGet(userName,
password);
if (result != null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, result, 0).show();
}
});
} else {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "请求失败。。。。", 0)
.show();
}
});
}
};
}.start();
}
public void clientPost(View view) {
final String userName = this.et_userName.getText().toString().trim();
final String password = this.et_password.getText().toString().trim();
new Thread() {
public void run() {
final String result = LoginService.loginByClientPost(userName,
password);
if (result != null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, result, 0).show();
}
});
} else {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "请求失败。。。。", 0)
.show();
}
});
}
};
}.start();
}
}
3.业务类
public class LoginService {
/*
* 采用get方式请求
*/
public static String loginByGet(String userName, String password) {
try {
String path = "http://110.65.99.66:8080/androidserver/WebServlet?userName="
+ URLEncoder.encode(userName, "UTF-8")
+ "&password="
+ URLEncoder.encode(password, "UTF-8");
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
int code = conn.getResponseCode();
if (code == 200) {
InputStream is = conn.getInputStream();
String result = StreamTool.readInputStream(is);
is.close();
return result;
} else {
return null;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/*
* 采用post方式
*/
public static String loginByPost(String userName, String password) {
String path = "http://110.65.99.66:8080/androidserver/WebServlet";
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setReadTimeout(5000);
String params = "userName=" + URLEncoder.encode(userName, "UTF-8")
+ "&password=" + URLEncoder.encode(password, "UTF-8");
// 设置请求
/**
* application/x-www-form-urlencoded 普通表单数据提交方式 multipart/form-data
* 文件上传 text/plain 原始文本数据
*/
conn.setRequestProperty("content-type",
"application/x-www-form-urlencoded");
conn.setRequestProperty("content-length", params.length() + "");
conn.setDoOutput(true);
OutputStream outputStream = conn.getOutputStream();
outputStream.write(params.getBytes());
int code = conn.getResponseCode();
if (code == 200) {
InputStream is = conn.getInputStream();
String result = StreamTool.readInputStream(is);
is.close();
return result;
} else {
return null;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/*
* 采用HttpGet方式
*/
public static String loginByClientGet(String userName, String password) {
try {
// 1.打开浏览器
HttpClient client = new DefaultHttpClient();
// 2.输入网址
String path = "http://110.65.99.66:8080/androidserver/WebServlet?userName="
+ userName + "&password=" + password;
HttpGet httpGet = new HttpGet(path);
// 3.敲回车
HttpResponse response = client.execute(httpGet);
int code = response.getStatusLine().getStatusCode();
if (code == 200) {
InputStream is = response.getEntity().getContent();
String result = StreamTool.readInputStream(is);
is.close();
return result;
} else {
return null;
}
} catch (Exception e) {
// TODO: handle exception
}
return null;
}
/*
* 采用HttpPost方式
*/
public static String loginByClientPost(String userName, String password) {
try {
// 1.打开浏览器
HttpClient client = new DefaultHttpClient();
// 2.输入网址
String path = "http://110.65.99.66:8080/androidserver/WebServlet";
HttpPost httpPost = new HttpPost(path);
// 3.设置参数
ArrayList<NameValuePair> parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("userName", userName));
parameters.add(new BasicNameValuePair("password", password));
httpPost.setEntity(new UrlEncodedFormEntity(parameters, "utf-8"));
// 4.敲回车
HttpResponse response = client.execute(httpPost);
int code = response.getStatusLine().getStatusCode();
if (code == 200) {
InputStream is = response.getEntity().getContent();
String result = StreamTool.readInputStream(is);
is.close();
return result;
} else {
return null;
}
} catch (Exception e) {
// TODO: handle exception
}
return null;
}
}