目录
第一节:网络操作
一、获取网络数据
获取数据步骤:
1、实例化URL对象。
2、获取HttpUrlConnection对象。
3、设置请求连接属性。
4、获取响应码、判断连接结果码。
connection.setReadTimeout(5000);
connection.setRequestMethod("GET");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Charset", "UTF-8");
connection.setRequestProperty("Accept-Charset", "UTF-8");
5、读取输入流并解析。
注意事项:
1、网络操作需要在子线程中进行。
2、需要获取网络权限。
<uses-permission android:name="android.permission.INTERNET"/>
3、子线程不能直接更新UI线程控件数据。
runOnUiThread(new Runnable() {
@Override
public void run() {
mTvShowData.setText(mResult);
}
});
获取数据代码
URL url=new URL(str);//str为网址
HttpURLConnection connection= (HttpURLConnection) url.openConnection();
connection.setReadTimeout(5000);
connection.setRequestMethod("GET");
if(connection.getResponseCode()==200){
InputStream inputStream=connection.getInputStream();
byte[] bytes=new byte[1024];
int len=0;
ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
while((len=inputStream.read(bytes))!=-1) {
outputStream.write(bytes,0,len);
}
result=outputStream.toString();
inputStream.close();
outputStream.close();
return result;
}
5、检查网络连接
1) ConnectivityManager:它会回答关于网络连接的查询结果,并在网络连接改变时通知应用程序。
2) NetworkInfo:描述一个给定类型(移动网络或 Wi-Fi 等)的网络接口状态。下面这个方法可以找到的第一个已连接的网络接口,如果返回 null,则表示没有已连接的网络接口(意味着网络连接不可用):
public boolean isOnline(){
ConnectivityManager connMgr=(ConnectivityManager)getSystemServic(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo=connMgr.getActiveNetworkInfo();
return (networkInfo!=null && networkInfo.isConnected());
}
二、解析JSON数据
1、使用Json解析
1、使用json类型字符串创建JSONObject数据。
2、[]中的数据使用getJSONArray获取。
3、使用getInt、getString等获取json中的数据。
JSONObject obj=new JSONObject(mResult);
JSONArray datas=obj.getJSONArray("data");
StringBuilder builder=new StringBuilder();
for (int i = 0; i < datas.length(); i++) {
JSONObject data=datas.getJSONObject(i);
int id=data.getInt("id");
String name=data.getString("name");
String description=data.getString("description");
builder.append("编号:"+id+"\n");
builder.append("名称:"+name+"\n");
builder.append("描述:"+description+"\n");
}
mTvShowData.setText(builder.toString());
2、使用Gson解析
1、导入gson依赖包。
2、创建json数据对应的类,成员名称必须相同。
3、可以使用嵌套、可以获取数组。
public class Essay {
int id;
String name;
String picSmall;
String picBig;
String description;
int learner;
//getter & setter 省略
}
public class Chapter{
int status;
List<Essay> data;
String msg;
//getter & setter 省略
}
//使用Gson解析
Gson gson=new Gson();
Chapter chapter=gson.fromJson(jsonString, Chapter.class);
List<Essay> datas=chapter.getData();
StringBuilder builder=new StringBuilder();
for (int i = 0; i < datas.size(); i++) {
Essay data=datas.get(i);
builder.append("编号:"+data.getId()+"\n");
builder.append("名称:"+data.getName()+"\n");
builder.append("描述:"+data.getDescription()+"\n");
}
mTvShowData.setText(builder.toString());
*注:上面代码中成员变量也可以随意命名,然后通过注解实现json数据同名
public class Essay {
@SerializedName("id")
int mId;
@SerializedName("name")
String mName;
@SerializedName("picSmall")
String mPicSmall;
@SerializedName("picBig")
String mPicBig;
@SerializedName("description")
String mDescription;
@SerializedName("learner")
int mLearner;
//getter & setter 省略
}
public class Chapter{
@SerializedName("status")
int mStatus;
@SerializedName("data")
List<Essay> mData;
@SerializedName("msg")
String mMsg;
//getter & setter 省略
}
GsonFormat插件的使用
GsonFormat插件可以快速生成json数据的实体类。
1、Settings->plugins->marketplace 搜索GsonFormat,下载然后重启AS
2、新建一个类,名字随意,在代码中使用快捷键Alt+insert调出菜单 选择GsonFormat ,粘贴json数据,next。。。
第二节:Handler通信
一、handler功能
主要用于异步消息的处理,包括发送消息和处理消息两部分。发送消息函数将消息发送到队列中,处理消息函数从队列中取出消息执行,这个过程是异步执行的,适合处理耗时较长的操作。
二、handler常用方法和属性
boolean handler.post(Runnable r)
boolean handler.postDelay(Runnable r,long delayMillis)
boolean handler.sendMessage(Message msg)
boolean handler.sendMessageDelay(Message msg,long delayMillis)
void handler.handlerMessage(Message msg) // 处理消息
void handler.removeCallbacks(Runnable r);
Message handler.obtainMessage();//获取消息,内部调用的是Message.obtain()
三、Message的方法与属性
Message Message.obtain();//获取消息
Message.what //int
Message.obj //object
Message.arg1 //int
Message.arg2 //int
四、handler的使用
1、更新UI线程。
Android中为了保证UI线程安全,所有子线程不允许直接更新UI,所有的UI操作都要通过Handler传递消息到主线程,由主线程按照消息队列顺序轮流执行UI操作。
注:runOnUiThread(Runnable r) 也是用来更新UI操作,内部机制与hanlder相同。如果方法在UI线程中调用则立即执行,在子线程调用则向消息队列发送消息,等待主线程处理。
2、延时执行某一操作。
闪屏页的实现,通过handler.postDelay(Runnable r,long delayMillis)方法延迟启动主界面。
五、关于handler的内存泄漏
原理:
Java中一个对象不被任何引用所指向,则该对象会在被GC发现的时候会被回收。创建Handler的时候,Handler对象会隐式地持有一个外部类对象(通常是一个Activity)的引用(用来更新UI)。handler通常用来执行耗时操作,如果在这个过程中用户关闭了Activity,由于这个Activity持有handler的引用,会导致Activity无法被回收(内存泄漏)。
危害:
使程序占用内存过高,内存溢出,程序报错,如果反复运行程序会导致Android内存使用超过系统限制。
解决办法:
方法一:通过程序逻辑来进行保护。
1.在关闭Activity的时候停掉你的后台线程。线程停掉了,就相当于切断了Handler和外部连接的线,Activity自然会在合适的时候被回收。
2.如果你的Handler是被delay的Message持有了引用,那么使用相应的Handler的removeCallbacks()方法,把消息对象从消息队列移除就行了。
方法二:将Handler声明为静态类。
PS:在Java 中,非静态的内部类和匿名内部类都会隐式地持有其外部类的引用,静态的内部类不会持有外部类的引用。
静态类不持有外部类的对象,所以你的Activity可以随意被回收。由于Handler不再持有外部类对象的引用,导致程序不允许你在Handler中操作Activity中的对象了。所以你需要在Handler中增加一个对Activity的弱引用(WeakReference)。
第三节:AsyncTask通信
AsyncTask,即异步任务,是Android给我们提供的一个处理异步任务的类.通过此类,可以实现UI线程和后台线程进行通讯,后台线程执行异步任务,并把结果返回给UI线程.
AsyncTask子类的泛型参数
AsyncTask<Params,Progress,Result>是一个抽象类,通常用于被继承.继承AsyncTask需要指定如下三个泛型参数:
Params:启动任务时输入的参数类型
Progress:后台任务执行中返回进度值的类型
Result:后台任务执行完成后返回结果的类型
AsyncTask子类的回调方法
Result doInBackground(Params p):必须重写,异步执行后台线程要完成的任务,耗时操作将在此方法中完成。参数p为泛型的第一个参数,实例化AsyncTask类后,由execute(Params p)方法传入;返回值为泛型的第三个参数类型。
void onPreExecute():执行后台耗时操作前被调用,通常用于进行初始化操作。
void onPostExecute(Result r):当doInBackground方法完成后,系统将自动调用此方法,并将doInBackground方法返回的值传入此方法.通过此方法进行UI的更新。
void onProgressUpdate(Progress p):当在doInBackground方法中调用publishProgress(p)方法更新任务执行进度后,将调用此方法.通过此方法我们可以知晓任务的完成进度。
第四节:ListView展示列表数据
一、使用ListView获取应用程序列表
1、在Layout中创建ListView并在代码中获取对象。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<ListView
android:id="@+id/appinfo_lv"
android:layout_width="match_parent"
android:layout_height="wrap_content"></ListView>
</LinearLayout>
mLvAppInfo = findViewById(R.id.appinfo_lv);
2、创建每一行的Layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/im_item"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@mipmap/icon01"/>
<TextView
android:id="@+id/tv_item"
android:gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:text="第一个图标"/>
</LinearLayout>
3、创建每一行的数据
private List<ResolveInfo> mAppInfos = getAppInfos();
/**
* 获取所有的应用信息的方法
* @return
*/
private List<ResolveInfo> getAppInfos(){
Intent intent=new Intent(Intent.ACTION_MAIN,null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
return getPackageManager().queryIntentActivities(intent,0);
}
4、用adapter将数据填充到每一行的视图中
//自定义适配器
public class ListAdapter extends BaseAdapter {
//private List<String> mAppNames;
private List<ResolveInfo> mAppInfos;
public ListAdapter(List<ResolveInfo> appInfos) {
//mAppNames = appNames;
mAppInfos=appInfos;
}
@Override
public int getCount() {
return mAppInfos.size();
}
@Override
public Object getItem(int i) {
return mAppInfos.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(final int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder=new ViewHolder();
if(view==null) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.item_list_view, null);
viewHolder.mTextView=view.findViewById(R.id.tv_item);
viewHolder.mImageView=view.findViewById(R.id.im_item);
view.setTag(viewHolder);
}else{
viewHolder= (ViewHolder) view.getTag();
}
viewHolder.mTextView.setText(mAppInfos.get(i).activityInfo.loadLabel(getPackageManager()));
viewHolder.mImageView.setImageDrawable(mAppInfos.get(i).activityInfo.loadIcon(getPackageManager()));
//点击事件
viewHolder.mTextView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
/*String packageName=mAppInfos.get(i).activityInfo.packageName;
String className=mAppInfos.get(i).activityInfo.name;
ComponentName componentName=new ComponentName(packageName,className);
Intent intent=new Intent();
intent.setComponent(componentName);
startActivity(intent);*/
}
});
return view;
}
public class ViewHolder{
TextView mTextView;
ImageView mImageView;
}
}
5、为ListView添加HeaderView
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@mipmap/icon01"/>
</LinearLayout>
LayoutInflater inflater=getLayoutInflater();
//LayoutInflater inflater1=LayoutInflater.from(this);
View view=inflater.inflate(R.layout.header_list_view,null);
mLvAppInfo.addHeaderView(view);
二、ListView实现隔行效果
当一个ListView中包含多种样式的item时,比如聊天列表中发送和接收的item应该设计成两种不同样式,如果聊天包含发送图片功能还应该增加样式,这种情况应该使用适配器的getViewTypeCount和getItemViewType两个方法解决。
getViewTypeCount 返回样式的个数。如包含发送消息、接收消息、发送图片、接受图片四种样式,则此处代码return 4;
getItemViewType 返回样式的序号。使用时根据数据项中的内容返回不同的整数(从0开始),然后在getView中通过switch(getItemViewType(position))来分别加载不同的布局。
public class ChatAdapter extends BaseAdapter {
private List<ChatMessage> mChatMessageList;
private LayoutInflater mInflater;
public ChatAdapter(Context context, List<ChatMessage> chatMessageList) {
mChatMessageList = chatMessageList;
mInflater=LayoutInflater.from(context);
}
@Override
public int getCount() {
return mChatMessageList.size();
}
@Override
public Object getItem(int position) {
return mChatMessageList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder=null;
ChatMessage chatMessage=mChatMessageList.get(position);
int viewType = getItemViewType(position);
if(convertView==null){
switch (viewType){
case IMessageViewType.COM_MESSAGE:
convertView = mInflater.inflate(R.layout.chatting_item_msg_text_left, null);
break;
case IMessageViewType.TO_MESSAGE:
convertView = mInflater.inflate(R.layout.chatting_item_msg_text_right, null);
break;
}
holder=new ViewHolder();
holder.mIcon=convertView.findViewById(R.id.icon_iv);
holder.mName=convertView.findViewById(R.id.name_tv);
holder.mContent=convertView.findViewById(R.id.content_tv);
holder.mTime=convertView.findViewById(R.id.time_tv);
convertView.setTag(holder);
}else{
holder= (ViewHolder) convertView.getTag();
}
holder.mTime.setText(chatMessage.getDate());
if(chatMessage.isComeMessage()){
holder.mIcon.setImageResource(R.mipmap.girl_icon);
}else{
holder.mIcon.setImageResource(R.mipmap.boy_icon);
}
holder.mName.setText(chatMessage.getName());
holder.mContent.setText(chatMessage.getContent());
return convertView;
}
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getItemViewType(int position) {
ChatMessage chatMessage=mChatMessageList.get(position);
return chatMessage.isComeMessage()?IMessageViewType.TO_MESSAGE:IMessageViewType.COM_MESSAGE;
}
interface IMessageViewType{
int COM_MESSAGE = 0;
int TO_MESSAGE = 1;
}
class ViewHolder{
ImageView mIcon;
TextView mTime;
TextView mName;
TextView mContent;
}
}
第五节:GridView实现九宫格
一、GridView常用属性
android:columnWidth="90dp" 每一列的宽度
android:numColumns="4 | auto_fit" 列宽 auto_fit(列数根据屏幕大小自适应)
android:verticalSpacing="10dp" 垂直方向的间距
android:horizontalSpacing="10dp" 水平方向的间距
android:stretchMode = "columnWidth | spacingWidth" 屏幕两侧剩余宽度平均分配给列宽(columnWidth)或者间距(spacingWidth)
二、ArrayAdapter适配器
使用ArrayAdapter将文字显示成九宫格形式
List<String> strList=new ArrayList<String>();
for(int i=0;i<3;i++){
strList.add("测试"+i);
}
ArrayAdapter<String> arrayAdapter=new ArrayList<String>(this,android.R.layout.simple_list_item_1,strList);
mGridView.setAdapter(arrayAdapter);
三、使用GridView显示应用程序信息
public List<AppInfo> getAppList(){
List<AppInfo> appInfoList=new ArrayList<AppInfo>();
PackageManager packageManager=getPackageManager();
List<PackageInfo> installedPackages = packageManager.getInstalledPackages(0);
for (int i = 0; i < installedPackages.size(); i++) {
PackageInfo packageInfo=installedPackages.get(i);
AppInfo appInfo=new AppInfo();
appInfo.setAppIcon(packageInfo.applicationInfo.loadIcon(packageManager));
appInfo.setAppName(packageInfo.applicationInfo.loadLabel(packageManager).toString());
appInfo.setPackageName(packageInfo.packageName);
if((packageInfo.applicationInfo.flags& ApplicationInfo.FLAG_SYSTEM)==0)
{
appInfoList.add(appInfo);
}
}
return appInfoList;
}
//初始化数据
List<AppInfo> appInfoList=getAppList();
AppInfoAdapter adapter=new AppInfoAdapter(this,appInfoList);
mGridView.setAdapter(adapter);
public class AppInfoAdapter extends BaseAdapter {
private Context mContext;
private List<AppInfo> mAppInfoList;
public AppInfoAdapter(Context context, List<AppInfo> appInfoList) {
mContext = context;
mAppInfoList = appInfoList;
}
@Override
public int getCount() {
return mAppInfoList.size();
}
@Override
public Object getItem(int i) {
return mAppInfoList.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder;
if(view==null){
view=View.inflate(mContext, R.layout.item_grid_appinfo,null);
holder=new ViewHolder();
holder.mAppIcon=view.findViewById(R.id.appicon_iv);
holder.mAppName=view.findViewById(R.id.appname_tv);
holder.mPackageName=view.findViewById(R.id.pkname_tv);
view.setTag(holder);
}else{
holder= (ViewHolder) view.getTag();
}
AppInfo appInfo=mAppInfoList.get(i);
holder.mAppIcon.setImageDrawable(appInfo.getAppIcon());
holder.mAppName.setText(appInfo.getAppName());
holder.mPackageName.setText(appInfo.getPackageName());
return view;
}
private class ViewHolder{
ImageView mAppIcon;
TextView mAppName;
TextView mPackageName;
}
}
public class AppInfo {
private String appName;
private String packageName;
private Drawable appIcon;
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public Drawable getAppIcon() {
return appIcon;
}
public void setAppIcon(Drawable appIcon) {
this.appIcon = appIcon;
}
}
四、使用GridView显示网络图片
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_grid_net_image);
//初始化控件
mGridView = findViewById(R.id.grid_netimage_gv);
//初始化数据
List<String> mImgList = new ArrayList<>();
mImgList.add("http://img5.duitang.com/uploads/item/201406/26/20140626164837_dzKds.jpeg");
mImgList.add("http://img2.imgtn.bdimg.com/it/u=3980629563,3881837630&fm=21&gp=0.jpg");
mImgList.add("http://img5q.duitang.com/uploads/item/201505/08/20150508155052_XJaNW.jpeg");
mImgList.add("http://img4.duitang.com/uploads/item/201407/02/20140702105736_FdN5P.jpeg");
mImgList.add("http://img2.imgtn.bdimg.com/it/u=2866652161,3841912673&fm=21&gp=0.jpg");
mImgList.add("http://img4.imgtn.bdimg.com/it/u=883757693,2063816225&fm=21&gp=0.jpg");
mImgList.add("http://cdn.duitang.com/uploads/item/201309/26/20130926110955_QtUdX.jpeg");
mImgList.add("http://zjimg.5054399.com/allimg/160815/14_160815161625_9.jpg");
mImgList.add("http://i-7.vcimg.com/trim/09ce7067d2467c54cf05bbd271ee3ec8430415/trim.jpg");
mImageInfos = new ArrayList<>();
for (int i = 0; i < mImgList.size(); i++) {
ImageInfo imageInfo=new ImageInfo();
imageInfo.setImagePath(mImgList.get(i));
imageInfo.setName("图片"+i);
mImageInfos.add(imageInfo);
}
ImageAdapter adapter=new ImageAdapter(this,mImageInfos);
mGridView.setAdapter(adapter);
}
public class ImageAdapter extends BaseAdapter {
private Context mContext;
private List<ImageInfo> mImageInfoList;
public ImageAdapter(Context context, List<ImageInfo> imageInfoList) {
mContext = context;
mImageInfoList = imageInfoList;
}
@Override
public int getCount() {
return mImageInfoList.size();
}
@Override
public Object getItem(int i) {
return mImageInfoList.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder;
if(view==null){
holder=new ViewHolder();
view=View.inflate(mContext, R.layout.item_grid_image,null);
holder.mImageView=view.findViewById(R.id.image_iv);
holder.mTextView=view.findViewById(R.id.text_tv);
view.setTag(holder);
}else{
holder= (ViewHolder) view.getTag();
}
ImageInfo imageInfo=mImageInfoList.get(i);
holder.mTextView.setText(imageInfo.getName());
//RequestOptions options=new RequestOptions();
Glide.with(mContext).load(imageInfo.getImagePath()).into(holder.mImageView);
return view;
}
private class ViewHolder{
ImageView mImageView;
TextView mTextView;
}
}
public class ImageInfo {
private String mImagePath;
private String mName;
public String getImagePath() {
return mImagePath;
}
public void setImagePath(String imagePath) {
mImagePath = imagePath;
}
public String getName() {
return mName;
}
public void setName(String name) {
mName = name;
}
}
第六节:CardView实现卡片布局效果
一、CardView是什么?
1、Android 5.0 之后新增
2、android support v7包 独立引入
3、继承自FrameLayout,方便作为其他控件容器,添加3D阴影和圆角效果
二、CardView常用属性
1、cardBackgroundColor 设置背景颜色
2、cardCornerRadius 设置圆角半径
3、contentPadding 设置内部padding
4、cardElevation 设置阴影大小
5、cardUseCompatPadding 默认为false,用于5.0及以上,true则添加额外padding绘制阴影
6、cardPreventCornerOverlap 默认为true,用于5.0以下,添加额外的padding,防止内容和圆角重叠
三、一个简单的案例
使用前需要导包,搜索cardview
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardBackgroundColor="#44ff0000"
app:cardCornerRadius="10dp"
app:cardElevation="10dp"
android:layout_gravity="center">
<TextView
android:layout_width="200dp"
android:layout_height="50dp"
android:text="Hello World!"
android:gravity="center" />
</android.support.v7.widget.CardView>
</FrameLayout>