• 【Android】【实践】


    请求位置权限:如果您同时使用NETWORK_PROVIDER和GPS_PROVIDER,则只需要请求ACCESS_FINE_LOCATION权限,大权限包含小权限
    在Android6.0开始,App可以直接安装,App在运行时一个一个询问用户授予权限,这个对话框不是开发者调用某个权限的功能时由系统自动弹出,而是需要开发者手动调用,如果你直接调用而没有去申请权限的话,将会导致App奔溃!!!
        不涉及用户隐私的,		只需要在Manifest中声明即可,比如网络、蓝牙、NFC等;
        涉及到用户隐私信息的,	需要用户授权后才可使用,比如SD卡读写、联系人、短信读写等。()
            此类权限也必须在Manifest中申明,否则申请时不提使用用户,直接回调开发者权限被拒绝
    生成tag:  logt
        打印日志  Log.v() Log.d() Log.i() Log.w() 以及 Log.e() 
        根据首字母对应VERBOSE,DEBUG,INFO, WARN,ERROR
    BUG :  过多子线程抢占资源导致程序崩溃
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    完美请求权限,解决用户永久拒绝,多次拒绝等问题

    //完美处理权限
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
        locationText = (TextView) findViewById(R.id.Location);
        locationText.setText("..........");
        //app启动,但没有权限
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
                Log.e("1", "shouldShowRequestPermissionRationale() 返回 true, 即上次弹出权限点击了禁止(但没有勾选“下次不在询问”),则重新请求权限");
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
            } else {
                //app第一次启动
                Log.e("1", "shouldShowRequestPermissionRationale() 返回 false ,即第一次打开App时,重新请求权限");
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
            }
        }else {
            //有权限了
            Log.e("1", "已经有权限了");
            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
            locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
        }
    }
    
    @SuppressLint("MissingPermission")
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        Toast.makeText(this, "onRequestPermissionsResult", Toast.LENGTH_LONG).show();
        switch (requestCode) {
            case 1: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.e("1", "权限被用户同意,可以去放肆了");
                    //有权限了,直接放肆!
                    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
                    locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
    
                } else {
                    Log.e("1", "权限被用户拒绝了,洗洗睡吧");
                    Boolean notFoeverRefused = ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION);
                    if (notFoeverRefused) {
                        //没有选不再提醒,那我就再次申请!
                        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
                    } else {
                        Log.e("1", "shouldShowRequestPermissionRationale() 返回 false ,上次选择禁止并勾选【下次不在询问】" +
                                "现在我们唯一能做的就是跳转到我们 App 的设置界面,让用户手动开启权限了。");
                        //选了不再提醒,那就调到设置页面让用户手动开权限
                        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                        Uri uri = Uri.fromParts("package", getPackageName(), null);
                        intent.setData(uri);
                        startActivityForResult(intent, 1);
                    }
                }
                return;
            }
        }
    }
    
    @SuppressLint("MissingPermission")
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode==1){
            Log.e("1", "onActivityResult");
            //用户从设置界面回来了,再检查一下有没有权限
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
                    Log.e("1", "shouldShowRequestPermissionRationale() 返回 true, 即上次弹出权限点击了禁止(但没有勾选“下次不在询问”),则重新请求权限");
                    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
                } else {
                    //第一次打开App时
                    Log.e("1", "shouldShowRequestPermissionRationale() 返回 false ,即第一次打开App时,重新请求权限");
                    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
                }
            }else {
                //有权限了
                Log.e("1", "已经有权限了");
                locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
                locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
            }
    
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    implements View.OnClickListener
    
    private Button login;  
    login = (Button) findViewById(R.id.login);  
    
    @Override
    public void onClick(View v) {
    switch(v.getId()){
        case R.id.buttonDW:
            break;
    }
    
    Toast.makeText().show();
    startActivity(new Intent(this,MapActivity.class));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 服务器传过来的,图片是二进制的
      • 把string 的response用getBytes方法获得位流 http://blog.csdn.net/ameyume/article/details/6528205
        • 一种是先转换为byte[],再生成bitmap;
        • 一种是直接用InputStream生成bitmap。

    开个子线程(不能传消息到UI线程),不推荐

    new Thread(new Runnable(){
        public void run() {}
    }).start();//来运行
    
    //相当于: 
    class Anomymous implements Runnable {
        public void run() {
        }
    }
    Runnable rn = new Anomymous();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    AsyncTask(推荐)

    //AsyncTask:适用于短时间的后台任务,如网络请求,把耗时的操作异步到后台去,你可以接着干别的,可以从子线程更新到UI线程
    ReverseTask reverseTask = new ReverseTask();
    reverseTask.execute(text);
    
    class ReverseTask extends AsyncTask<String,Integer,String> {
                              //
                              //    onProgressUpdate进度progress的类型,  
                              //    doInBackground后传给onPostExecute的类型
        @Override
        protected void onPreExecute() {//在 UI 线程中调用
            progressDialog.show();
        }
    
        @Override
        protected String doInBackground(String... params) {//此方法会在工作线程中运行,在这里去处理所有耗时的任务,
            int progress = 0;
            try {//更新进度
                for(int i = 0;i <= 10;i ++){
                    progress += 10;
                    Thread.sleep(200);
                    publishProgress(progress);
                    //在doInBackground通过publishProgress(Progress..)来反馈进度到UI 
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return Reverse(params[0]);
        }
    
        @Override
        protected void onProgressUpdate(Integer... values) {//在 UI 线程中调用
            progressDialog.setMessage(values[0]+"% Finished");
        }
    
        @Override
        protected void onPostExecute(String s) {//在 UI 线程中调用
            //在 doInBackground(...) 方法执行完毕后才会运行。
            //doInBackground() 返回的值将发送到 onPostExecute()
            textView.setText(s);
            progressDialog.dismiss();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    安卓原生的 Thread (Looper)

    对于一些普通的程序开发工作而言,只需要了解Handler的用法即可,几乎接触不到Looper 
    Handler 在它关联的looper线程中处理异步消息:当发出一个消息之后,首先进入一个MessageQueue,发送消息的函数即刻返回,
    而另外一个部分在消息队列中逐一将消息取出,然后对消息进行处理,也就是发送消息和接收消息不是同步的处理。 
    这种机制通常用来处理相对耗时比较长的操作。
    //构造参数为空就是主线程的Handler,反正它可以传入Looper为构造参数,Looper是谁的它就是谁的Handler
    
    Looper.myLooper()  //通过得到当前线程的Looper对象,通过Looper.getMainLooper()//得到当前进程的主线程的Looper对象
    //Handler
       //sendMessage
      //sendMessageDelayed
      //post(Runable)
      //postDelayed(Runable,long)
      //sendMessage交由handleMessage(Message)方法处理(其实自己发送自己接收)
    
    ThreadLocal //用于存取一个线程的局部变量为mThread
    
    //Looper线程中有一个MessageQueue
         //handler:    发消息
         //Looper:	    收消息,再传回去
         //MessageQue:  存消息
    public class Thread1 extends Thread {
        @Override
        public void run() {
            // 将当前线程初始化为Looper线程
            Looper.prepare();
            // ...其他处理,如实例化handler, Handler是用来异步更新UI的,是子线程与UI主线程之间的通信。
            mHandler = new Handler() {
                    public void handleMessage(Message msg) {
                        // process incoming messages here
                    }
            };
            // 开始循环处理消息队列
            Looper.loop();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    HandlerThread: 简化的 Thread (Looper)

    //HandlerThread本质上是一个线程类,它继承了Thread; 主要是在HandlerThread里面自己创建一个Looper,和默认的 handler 进行关联。
    //所有的handlerMessage()都是在子线程中调用。所以,HandlerThread可以处理耗时操作,例如下载网络图片、更新数据库等等
    //可重写onLooperPrepared方法,它被置于Looper中,用来做消息的取出和处理
    HandlerThread.start();//线程开始
    Looper loop =HandlerThread.getLooper();
    //此方法等待Looper生成成功,成功后才会调用onLooperPrepared,因为上面说的onLooperPrepared方法,它被置于Looper中
    //创建Handler与该线程绑定
    mSubThreadHandler = new Handler(loop){
                public void handleMessage(Message msg) {
                    }
    }
    //那么现在我们要是想子线程与子线程之间的通信要怎么做呢?如果不用HandlerThread的话,需要手动去调用
    Looper.prepare()
    Looper.loop()
    //去解决多线程并发的问题
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    连接到外部模拟器

    //然后运行cmd命令,cd到夜神安装目录,执行命令
    adb connect 127.0.0.1:5555
    adb devices //#查看设备
    
    • 1
    • 2
    • 3

    输出调试日志

    Log.v(tag,message)
    
    • 1

    正确地子线程中修改UI

    //Android 提供了几种途径来从其他线程访问 UI 线程。 以下列出了几种有用的方法:
    Activity.runOnUiThread(Runnable) //方法1
    View.postDelayed(Runnable, long) //方法2
    
    //例如,您可以通过使用 View.post(Runnable) 方法修复上述代码:
    public void onClick(View v) {//线程安全,在单独的线程中完成网络操作,而在 UI 线程中操纵 ImageView。
        new Thread(new Runnable() {
            public void run() {
                final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
                mImageView.post(new Runnable() { //View.post(Runnable) //方法3
                    public void run() {
                        mImageView.setImageBitmap(bitmap);
                    }
                });
            }
        }).start();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • RxJava + Retrofit + okHttp -网络请求最流行的方式
      • Retrofit 负责请求的数据/结果,使用接口的方式呈现
      • OkHttp 负责请求的过程
      • RxJava 负责异步,各种线程之间的切换,比原生的简洁。
    compile 'io.reactivex:rxjava:1.1.5'
    compile 'io.reactivex:rxandroid:1.1.0'
    //RxJava 	开关\被观察者\Observable.订阅\观察(台灯\观察者\Observer\Subscriber\订阅者)
    compile 'com.squareup.retrofit2:retrofit:2.3.0'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'  //配合Rxjava 使用
    implementation 'com.squareup.okhttp3:okhttp:3.9.1'
    
     //用注释来findviewbyid
    compile 'com.jakewharton:butterknife:8.8.1'          
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    SharedPreferences:一个轻量级的存储类,特别适合用于保存软件配置参数。(是用xml文件存放数据,文件存放在/data/data/<package name>/shared_prefs目录下)
    
    • 1
    安卓单元测试的分类:
        本地测试(Local tests): 只在本地机器JVM上运行,以最小化执行时间,这种单元测试不依赖于Android框架,或者即使有依赖,也很方便使用模拟框架来模拟依赖,以达到隔离Android依赖的目的,模拟框架如google推荐的[Mockito][1];
        仪器化测试(Instrumented tests): 在真机或模拟器上运行的单元测试,由于需要跑到设备上,比较慢,这些测试可以访问仪器(Android系统)信息,比如被测应用程序的上下文,一般地,依赖不太方便通过模拟框架模拟时采用这种方式。
    
    • 1
    • 2
    • 3
    app/src
         ├── androidTestjava (仪器化单元测试、UI测试)
         ├── main/java (业务代码)
         └── test/java  (本地单元测试)
    
    • 1
    • 2
    • 3
    • 4
    var isExistPeopleName=false;  var peopleNameId='';
    //判断用户名是否存在
    function isExist(name)
    {
    	var jsonObj; 
    	fetch("https://api2.bmob.cn/1/classes/position/",
    	{
    		headers:
    		{
    			'X-Bmob-Application-Id': 'ae69ae4ad1b9328f1993c62a637454a7',
    			'X-Bmob-REST-API-Key': '05d377b293e63f9f9e22788154af1449',
    		},
    		method: 'GET',
    	}).then(response => response.json()).then(function (result)
    	{
    		jsonObj = result;
    	}).then(() =>
    		{	isExistPeopleName=false;
    			for (var i = 0; i < jsonObj.results.length; i++)
    			{
    				if (jsonObj.results[0].name == name)
    				{
    					 isExistPeopleName=true;
    					 peopleNameId=jsonObj.results[0].objectId;
    					 break;
    				}
    			}
    		}
    
    	);
    }
    
    isExist('123');
    undefined
    isExistPeopleName;
    true
    peopleNameId;
    "b5bbd688b1"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    android:launchMode="singleTask" //不会在主activity点一下就跳会登录界
    SingleTop       通知消息打开的页面;登录页面
    SingleTask      浏览器、微博等页面(大多数App的主页)
    SingleInstance  呼叫来电界面,整个手机操作系统里面只有一个实例存在。
    
    • 1
    • 2
    • 3
    • 4
    ImageView控件上下留白原因与解决:在图片ImageView控件中添加属性android:adjustViewBounds="true"即可,既保持宽高比
    安卓用jdbc操作oracle数据库:要用classes12.jar作为jdbc驱动包,用传统的Class.forName来加载,不能用OracleDataSource这些用了JNDI的方法来加载,其他包太新,都要依赖jdk库!
    安卓不能用jdk的库!因为安卓虚拟机改造过了!
        Java有很多第三方库。AndroidDalvik虚拟器不完全是Java,也就是Android SDK和传统的SDK不完全一样,如果Java库兼容Android,则可被利用。
        Java库使用受限于下面因素:
            目标平台:Java代码适配版本是否比Android基于的Java版本更高。是否用了Android不支持的Java SE的API,例如Swing、AWT图形。
            Size:为桌面或者服务器设计的Java代码不需要考虑存储和内存空间,Android需要,使用第三方Java代码,可能会是应用Size无法容忍。
            性能:Java代码是否要消耗Android设备所能提供的CPU。
            界面:Java代码是否需要console界面,或者可以包装我们自己界面中的单纯API。
    Android Devcie Monitor:查看手机文件,若显示空白,则	cmd执行 adb root		#获取root权限
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    Android中XML的命名空间(xmlns):
        //android	用于 Android 系统定义的一些属性。
        //app 		用于我们应用自定义的一些属性
        //tools: 	只对IDE有效(在设计器中有个小工具的图标,容易认)
            //tools:context   开发中查看Activity布局效果
            //tools:layout    开发中查看fragment布局效果
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    //解决Recyclerview 只有一条: 
    //Recyclerview 的版本改为23以下,如:
    compile 'com.android.support:support-v4:22.1.0'
    compile 'com.android.support:recyclerview-v7:22.1.0'
    compile 'com.android.support:appcompat-v7:22.1.0'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    R文件的位置:app-build-generated-source-r-debug-packageName-R.java
    style.xml 可设置应用的主题和颜色,被引用
    旋转屏幕,Android就会销毁当前activity,然后再创建新的activity。
    在异常的时候自动在异常处生成断点:
        RunView Breakpoints.,选择下拉列表中的Java Exception Breakpoints选项。
        接下来选择要捕捉的异常类型。输入 RuntimeException ,按提示选择RuntimeException(java.lang)
    返回上一个Activiey:  xml设置其 parentActivityName即可 , eg: [.ParentActivity]
    fragment :要委托工作任务给托管activity(Fragment只做它该做的事,其他让Activity)
        通常的做法是由fragment定义名为 Callbacks 的回调接口,实现Callbacks接口和其方法,而后Fragment就可以调用它让Activity干事.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    //values.xml  定义有占位符的 string
    <string name="crime_report">%1$s! %2$s. %3$s, and %4$s</string>
    //传参: 对应以下后4个参数
    String report=getString(R.string.crime_report,'arg1','arg2','arg3','arg4');
    
    • 1
    • 2
    • 3
    • 4
    android:orientation="vertical"  	时, 只有水平方向的设置才起作用,垂直方向的设置不起作用。即:left,right,center_horizontal 是生效的。
    android:orientation="horizontal" 	时, 只有垂直方向的设置才起作用,水平方向的设置不起作用。即:top,bottom,center_vertical 是生效的。
    android:gravity:					这个是针对控件里的元素来说的
    android:layout_gravity:			控件的父控件中的位置
    
    ProGuard						为了很好的保护Java源代码,我们需要对编译好后的class文件进行混淆。
    
    可以看到在Android studio3.0中,compile依赖关系已被弃用,被implementation和api替代,provided被compile only替代,apk被runtime only替代。
    
    *.jar, Java Archive File,包含了class 文件与清单文件
    *.arr,包含所有资源,class 文件以及 res 资源文件。
    *.so ,文件是 unix 的动态连接库,二进制文件。SO 库本身不参与 APK 的编译过程,使用 JNI 调用 SO 库里的 Native 方法,进行NDK开发。
    /lib/<abi>/lib<name>.so  #系统在预期位置找不到原生共享库,便无法加以使用
    在胖 APK 中,每个库位于名称与相应 ABI 匹配的目录下。 例如,胖 APK 可能包含:
        /lib/armeabi/libfoo.so
        /lib/armeabi-v7a/libfoo.so
        /lib/arm64-v8a/libfoo.so
        /lib/x86/libfoo.so
        /lib/x86_64/libfoo.so
    HttpClient在sdk 23中不再支持!!!		#你必须使用URLConnectionOkHttp或降级到sdk 22(compile 'com.android.support:appcompat-v7:22.2.0')
    //Error type 3 Error: Activity class {} does not exist:
    adb uninstall test.alexander.ru.testapp  
    //cmd执行,从设备中完全删除应用即可!
    
    //解决缺少com.android.support:appcompat-v7:25.3.1
    allprojects {
        repositories {
            jcenter()
            google()    //加入这一句
        }
    }
    
    
    AbsoluteLayoutDrawerLayoutCoordinatorLayoutGridLayoutFrameLayoutLinearLayoutRelativeLayoutSlidingPaneLayoutSwipeRefreshLayoutAdapterView <T extends  Adapter >FragmentBreadCrumbsLinearLayoutCompatPagerTitleStripRecyclerViewSlidingDrawer, 工具栏, TvViewViewPager
    
    TabLayout (FrameLayout子类):左右滑动切换页面 		#或 ViewPager
    CoordinatorLayout:(上滑自动隐藏工具栏)
    让工具栏(AppBarLayout里嵌入Toolbar) 能和RecyclerView通信,它只提供触控层,布局还是得再加个其他LayoutDrawerLayout:用来全局放侧滑导航栏用
    
    //右滑返回
    compile 'me.imid.swipebacklayout.lib:library:1.1.0'
    //继承SwipeBackActivity即可
    
    SdkVersion 对应 安卓版本
        Android Support v4: 		SDK4	对应	安卓1.6及更高版本	,这个包是使用最广泛的
        Android Support v7:  		SDK7	对应	安卓2.1及以上版本	,但不包含更低(v7依赖v4)
        com.android.support:appcompat-v7 支持库:  一些库旨在与 Android 2.3(API 级别 9)及更高版本搭配使用。
        android.support.design:		Android的material design兼容库
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    //4 列表 RecycleView
                //现在更推荐用RecycleView》viewholder获得view》adapter处理view的事件
                mAdapter = new MyAdapter(datas);
                
                StaggeredGridLayoutManager mLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);//垂直布局管理器  
                mRecyclerView.setLayoutManager(mLayoutManager);//设置布局管理器  
                mRecyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));//设置分隔线  
                mRecyclerView.setAdapter(mAdapter);//设置Adapter  
                
                class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> 
                @Override
                onCreateViewHolder//绑定R.layout.列表项
                onBindViewHolder(final ListViewHolder holder, int position) //绑定内容到列表项,绑定点击事件,参数position是列表项的位置
                getItemCount//获取列表项数
                static class ViewHolder extends RecyclerView.ViewHolder{//获得列表项}
                 //数据变化时:
                 mMAdapter.notifyDataSetChanged(); 
                //1点击事件:在Activity中使用
                        mAdapter.setOnItemClickListener(new OnItemClickListener(){//把OnItemClickListener点击事件传给mAdapter里给它使用
                            @Override    
                            public void onItemClick(View view , int position){
                                Toast.makeText(MainActivity.this, data[position], 600).show();
                            }
                        });
                //2点击事件:MyAdapter 代码中声明
                public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> implements View.OnClickListener{
                    private  String[]  datas;
                    public MyAdapter(String[] datas) {
                        this.datas = datas;
                    }
                //定义接口
                    public static interface OnItemClickListener {
                        void onItemClick(View view , int position);
                    }
                //声明接口
                   private OnItemClickListener mOnItemClickListener = null;
                    @Override
                    public ViewHolder onCreateViewHolder(ViewGroup viewGroup,  int viewType) {
                        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false);
                        ViewHolder vh = new ViewHolder(view);
                        //在onCreateViewHolder创建的View注册点击事件
                        view.setOnClickListener(this);
                        return vh;
                    }
                    
                    @Override
                    public void onBindViewHolder(ViewHolder viewHolder,  int position) {
                        viewHolder.mTextView.setText(datas[position]);
                        //在onBindViewHolder,将position保存在itemView的Tag中,以便点击时进行获取
                        viewHolder.itemView.setTag(position);
                    }
                // 实现View.OnClickListener的方法
                    @Override
                    public void onClick(View v) {
                        if (mOnItemClickListener != null) {
                            //注意这里使用getTag方法获取position
                            mOnItemClickListener.onItemClick(v,(int)v.getTag());//使用接口
                        }
                    }
                //被直接调用的
                    public void setOnItemClickListener(OnItemClickListener listener) {
                //在Activity中用mAdapter.setOnItemClickListener调用它
                        this.mOnItemClickListener = listener;
                    }
                }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
  • 相关阅读:
    Redis 切片集群
    贝塞尔曲线和曲面原理
    数据库系统原理与应用教程(065)—— MySQL 练习题:操作题 62-70(九)
    如何使用固态硬盘+硬盘盒子+U盘创造移动双系统
    深圳家具展首日,金可儿展位三大看点全解锁!
    uni-app 解决钉钉小程序日期组件uni-datetime-picker不兼容ios问题
    前端面试基础面试题——9
    KMP 算法 + 详细笔记
    Redis是单线程吗?以及为什么使用单线程(Redis 的网络模型)
    openEuler 22.03 LTS 环境使用 Docker Compose 一键部署 JumpServer (all-in-one 模式)
  • 原文地址:https://blog.csdn.net/a571574085/article/details/126099739