ksoap2下载地址:http://simpligility.github.io/ksoap2-android/getting-started.html下载之后放在:特别注意放到这个目录之后要做两步:1、添加依赖,网上有说用compile的,然而实际上compile过时了,改成implementation即可2、要右键点击这个jar包,在选项卡最下面有一个AddAsLibrary,这一步很关键,我之前就是这一步没做,一直无法识别这个库。---------------------------------------------------------------------编译时候发现,做了第二步会直接在gradle文件里加入依赖,所以根本不需要第一步自己添加。
if(ContextCompat.checkSelfPermission(this,android.Manifest.permission.ACCESS_FINE_LOCATION)==PackageManager.PERMISSION_GRANTED||ContextCompat.checkSelfPermission(this,android.Manifest.permission.ACCESS_COARSE_LOCATION)==PackageManager.PERMISSION_GRANTED){lm=(LocationManager)getSystemService(Context.LOCATION_SERVICE);}lm=(LocationManager)getSystemService(Context.LOCATION_SERVICE);这句话放在这个if语句就可以
1、线程相关概念1)相关概念:程序:为了完成特定任务,用某种语言编写的一组指令集合(一组静态代码)进程:运行中的程序,系统调度与资源分配的一个独立单位,操作系统会为每个进程分配一段内存空间!程序的依次动态执行,经历代码的加载,执行,执行完毕的完整过程!线程:比进程更小的执行单元,每个进程可能有多条线程,线程需要放在一个进程中才能执行,线程由程序负责管理,而进程则由系统进行调度!多线程的理解:并行执行多个条指令,将CPU时间片按照调度算法分配给各个线程,实际上是分时执行的,只是这个切换的时间很短,用户感觉到"同时"而已!2)线程的生命周期:3)创建线程的三种方式:继承Thread类实现Runnable接口实现Callable接口如果:使用的是2创建的线程的话,可以直接这样启动:newThread(myThread).start();当更多的时候我们喜欢使用匿名类,即下面这种写法:newThread(newRunnable(){publicvoidrun();}).start();2.Service的生命周期图3.生命周期解析好的,从上图的生命周期,我们可以知道,Android中使用Service的方式有两种:1)StartService()启动Service2)BindService()启动ServicePS:还有一种,就是启动Service后,绑定Service!1)相关方法详解:onCreate():当Service第一次被创建后立即回调该方法,该方法在整个生命周期中只会调用一次!onDestory():当Service被关闭时会回调该方法,该方法只会回调一次!onStartCommand(intent,flag,startId):早期版本是onStart(intent,startId),当客户端调用startService(Intent)方法时会回调,可多次调用StartService方法,但不会再创建新的Service对象,而是继续复用前面产生的Service对象,但会继续回调onStartCommand()方法!IBinderonOnbind(intent):该方法是Service都必须实现的方法,该方法会返回一个IBinder对象,app通过该对象与Service组件进行通信!onUnbind(intent):当该Service上绑定的所有客户端都断开时会回调该方法!2)StartService启动Service①首次启动会创建一个Service实例,依次调用onCreate()和onStartCommand()方法,此时Service进入运行状态,如果再次调用StartService启动Service,将不会再创建新的Service对象,系统会直接复用前面创建的Service对象,调用它的onStartCommand()方法!②但这样的Service与它的调用者无必然的联系,就是说当调用者结束了自己的生命周期,但是只要不调用stopService,那么Service还是会继续运行的!③无论启动了多少次Service,只需调用一次StopService即可停掉Service3)BindService启动Service①当首次使用bindService绑定一个Service时,系统会实例化一个Service实例,并调用其onCreate()和onBind()方法,然后调用者就可以通过IBinder和Service进行交互了,此后如果再次使用bindService绑定Service,系统不会创建新的Sevice实例,也不会再调用onBind()方法,只会直接把IBinder对象传递给其他后来增加的客户端!②如果我们解除与服务的绑定,只需调用unbindService(),此时onUnbind和onDestory方法将会被调用!这是一个客户端的情况,假如是多个客户端绑定同一个Service的话,情况如下当一个客户完成和service之间的互动后,它调用unbindService()方法来解除绑定。当所有的客户端都和service解除绑定后,系统会销毁service。(除非service也被startService()方法开启)③另外,和上面那张情况不同,bindService模式下的Service是与调用者相互关联的,可以理解为"一条绳子上的蚂蚱",要死一起死,在bindService后,一旦调用者销毁,那么Service也立即终止!通过BindService调用Service时调用的Context的bindService的解析bindService(IntentService,ServiceConnectionconn,intflags)service:通过该intent指定要启动的Serviceconn:ServiceConnection对象,用户监听访问者与Service间的连接情况,连接成功回调该对象中的onServiceConnected(ComponentName,IBinder)方法;如果Service所在的宿主由于异常终止或者其他原因终止,导致Service与访问者间断开连接时调用onServiceDisconnected(CompanentName)方法,主动通过unBindService()方法断开并不会调用上述方法!flags:指定绑定时是否自动创建Service(如果Service还未创建),参数可以是0(不自动创建),BIND_AUTO_CREATE(自动创建)4)StartService启动Service后bindService绑定如果Service已经由某个客户端通过StartService()启动,接下来由其他客户端再调用bindService()绑定到该Service后调用unbindService()解除绑定最后在调用bindService()绑定到Service的话,此时所触发的生命周期方法如下:onCreate()->onStartCommand()->onBind()->onUnbind()->onRebind()PS:前提是:onUnbind()方法返回true!!!这里或许部分读者有疑惑了,调用了unbindService后Service不是应该调用onDistory()方法么!其实这是因为这个Service是由我们的StartService来启动的,所以你调用onUnbind()方法取消绑定,Service也是不会终止的!得出的结论:假如我们使用bindService来绑定一个启动的Service,注意是已经启动的Service!!!系统只是将Service的内部IBinder对象传递给Activity,并不会将Service的生命周期与Activity绑定,因此调用unBindService()方法取消绑定时,Service也不会被销毁!onCreate():当Service第一次被创建后立即回调该方法,该方法在整个生命周期中只会调用一次!onDestory():当Service被关闭时会回调该方法,该方法只会回调一次!onStartCommand(intent,flag,startId):早期版本是onStart(intent,startId),当客户端调用startService(Intent)方法时会回调,可多次调用StartService方法,但不会再创建新的Service对象,而是继续复用前面产生的Service对象,但会继续回调onStartCommand()方法!IBinderonOnbind(intent):该方法是Service都必须实现的方法,该方法会返回一个IBinder对象,app通过该对象与Service组件进行通信!onUnbind(intent):当该Service上绑定的所有客户端都断开时会回调该方法!5)IntentService如果是大量耗时的service则使用intentService()4、IBundlerIBinder是Android给我们提供的一个进程间通信的一个接口,而我们一般是不直接实现这个接口的,而是通过继承Binder类来实现进程间通信!是Android中实现IPC(进程间通信)的一种方式!1)Binder机制浅析Android中的Binder机制由一系列系统组件构成:Client、Server、ServiceManager和Binder驱动程序大概调用流程如下,另外ServiceManager比较复杂,这里并不详细研究!流程解析:->Client调用某个代理接口中的方法时,代理接口的方法会将Client传递的参数打包成Parcel对象;->然后代理接口把该Parcel对象发送给内核中的Binderdriver;;->然后Server会读取BinderDriver中的请求数据,假如是发送给自己的,解包Parcel对象,处理并将结果返回;PS:代理接口中的定义的方法和Server中定义的方法是一一对应的,另外,整个调用过程是一个同步的,即Server在处理时,Client会被Block(锁)住!而这里说的代理接口的定义就是等下要说的AIDL(Android接口描述语言)!3)为何Android使用Binder机制来实现进程间的通信?可靠性:在移动设备上,通常采用基于Client-Server的通信方式来实现互联网与设备间的内部通信。目前linux支持IPC包括传统的管道,SystemVIPC,即消息队列/共享内存/信号量,以及socket中只有socket支持Client-Server的通信方式。Android系统为开发者提供了丰富进程间通信的功能接口,媒体播放,传感器,无线传输。这些功能都由不同的server来管理。开发都只关心将自己应用程序的client与server的通信建立起来便可以使用这个服务。毫无疑问,如若在底层架设一套协议来实现Client-Server通信,增加了系统的复杂性。在资源有限的手机上来实现这种复杂的环境,可靠性难以保证。传输性能:socket主要用于跨网络的进程间通信和本机上进程间的通信,但传输效率低,开销大。消息队列和管道采用存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的一块缓存区中,然后从内核缓存区拷贝到接收方缓存区,其过程至少有两次拷贝。虽然共享内存无需拷贝,但控制复杂。比较各种IPC方式的数据拷贝次数。共享内存:0次。Binder:1次。Socket/管道/消息队列:2次。安全性:Android是一个开放式的平台,所以确保应用程序安全是很重要的。Android对每一个安装应用都分配了UID/PID,其中进程的UID是可用来鉴别进程身份。传统的只能由用户在数据包里填写UID/PID,这样不可靠,容易被恶意程序利用。而我们要求由内核来添加可靠的UID。所以,出于可靠性、传输性、安全性。android建立了一套新的进程间通信方式。——摘自:Android中的Binder机制的简要理解当然,作为一个初级的开发者我们并不关心上述这些,Binder机制给我们带来的最直接的好处就是:我们无需关心底层如何实现,只需按照AIDL的规则,自定义一个接口文件,然后调用调用接口中的方法,就可以完成两个进程间的通信了!3).AIDL使用详解AIDL是什么?嘿嘿,前面我们讲到IPC这个名词,他的全名叫做:跨进程通信(interprocesscommunication),因为在Android系统中,个个应用程序都运行在自己的进程中,进程之间一般是无法直接进行数据交换的,而为了实现跨进程,Android给我们提供了上面说的Binder机制,而这个机制使用的接口语言就是:AIDL(AndroidInterfaceDefinitionLanguage),他的语法很简单,而这种接口语言并非真正的编程语言,只是定义两个进程间的通信接口而已!而生成符合通信协议的Java代码则是由AndroidSDK的platform-tools目录下的aidl.exe工具生成,生成对应的接口文件在:gen目录下,一般是:Xxx.java的接口!而在该接口中包含一个Stub的内部类,该类中实现了在该类中实现了IBinder接口与自定义的通信接口,这个类将会作为远程Service的回调类——实现了IBinder接口,所以可作为Service的onBind()方法的返回值!AIDL实现两个进程间的简单通信(没写)4)BroadcastReceiver两种广播类型接收系统广播1)两种注册广播的方式前面也讲了,系统在某些时候会发送相应的系统广播,下面我们就来让我们的APP接收系统广播,接收之前,还需要为我们的APP注册广播接收器哦!而注册的方法又分为以下两种:动态与静态!5)ContentProvider6)Intent1.显式Intent与隐式Intent的区别显式Intent:通过组件名指定启动的目标组件,比如startActivity(newIntent(A.this,B.class));每次启动的组件只有一个~隐式Intent:不指定组件名,而指定Intent的Action,Data,或Category,当我们启动组件时,会去匹配AndroidManifest.xml相关组件的Intent-filter,逐一匹配出满足属性的组件,当不止一个满足时,会弹出一个让我们选择启动哪个的对话框~2.Intent的七个属性:1)ComponentName(组件名称)--------------一个全限定类2)Action(动作)--------------------------别如get一个权限3)Category(类别)-----------------与action结合使用4)Data(数据),Type(MIME类型)-----------URI等5)Extras(额外)----------------------------例如传递字符6)Flags(标记)--------------------------大多用于android如何启动3、intent复杂数据传递https://www.runoob.com/w3cnote/android-tutorial-intent-pass-data.html
借图流程图解析:相关名词UI线程:就是我们的主线程,系统在创建UI线程的时候会初始化一个Looper对象,同时也会创建一个与其关联的MessageQueue;Handler:作用就是发送与处理信息,如果希望Handler正常工作,在当前线程中要有一个Looper对象Message:Handler接收与处理的消息对象MessageQueue:消息队列,先进先出管理Message,在初始化Looper对象时会创建一个与之关联的MessageQueue;Looper:每个线程只能够有一个Looper,管理MessageQueue,不断地从中取出Message分发给对应的Handler处理!简单点说:当我们的子线程想修改Activity中的UI组件时,我们可以新建一个Handler对象,通过这个对象向主线程发送信息;而我们发送的信息会先到主线程的MessageQueue进行等待,由Looper按先入先出顺序取出,再根据message对象的what属性分发给对应的Handler进行处理!4.Handler的相关方法:voidhandleMessage(Messagemsg):处理消息的方法,通常是用于被重写!sendEmptyMessage(intwhat):发送空消息sendEmptyMessageDelayed(intwhat,longdelayMillis):指定延时多少毫秒后发送空信息sendMessage(Messagemsg):立即发送信息sendMessageDelayed(Messagemsg):指定延时多少毫秒后发送信息finalbooleanhasMessage(intwhat):检查消息队列中是否包含what属性为指定值的消息如果是参数为(intwhat,Objectobject):除了判断what属性,还需要判断Object属性是否为指定对象的消息5、Handler写在子线程中在主线程中,因为系统已经初始化了一个Looper对象,所以我们直接创建Handler对象,就可以进行信息的发送与处理了!在子线程中则需要自己创建一个Looper对象了!创建的流程如下:1)直接调用Looper.prepare()方法即可为当前线程创建Looper对象,而它的构造器会创建配套的MessageQueue;2)创建Handler对象,重写handleMessage()方法就可以处理来自于其他线程的信息了!3)调用Looper.loop()方法启动Looper使用示例:输入一个数,计算后通过Toast输出在这个范围内的所有质数实现代码:activity_main.xml:<?xmlversion="1.0"encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayoutxmlns: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"><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><EditTextandroid:id="@+id/etNum"android:inputType="number"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="请输入上限"/><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="cal"android:text="计算"/></LinearLayout></androidx.constraintlayout.widget.ConstraintLayout>实现代码:MainActivity.java:packagecom.example.tets4;importandroidx.appcompat.app.AppCompatActivity;importandroid.app.Activity;importandroid.os.Bundle;importandroid.os.Handler;importandroid.os.Looper;importandroid.os.Message;importandroid.view.View;importandroid.widget.EditText;importandroid.widget.Toast;importjava.util.ArrayList;importjava.util.List;publicclassMainActivityextendsActivity{staticfinalStringUPPER_NUM="upper";EditTextetNum;CalThreadcalThread;//定义一个线程类classCalThreadextendsThread{publicHandlermHandler;publicvoidrun(){Looper.prepare();mHandler=newHandler(){//定义处理消息的方法@OverridepublicvoidhandleMessage(Messagemsg){if(msg.what==0x123){intupper=msg.getData().getInt(UPPER_NUM);List<Integer>nums=newArrayList<Integer>();//计算从2开始、到upper的所有质数outer:for(inti=2;i<=upper;i++){//用i处于从2开始、到i的平方根的所有数for(intj=2;j<=Math.sqrt(i);j++){//如果可以整除,表明这个数不是质数if(i!=2&&i%j==0){continueouter;}}nums.add(i);}//使用Toast显示统计出来的所有质数Toast.makeText(MainActivity.this,nums.toString(),Toast.LENGTH_LONG).show();}}};Looper.loop();}}@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);etNum=(EditText)findViewById(R.id.etNum);calThread=newCalThread();//启动新线程calThread.start();}//为按钮的点击事件提供事件处理函数publicvoidcal(Viewsource){//创建消息Messagemsg=newMessage();msg.what=0x123;Bundlebundle=newBundle();bundle.putInt(UPPER_NUM,Integer.parseInt(etNum.getText().toString()));msg.setData(bundle);//向新线程中的Handler发送消息calThread.mHandler.sendMessage(msg);}}
1.什么是方法回调?文字表述:答:是将功能定义与功能分开的一种手段,一种解耦合的设计思想;在Java中回调是通过接口来实现的,作为一种系统架构,必须要有自己的运行环境,且需要为用户提供实现接口;实现依赖于客户,这样就可以达到接口统一,实现不同,系统通过在不同的状态下"回调"我们的实现类,从而达到接口和实现的分离!找了一篇文章,挺不错https://blog.csdn.net/aigestudio/article/details/408698932.Android回调的事件处理机制详解:在Android中基于回调的事件处理机制使用场景有两个:1)自定义view当用户在GUI组件上激发某个事件时,组件有自己特定的方法会负责处理该事件通常用法:继承基本的GUI组件,重写该组件的事件处理方法,即自定义view注意:在xml布局中使用自定义的view时,需要使用"全限定类名"常见View组件的回调方法:android为GUI组件提供了一些事件处理的回调方法,以View为例,有以下几个方法①在该组件上触发屏幕事件:booleanonTouchEvent(MotionEventevent);②在该组件上按下某个按钮时:booleanonKeyDown(intkeyCode,KeyEventevent);③松开组件上的某个按钮时:booleanonKeyUp(intkeyCode,KeyEventevent);④长按组件某个按钮时:booleanonKeyLongPress(intkeyCode,KeyEventevent);⑤键盘快捷键事件发生:booleanonKeyShortcut(intkeyCode,KeyEventevent);⑥在组件上触发轨迹球屏事件:booleanonTrackballEvent(MotionEventevent);*⑦当组件的焦点发生改变,和前面的6个不同,这个方法只能够在View中重写哦!protectedvoidonFocusChanged(booleangainFocus,intdirection,RectpreviouslyFocusedRect)MyButton.javapackagecom.example.test3;importandroid.content.Context;importandroid.util.AttributeSet;importandroid.util.Log;importandroid.view.KeyEvent;importandroid.view.MotionEvent;importandroid.widget.Button;publicclassMyButtonextendsButton{privatestaticStringTAG="呵呵";publicMyButton(Contextcontext,AttributeSetattrs){super(context,attrs);}//重写键盘按下触发的事件@OverridepublicbooleanonKeyDown(intkeyCode,KeyEventevent){super.onKeyDown(keyCode,event);Log.i(TAG,"onKeyDown方法被调用");returntrue;}//重写弹起键盘触发的事件@OverridepublicbooleanonKeyUp(intkeyCode,KeyEventevent){super.onKeyUp(keyCode,event);Log.i(TAG,"onKeyUp方法被调用");returntrue;}//组件被触摸了@OverridepublicbooleanonTouchEvent(MotionEventevent){super.onTouchEvent(event);Log.i(TAG,"onTouchEvent方法被调用");returntrue;}}布局文件<com.example.test3.MyButtonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/btnshow"android:text="按钮"/>通过重写Button的三个回调方法,当发生点击事件后就不需要我们在Java文件中进行事件监听器的绑定就可以完成回调,即组件会处理对应的事件,即事件由事件源(组件)自身处理!(按键自己搞自己,监控是后台搞)(2)回调事件传播代码不贴了,只记录一下传播顺序:传播的顺序是:监听器--->view组件的回调方法--->Activity的回调方法;
借图事件监听机制中由事件源,事件,事件监听器三类对象组成处理流程如下:Step1:为某个事件源(组件)设置一个监听器,用于监听用户操作Step2:用户的操作,触发了事件源的监听器Step3:生成了对应的事件对象Step4:将这个事件源对象作为参数传给事件监听器step5:事件监听器对事件对象进行判断,执行对应的事件处理器(对应事件的处理方法)五种不同的实现形式1、直接用匿名内部类直接setXxxListener后,重写里面的方法即可;通常是临时使用一次,复用性不高btnshow=(Button)findViewById(R.id.btnshow);btnshow.setOnClickListener(newView.OnClickListener(){//重写点击事件的处理方法onClick()@OverridepublicvoidonClick(Viewv){//显示提示Toast.makeText(getApplicationContext(),"你点击了按钮",Toast.LENGTH_SHORT).show();}});2、使用内部类btnshow.setOnClickListener(newBtnClickListener());}classBtnClickListenerimplementsView.OnClickListener{@OverridepublicvoidonClick(Viewv){Toast.makeText(getApplicationContext(),"你点击了按钮",Toast.LENGTH_SHORT).show();}}3、使用外部类和外部类但是,但是不能外部类直接访问组件,所以需要通过构造函数传入组件。4、直接使用Activity作为事件监听器//让Activity方法实现OnClickListener接口publicclassMainActivityextendsActivityimplementsOnClickListener{privateButtonbtnshow;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btnshow=(Button)findViewById(R.id.btnshow);//直接写个thisbtnshow.setOnClickListener(this);}//重写接口中的抽象方法@OverridepublicvoidonClick(Viewv){Toast.makeText(getApplicationContext(),"点击了按钮",Toast.LENGTH_SHORT).show();}}直接让Activity继承OnClickListener,然后按钮直接监听this,并实现Activity的触发方法onClick。5、直接绑定到标签标签中加上这个,myclick是对应函数名android:onClick="myclick"@OverridepublicvoidmyClick(Viewv){Toast.makeText(getApplicationContext(),"点击了按钮",Toast.LENGTH_SHORT).show();}
先做前端布局1、adapter_view.xml(图片加文本布局)<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"><ImageViewandroid:id="@+id/ima1"android:layout_width="50dp"android:layout_height="50dp"android:src="@mipmap/ic_launcher"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="52dp"android:orientation="vertical"><TextViewandroid:id="@+id/tv1"android:layout_width="wrap_content"android:layout_height="20dp"android:text="TextView"android:textColor="#FFEBCD"/><TextViewandroid:id="@+id/tv2"android:layout_width="wrap_content"android:layout_height="20dp"android:text="TextView"android:textColor="#000000"/></LinearLayout></LinearLayout>2、activity_main.xml(listview布局,相当于在这里把adapter_view.xml中的布局*N)<?xmlversion="1.0"encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayoutxmlns: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"><ListViewandroid:id="@+id/lv1"android:layout_width="match_parent"android:layout_height="match_parent"/><!--这里设置一个ListView用来作为显示主界面,后面我们直观看到的就是它--></androidx.constraintlayout.widget.ConstraintLayout>3、在drawable文件中放上rc_1,rc_2,rc_3,rc_4,四张jpg图片,自己随便放,开心就好后端代码我们要把Animal的数据放到Listview中就需要用到adapter,所以这里通过继承BaseAdapter设计一个AnimalAdapter1、新建Animals.java类packagecom.example.test2;publicclassAnimals{privateStringanimal;privateStringanimalTell;privateintimgId;publicAnimals(Stringanimal,StringanimalTell,intimgId){this.animal=animal;this.animalTell=animalTell;this.imgId=imgId;}publicStringgetAnimalTell(){returnanimalTell;}publicvoidsetAnimalTell(StringanimalTell){this.animalTell=animalTell;}publicStringgetAnimal(){returnanimal;}publicvoidsetAnimal(Stringanimal){this.animal=animal;}publicintgetImgId(){returnimgId;}publicvoidsetImgId(intimgId){this.imgId=imgId;}}2.AnimalAdapter.java通过继承BaseAdapter设计packagecom.example.test2;importandroid.content.Context;importandroid.view.LayoutInflater;importandroid.view.View;importandroid.view.ViewGroup;importandroid.widget.BaseAdapter;importandroid.widget.ImageView;importandroid.widget.TextView;importjava.util.List;publicclassAnimalAdapterextendsBaseAdapter{privateContextcontext;//创建一个上下文对象privateList<Animals>datas;//创建一个List数组,里面存放Animal对象,用来接收MainActivity传过来的数据publicAnimalAdapter(Contextcontext,List<Animals>datas){this.context=context;this.datas=datas;}@OverridepublicintgetCount(){//获取数据的长度returndatas.size();}@OverridepublicObjectgetItem(inti){//适配器放入了很多条数据,获取数据所在的位置returndatas.get(i);}@OverridepubliclonggetItemId(inti){returni;}@OverridepublicViewgetView(inti,Viewview,ViewGroupviewGroup){Animalsanm=(Animals)getItem(i);//实例化给定位置上的对象Viewv;//创建视图v,这是是用来返回给ListView的,作为ListView的子视图ViewHoldviewHold;//创建临时的储存器ViewHold,它的作用是把你getView方法中每次返回的View存起来,可以下次再用if(view==null){v=LayoutInflater.from(context).inflate(R.layout.adapter_view,null);//将adapter_view视图作为子视图放入v中viewHold=newViewHold();//绑定id,建立与adapter_view视图的连接viewHold.animalImage=v.findViewById(R.id.ima1);viewHold.animalName=v.findViewById(R.id.tv1);viewHold.animalTell=v.findViewById(R.id.tv2);v.setTag(viewHold);//储器中的视图设置到v中}else{v=view;viewHold=(ViewHold)v.getTag();}//将制定位置上的数据显示到空间中viewHold.animalName.setText(anm.getAnimal());viewHold.animalTell.setText(anm.getAnimalTell());viewHold.animalImage.setImageResource(anm.getImgId());//返回视图v在main中显示returnv;}classViewHold{//将数据(也就是Animals对象)进行实例化,方便与xml文件里面的控件对接ImageViewanimalImage;TextViewanimalName;TextViewanimalTell;}}3、MainActivity.javapackagecom.example.test2;importandroidx.appcompat.app.AppCompatActivity;importandroid.os.Bundle;importandroid.view.View;importandroid.view.Window;importandroid.widget.AdapterView;importandroid.widget.ListView;importandroid.widget.Toast;importjava.util.ArrayList;importjava.util.List;publicclassMainActivityextendsAppCompatActivity{privateListViewmListView1;//创建ListView对象,将这个对象与xml文件中的ListView控件通过id的方式绑定绑定privateList<Animals>datas=newArrayList<Animals>();//创建一个List数组,用来存放数据privateAnimalAdapteranimalAdapter;//用来设置一个适配器的实现类对象@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_main);initDatas();//初始化数据mListView1=(ListView)findViewById(R.id.lv1);//绑定控件animalAdapter=newAnimalAdapter(this,datas);//创建适配器的实现类对象,并且将本类的class对象和定义的数据作为参数传入mListView1.setAdapter(animalAdapter);//为ListView绑定一个适配器mListView1.setOnItemClickListener(newAdapterView.OnItemClickListener(){//为ListView创建一个监听事件,方便我们对它进行操作@OverridepublicvoidonItemClick(AdapterView<?>adapterView,Viewview,inti,longl){Toast.makeText(MainActivity.this,"您单击了"+datas.get(i).getAnimal(),Toast.LENGTH_SHORT).show();}});}privatevoidinitDatas(){//将Animals的实现类对象传到数据列表当中Animalsanimal1=newAnimals("喜羊羊","喜气洋洋过大年",R.drawable.rc_1);Animalsanimal2=newAnimals("懒羊羊","我就是喜欢吃",R.drawable.rc_2);Animalsanimal3=newAnimals("灰太狼","我一定会回来的",R.drawable.rc_3);Animalsanimal4=newAnimals("小灰灰","喜羊羊哥哥,带我一起玩",R.drawable.rc_4);for(inti=0;i<10;i++){datas.add(animal1);datas.add(animal2);datas.add(animal3);datas.add(animal4);}}}转载自https://blog.csdn.net/weixin_46067095/article/details/115741364
前面那些鸟玩意终于看完了,吐了,看完了啥也没记住。用到再说吧,先找有用的看。Adapter是用来帮助填充数据的中间桥梁,简单点说就是:将各种数据以合适的形式显示到view上,提供给用户看!继承结构图一个读取联系人的代码:1、定义列表中每一行的布局,在res/layout目录下新建一个文件list_item.xml<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"><TextViewandroid:id="@+id/list_name"android:layout_width="0dp"android:layout_height="64dp"android:layout_weight="1"android:gravity="center"android:text="简单教程"android:textColor="#0000FF"android:textSize="18sp"/><TextViewandroid:id="@+id/list_phone"android:layout_width="0dp"android:layout_height="64dp"android:layout_weight="1"android:gravity="center"android:text="13888888888"android:textColor="#EA5C4D"android:textSize="18sp"/></LinearLayout>2、修改activity_main.xml添加一个ListView<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns: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:padding="8dp"android:orientation="vertical"><ListViewandroid:id="@+id/listview"android:layout_width="match_parent"android:layout_height="wrap_content"/></LinearLayout>3、修改MainActivity.javapublicclassMainActivityextendsAppCompatActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ListViewlist_test=(ListView)findViewById(R.id.list_test);//读取联系人Cursorcursor=getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,null,null,null);SimpleCursorAdapterspcAdapter=newSimpleCursorAdapter(this,R.layout.list_item,cursor,newString[]{ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,ContactsContract.CommonDataKinds.Phone.NUMBER},newint[]{R.id.list_name,R.id.list_phone});ListViewlist_view=(ListView)findViewById(R.id.list_view);list_view.setAdapter(spcAdapter);}}读取联系人导致系统崩溃的原因:没有给权限最后AndroidManifest.xml里加个读联系人的权限<uses-permissionandroid:name="android.permission.READ_CONTACTS"/>我加了这一行,依然没用,就去手机设置的权限管理里面手动给开了权限了
一、Date&Time组件1.TextClock(文本时钟)就是时间显示AttributeNameRelatedMethodDescriptionandroid:format12HoursetFormat12Hour(CharSequence)设置12时制的格式android:format24HoursetFormat24Hour(CharSequence)设置24时制的格式android:timeZonesetTimeZone(String)设置时区2.AnalogClock(模拟时钟)就是个表3.Chronometer(计时器)就是个计时器4.DatePicker(日期选择器)5.TimePicker(时间选择器)6.CalendarView(日历视图)
前面看了TextView控件,后面不想看了,先把控件都记一下,知道功能,后面用到了再查资料吧1、EditText(输入框)用于输入文本2、Button(按钮)与ImageButton(图像按钮)用于点击事件3、ImageView(图像视图)用于玩图片的,可以设置图片填满,图纵横比,圆角图之类4、RadioButton(单选按钮)&Checkbox(复选框)单选框布局代码<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/LinearLayout1"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="请选择性别"android:textSize="23dp"/><RadioGroupandroid:id="@+id/radioGroup"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"><RadioButtonandroid:id="@+id/btnMan"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="男"android:checked="true"/><RadioButtonandroid:id="@+id/btnWoman"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="女"/></RadioGroup><Buttonandroid:id="@+id/btnpost"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="提交"/></LinearLayout>点击事件判断:@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//RadioGroupradgroup=(RadioGroup)findViewById(R.id.radioGroup);////第一种获得单选按钮值的方法一开始是男,选了女之后会有提示,而不需要点击提交////为radioGroup设置一个监听器:setOnCheckedChanged()//radgroup.setOnCheckedChangeListener(newRadioGroup.OnCheckedChangeListener(){//@Override//publicvoidonCheckedChanged(RadioGroupgroup,intcheckedId){//RadioButtonradbtn=(RadioButton)findViewById(checkedId);//Toast.makeText(getApplicationContext(),"按钮组值发生改变,你选了"+radbtn.getText(),Toast.LENGTH_LONG).show();//}//});////////第二种方式,通过点击提交按钮获取值Buttonbtnchange=(Button)findViewById(R.id.btnpost);RadioGroupradgroup=(RadioGroup)findViewById(R.id.radioGroup);//为radioGroup设置一个监听器:setOnCheckedChanged()btnchange.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){for(inti=0;i<radgroup.getChildCount();i++){//getChildCount()获得按钮组中的单选按钮的数目;RadioButtonrd=(RadioButton)radgroup.getChildAt(i);//getChinldAt(i):根据索引值获取我们的单选按钮if(rd.isChecked()){//isChecked():判断按钮是否选中Toast.makeText(getApplicationContext(),"点击提交按钮,获取你选择的是:"+rd.getText(),Toast.LENGTH_LONG).show();break;}}}});}复选框布局类似,大差不差,同时,可以根据需求修改选择框样式5、开关按钮ToggleButton和开关Switch6、ProgressBar(进度条)android:max:进度条的最大值android:progress:进度条已完成进度值android:progressDrawable:设置轨道对应的Drawable对象android:indeterminate:如果设置成true,则进度条不精确显示进度android:indeterminateDrawable:设置不显示进度的进度条的Drawable对象android:indeterminateDuration:设置不精确显示进度的持续时间android:secondaryProgress:二级进度条,类似于视频播放的一条是当前播放进度,一条是缓冲进度,前者通过progress属性进行设置!7、SeekBar(拖动条)这玩意是进度条的子类android:max="100"//滑动条的最大值android:progress="60"//滑动条的当前值android:secondaryProgress="70"//二级滑动条的进度android:thumb="@mipmap/sb_icon"//滑块的drawable接着要说下SeekBar的事件了,SeekBar.OnSeekBarChangeListener我们只需重写三个对应的方法:onProgressChanged:进度发生改变时会触发onStartTrackingTouch:按住SeekBar时会触发onStopTrackingTouch:放开SeekBar时触发8、RatingBar(星级评分条)最傻逼和最简单的。。。。。9、ScrollView(滚动条)滚动到底部:我们可以直接利用ScrollView给我们提供的:fullScroll()方法:scrollView.fullScroll(ScrollView.FOCUS_DOWN);滚动到底部scrollView.fullScroll(ScrollView.FOCUS_UP);滚动到顶部另外用这玩意的时候要小心异步的玩意,就是addView后,有可能还没有显示完,如果这个时候直接调用该方法的话,可能会无效,这就需要自己写handler来更新了~publicstaticvoidscrollToBottom(finalViewscroll,finalViewinner){HandlermHandler=newHandler();mHandler.post(newRunnable(){publicvoidrun(){if(scroll==null||inner==null){return;}intoffset=inner.getMeasuredHeight()-scroll.getHeight();if(offset<0){offset=0;}scroll.scrollTo(0,offset);}});}2.设置滚动的滑块图片这个更加简单:垂直方向滑块:android:scrollbarThumbVertical水平方向滑块:android:scrollbarThumbHorizontal