Android的基础开发

基础开发

listView

ListView就是列表条目,可以向下滚动,也可以点击。

首先设置两个视图布局

activity_main2.xml【充当容器{ListView}】

<ListView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/lv"/>
list_view_item.xml【充当容器中的组件{TextView}】

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/tv1"
    android:textSize="30sp"
    />

设置主方法

private List<ListViewBean> data = new ArrayList<>();
public void testListView(){
    for (int i = 0; i < 100; i++) {
        ListViewBean bean = new ListViewBean();
        bean.setName("pansd"+i);
        data.add(bean);
    }
    ListView listView = findViewById(R.id.lv);
    //给listView组装item,就是textview
    listView.setAdapter(new MyAdapter(data,this));
    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
            Log.e("pansd - item - click", "onItemClick: "+i );
        }
    });
}

设置适配ListView的适配器(将TextView适配到其的item)

package com.pshdhx.demo1.adapter;
​
import android.content.Context;
import android.database.DataSetObserver;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.BaseAdapter;
import android.widget.TextView;
​
import com.pshdhx.demo1.Bean.ListViewBean;
import com.pshdhx.demo1.R;
​
import java.util.List;
​
public class MyAdapter extends BaseAdapter {
​
    private List<ListViewBean> data;
    private Context context;
​
​
    public MyAdapter(List<ListViewBean> data, Context context) {
        this.data = data;
        this.context = context;
    }
​
    @Override
    public int getCount() {
        return data.size();
    }
​
    @Override
    public Object getItem(int i) {
        return null;
    }
​
    @Override
    public long getItemId(int i) {
        return i;
    }
​
​
​
    /**
     *     //获取每个列表项的视图
     * @param i 下标
     * @param view 当前要显示或者是重用的列表项视图
     * @param viewGroup 表示listview本身
     * @return
     */
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        if(view == null){ //第一次加载没有可重用的视图,LayoutInflater从布局文件中填充一个新试图,并将其分配给view对象
            //将子元素视图填充到父元素中
            view = LayoutInflater.from(context).inflate(R.layout.list_view_item,viewGroup,false);
        }
        //view存在,即视图对象存在,可以直接使用它,不用再创建视图对象,从容器中获取listview
        TextView textView = view.findViewById(R.id.tv1);
        textView.setText(data.get(i).getName());
        Log.e("pansd", "getView: "+ i );
        return view;
    }
​
    //由于view.findViewById(R.id.tv1); 每次进来时,比较耗时,所以把TextView抽取出来
    public View getView2(int i, View view, ViewGroup viewGroup) {
        ViewHolder viewHolder;
        if(view == null){
            viewHolder = new ViewHolder();
            view = LayoutInflater.from(context).inflate(R.layout.list_view_item,viewGroup,false);
            viewHolder.textView = view.findViewById(R.id.tv1);
        }else{
//            通过调用view.setTag(viewHolder);将ViewHolder对象设置为视图的标签,以便在以后进行重用。
            viewHolder = (ViewHolder) view.getTag();
        }
        viewHolder.textView.setText(data.get(i).getName());
        Log.e("pansd", "getView: "+ i );
        return view;
    }
    private final class ViewHolder{
        TextView textView;
    }
}

其余:

public class ListViewBean {
    String name;
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
}

效果:

RecyclerView

1、导入包

build.gradle中

implementation 'androidx.recyclerview:recyclerview:1.1.0'

2、构造器,很重要,实现监听

package com.pshdhx.demo1.adapter;
​
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
​
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
​
import com.pshdhx.demo1.Bean.ListViewBean;
import com.pshdhx.demo1.R;
​
import java.util.List;
​
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {
    private List<ListViewBean> data;
    private Context context;
​
​
    public RecyclerAdapter(List<ListViewBean> data, Context context) {
        this.data = data;
        this.context = context;
    }
​
    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = parent.inflate(context, R.layout.recycler_view_item, null);
        return new MyViewHolder(view);
    }
​
    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        holder.tv.setText(data.get(position).getName());
    }
​
    @Override
    public int getItemCount() {
        return data == null ? 0 : data.size();
    }
​
    public class MyViewHolder extends RecyclerView.ViewHolder {
        private TextView tv;
        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            tv = itemView.findViewById(R.id.tv1);
            itemView.setOnClickListener(new View.OnClickListener(){
                @Override
                public void onClick(View view) {
                     if(onRecyclerItemClickListener != null){
                        onRecyclerItemClickListener.onRecyclerItemClick(getAdapterPosition());
                     }
                }
            });
        }
    }
​
    private OnRecyclerItemClickListener onRecyclerItemClickListener;
​
    public void setOnRecyclerItemClickListener(OnRecyclerItemClickListener listener){
        onRecyclerItemClickListener = listener;
    }
​
    public interface OnRecyclerItemClickListener{
        void onRecyclerItemClick(int position);
    }
}
3、主方法

    public void testRecyclerView(){
        for (int i = 0; i < 100; i++) {
            ListViewBean bean = new ListViewBean();
            bean.setName("pansd cycler"+i);
            data.add(bean);
        }
        RecyclerView recyclerView = findViewById(R.id.rv);
        //给listView组装item,就是textview
//        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setLayoutManager(new GridLayoutManager(this,3)); //三个显示一行
        RecyclerAdapter recyclerAdapter = new RecyclerAdapter(data, this);
        recyclerAdapter.setOnRecyclerItemClickListener(new RecyclerAdapter.OnRecyclerItemClickListener() {
            @Override
            public void onRecyclerItemClick(int position) {
                Log.e("pansd", "onRecyclerItemClick: "+ position);
            }
        });
        recyclerView.setAdapter(recyclerAdapter);
    }
4、recycler_view_item.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/tv1"
        android:textSize="30sp"
        />
​
</LinearLayout>
5、容器activity_main3.xml

<androidx.recyclerview.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/rv"
/>

动画类型

逐帧动画 frame-by-frame animation

F:\androidProject\android_learn\demo1\app\src\main\res\drawable\frame_list.xml

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
​
    <!-- 创建逐帧动画 -->
    <item android:drawable="@drawable/cat" android:duration="120"/>
    <item android:drawable="@drawable/cat" android:duration="120"/>
    <item android:drawable="@drawable/cat" android:duration="120"/>
</animation-list>
activity_main_framebyframe.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:id="@+id/frameid"
    android:background="@drawable/frame_list"
    android:orientation="vertical"
    tools:context=".MainActivity">
​
​
</RelativeLayout>
/**
 * 测试逐帧动画
 */
public void testframeByFrame(){
    setContentView(R.layout.activity_main_framebyframe);
    RelativeLayout relativeLayout = findViewById(R.id.frameid);
    final AnimationDrawable background = (AnimationDrawable) relativeLayout.getBackground();
    relativeLayout.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View view) {
            if(flag){
                background.start();
                flag = false;
                Log.e(TAG, "onClick: 在运行" );
            }else{
                background.stop();
                flag = true;
                Log.e(TAG, "onClick: 已停止" );
            }
        }
    });
}

补间动画 tweened animation

1、透明度 alpha

2、旋转 rotate

3、缩放 scale

4、平移 translate

alpha.xml rotate.xml scale.xml translate.xml

<!-- 测试补间动画 透明度 [从透明变到不透明,整个过程需要花费两秒钟]-->
<alpha
    android:fromAlpha="0"
    android:toAlpha="1"
    android:duration="2000"
    />
<rotate
        android:fromDegrees="0"
        android:toDegrees="360"
        android:pivotX="50%"
        android:pivotY="50%"
        android:duration="2000"
        />
    <scale
​
        android:fromXScale="1"
        android:fromYScale="1"
        android:toXScale="0.5"
        android:toYScale="0.5"
        android:pivotX="50%"
        android:pivotY="50%"
        android:duration="2000"
        />
    <translate
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="400"
        android:toYDelta="400"
        android:duration="2000"
        />
    /**
     * 测试补间动画
     */
    public void testBujianDonghua(){
        setContentView(R.layout.activity_main_tweened_animation);
        final ImageView imageView = findViewById(R.id.iv);
        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
//                Animation animation = AnimationUtils.loadAnimation(MainActivity.this,
//                        R.anim.alpha);
//                Animation animation = AnimationUtils.loadAnimation(MainActivity.this,
//                        R.anim.rotate);
//                Animation animation = AnimationUtils.loadAnimation(MainActivity.this,
//                        R.anim.scale);
                Animation animation = AnimationUtils.loadAnimation(MainActivity.this,
                        R.anim.translate);
                imageView.startAnimation(animation);
            }
        });
属性动画 property animation

/**
 * 测试属性动画 1
 */
public void testPropertyAnimation1(){
    setContentView(R.layout.activity_main_tweened_animation);
    ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 1f);
    valueAnimator.setDuration(2000);
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator valueAnimator) {
            float val = (float) valueAnimator.getAnimatedValue();
            Log.e(TAG, "onAnimationUpdate: "+val );
        }
    });
    valueAnimator.start();
    ImageView imageView = findViewById(R.id.iv);
    //将会由完全透明 变为不透明
    ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "alpha", 0f, 1f);
    objectAnimator.setDuration(4000);
    objectAnimator.start();
​
    objectAnimator.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animator) {
            Log.e(TAG, "onAnimationStart: ");
        }
​
        @Override
        public void onAnimationEnd(Animator animator) {
​
            Log.e(TAG, "onAnimationEnd: " );
        }
​
        @Override
        public void onAnimationCancel(Animator animator) {
​
            Log.e(TAG, "onAnimationCancel: " );
        }
​
        @Override
        public void onAnimationRepeat(Animator animator) {
​
        }
    });
    objectAnimator.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationStart(Animator animation) {
            super.onAnimationStart(animation);
            Log.e(TAG, "只监听start方法...onAnimationStart: " );
        }
    });
​
}

单位尺寸

  1. px: pixels(像素).不同设备显示效果相同

  2. pt: point,是一个标准的长度单位,1pt= 1/72英寸,用于印刷业,非常简单易用

3、dip: device independent pixels(设备独立像素).不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA、HVGA和QVGA 推荐使用这个,不依赖像素 4、dp:就是dip 5、sp: scaled pixels(放大像素).主要用于字体显示best for textsize。

6、LayoutParams相当于一个Layout的信息包,它封装了Layout的位置、高、宽等信息

   
 /**
     * 测试像素
     */
    public void testPx_dp_sp(){
        LinearLayout linearLayout = new LinearLayout( this);
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT);
        linearLayout.setLayoutParams(layoutParams);
        TextView textview = new TextView(this);
        textview.setText("我是文本");
        // 这里的300设置的是px
        LinearLayout.LayoutParams textLayoutParams = new LinearLayout.LayoutParams(  300, 300);
//        textview.setLayoutParams(textLayoutParams);
//        linearLayout.addView(textview);
        linearLayout.addView(textview,textLayoutParams);
    }

ViewPager

类似于左右滑动的轮播图===屏幕之间左右切换

重点:明白配置ViewPager作为容器的适配器

适配器代码:

public class ViewPagerAdapter  extends PagerAdapter {
    List<View> viewList;
​
    public ViewPagerAdapter(List<View> viewList) {
        this.viewList = viewList;
    }
​
    @Override
    public int getCount() {
        return viewList.size();
    }
​
    @Override
    public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
        return view == object;
    }
​
    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
        container.addView(viewList.get(position),0);
        return viewList.get(position);
    }
​
    @Override
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        container.removeView(viewList.get(position));
    }
}

主方法:加载布局文件并将其转换成View对象的,用于在Android应用程序中显示用户界面,填充到主视图中。

/**
 * 测试ViewPager
 */
public void testViewPager(){
    setContentView(R.layout.activity_main_view_pager);
    LayoutInflater lf = getLayoutInflater().from(this);
    View view1 = lf.inflate(R.layout.view_pager_layout1, null);
    View view2 = lf.inflate(R.layout.view_pager_layout2, null);
    View view3 = lf.inflate(R.layout.view_pager_layout3, null);
    List<View> viewList = new ArrayList<>();
    viewList.add(view1);
    viewList.add(view2);
    viewList.add(view3);
​
    ViewPager viewPager = findViewById(R.id.vp);
    ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(viewList);
    viewPager.setAdapter(viewPagerAdapter);
}
<?xml version="1.0" encoding="utf-8"?>
<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">
​
    <!-- 效果,屏幕之间左右切换,像全屏的轮播图 -->
    <androidx.viewpager.widget.ViewPager
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/vp"
        />
​
​
​
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="#ff0000"
    android:layout_height="match_parent">
​
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="layout1"
        android:textSize="80dp"
        />
</LinearLayout>

Fragment

演示Fragment

类似于web中的iframe,点击一条栏目,该栏目的内容显示在Fragment中。

1、有自己的生命周期,可以嵌入到activity中,并且fragment可以复用

可以在activity在运行的时候动态添加删除,有自己的响应事件。

像是一个子activity

2、必须在activity中才能运行。所以其生命周期受到activity的限制。

代码:

新建Fragment,注意不是class

package com.pshdhx.demo1.fragment;
​
import android.os.Bundle;
​
import androidx.fragment.app.Fragment;
​
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
​
import com.pshdhx.demo1.R;
​
​
public class BlankFragment1 extends Fragment {
​
    private View root;
    TextView tv;
​
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
​
    }
​
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        if(root == null){
            root = inflater.inflate(R.layout.fragment_blank1,container,false);
        }
        tv = root.findViewById(R.id.tv_fragment);
        Button btn = root.findViewById(R.id.btn_fragment);
​
        btn.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                tv.setText("hello fragment hhh");
            }
        });
​
        return root;
    }
}

2、在新建Fragment的时候,自动把xml文件给添加好了,改布局为LinearLayout

<?xml version="1.0" encoding="utf-8"?>
<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=".fragment.BlankFragment1">
​
    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:text="hello_blank_fragment----first"
        android:id="@+id/tv_fragment"
        />
​
    <Button
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:id="@+id/btn_fragment"
        android:text="fragment中的按钮"
        />
​
</LinearLayout>

3、将Fragment的xml绑定到主布局中

<?xml version="1.0" encoding="utf-8"?>
<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">
<!--    测试fragment-->
    <fragment
        android:name="com.pshdhx.demo1.fragment.BlankFragment1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/fm"
        />
​
</LinearLayout>

4、主Activity绑定主布局

   
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_main);
//        setContentView(R.layout.activity_main3);
//        testRecyclerView();
//        testBujianDonghua();
//        testPropertyAnimation1();
        //testViewPager();
        testFragment();
    }
public void testFragment(){
    setContentView(R.layout.activity_main_fragment);
}

动态切换fragment

主方法:

public void testFragment2(){
    setContentView(R.layout.activity_main_fragment2);
    Button btn1 = findViewById(R.id.btn1);
    Button btn2 = findViewById(R.id.btn2);
    btn1.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View view) {
            replaceFragment(new BlankFragment1());
        }
    });
​
    btn2.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View view) {
            replaceFragment(new ItemFragment());
        }
    });
}
   //动态切换fragment
    public void replaceFragment(Fragment fragment){
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.replace(R.id.frameLayout,fragment);
        transaction.addToBackStack(null);//入栈操作,方便手机下边的返回按钮操作,防止一点直接返回到桌面
        transaction.commit();
    }

主视图:

<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/btn1"
    android:text="change"/>
​
<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/btn2"
    android:text="replace"/>
​
<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffff00"
    android:id="@+id/frameLayout"/>

新建两个Fragment 1个是空的 1个是item的,他们将放置在frameLayout的布局中,进行切换。

Activity与Fragment通信

Activity传递信息,使用Bundle对象

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Bundle bundle = getArguments();
    String message = (String) bundle.get("message");
    String message2 = bundle.getString("message");
    Log.e("pansd--", "onCreate: "+message+"---"+message2 );
​
}
Fragment获取信息,BlankFragment1.java

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Bundle bundle = getArguments();
    String message = (String) bundle.get("message");
    String message2 = bundle.getString("message");
    Log.e("pansd--", "onCreate: "+message+"---"+message2 );
​
}

Fragment与Activity相互通信

利用面向对象的接口 MainActivity.java

 /**
     * 1、测试Fragment的事件是小的activity
     * 2、测试fragment的切换
     * 3、利用IFragment接口测试fragment与Activity的通信
     */
    public void testFragment2(){
        setContentView(R.layout.activity_main_fragment2);
        Button btn1 = findViewById(R.id.btn1);
        btn1.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                //activity给fragment传递信息
                BlankFragment1 bf1 = new BlankFragment1();
                bf1.setFragmentCallback(new IFragmentCallback() {
                    @Override
                    public void sendMsgToActivity(String msg) {
//                        Log.e(TAG, "sendMsgToActivity: "+msg);
                        Toast.makeText(MainActivity.this,msg,Toast.LENGTH_SHORT).show();
                    }
​
                    @Override
                    public String getMsgFromActivity(String msg) {
                        return "hello fragment,this msg is from activity";
                    }
                });
                replaceFragment(bf1);
            }
        });
    }

BlankFragment1.java

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    if(root == null){
        root = inflater.inflate(R.layout.fragment_blank1,container,false);
    }
    Button btn = root.findViewById(R.id.btn_fragment);
    btn.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View view) {
            String msg = fragmentCallback.getMsgFromActivity("null");
            Toast.makeText(BlankFragment1.this.getContext(),msg,Toast.LENGTH_SHORT).show();
            fragmentCallback.sendMsgToActivity("hello activity,this msg from fragment");
​
        }
    });
​
    return root;
}

Debug流程走一遍之后,点击按钮,会先调用blank_fragment中的onClick方法,里边的方法会跳转到MainActivity中的onclick的方法,进而实现类似传递的效果。前提是接口被调用.[black_fragment和MainActitity的onclick方法都会被调用到]

Fragment的生命周期

Fragment的使用过程

1、点击按钮,打开Fragment

onCreate->onCreateView->onActitityCreated->onStart->onResume【即将可见,并开始响应用户输入】

2、直接返回到手机桌面

onPause->onStop

3、重新打开桌面

onStart->onResume

4、按后退键【整个应用彻底退出】

onPause->onStop->onDestroyView->onDestory->onDetach

5、如果在事务中,使用replace【替换,activity替换,先销毁之前的view,再加载新的view】fragment

onPause->onStop->onDestoryView

6、替换了之后,在按返回键

onCreateView【和5的最后一个相对应】->onActivityCreated->onstart->onResume

7、直接叉掉app

onDestory->onDetach

Fragment与PageView联合使用

viewPager2简介

先写下ViewPager2组件的介绍,优点是可以懒加载。

1、适配器

public class ViewPager2Adapter  extends RecyclerView.Adapter<ViewPager2Adapter.ViewPage2ViewHolder> {
​
​
    private List<String> titleList = new ArrayList<>();
    private List<Integer> colorList = new ArrayList<>();
​
    private ViewPage2ViewHolder holder;
​
    public ViewPager2Adapter(List<String> titleList, List<Integer> colorList, ViewPage2ViewHolder holder) {
        this.titleList = titleList;
        this.colorList = colorList;
        this.holder = holder;
    }
​
    public ViewPager2Adapter() {
​
        for (int i = 0; i < 10; i++) {
            titleList.add("title---" + i);
        }
        colorList.add(R.color.white1 );
        colorList.add(R.color.white2 );
        colorList.add(R.color.white3 );
        colorList.add(R.color.white4 );
        colorList.add(R.color.white1 );
        colorList.add(R.color.teal_200 );
        colorList.add(R.color.purple_700 );
        colorList.add(R.color.purple_500 );
        colorList.add(R.color.purple_200 );
        colorList.add(R.color.white1);
    }
​
    @NonNull
    @Override
    public ViewPage2ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new ViewPage2ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_pager, parent, false));
    }
​
    @Override
    public void onBindViewHolder(@NonNull ViewPage2ViewHolder holder, int position) {
        holder.tv.setText(titleList.get(position));
        holder.container.setBackgroundResource(colorList.get(position));
    }
​
​
    //这个有点重要呀,没有的话,界面为空!!
    @Override
    public int getItemCount() {
        return colorList.size();
    }
​
    class ViewPage2ViewHolder extends RecyclerView.ViewHolder{
​
        TextView tv;
        RelativeLayout container;
​
        public ViewPage2ViewHolder(@NonNull View itemView) {
            super(itemView);
            container = itemView.findViewById(R.id.container);
            tv = itemView.findViewById(R.id.tv);
        }
    }

2、主类

public class MainActivity extends AppCompatActivity {
​
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
​
        ViewPager2 viewPage2 = findViewById(R.id.view_pager_2);
        viewPage2.setAdapter(new ViewPager2Adapter());
​
    }
}
ViewPager与Fragment实现翻页效果

1、自定义适配器(Fragment和View一块的)

package com.pshdhx.viewpager2.adapter;
​
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager2.adapter.FragmentStateAdapter;
​
import java.util.List;
​
public class MyFragmentPageAdapter  extends FragmentStateAdapter {
    private List<Fragment> fragmentList;
​
    public MyFragmentPageAdapter(@NonNull FragmentActivity fragmentActivity, List<Fragment> fragmentList) {
        super(fragmentActivity);
        this.fragmentList = fragmentList;
    }
​
    public MyFragmentPageAdapter(@NonNull Fragment fragment, List<Fragment> fragmentList) {
        super(fragment);
        this.fragmentList = fragmentList;
    }
​
    public MyFragmentPageAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle, List<Fragment> fragmentList) {
        super(fragmentManager, lifecycle);
        this.fragmentList = fragmentList;
    }
​
    @NonNull
    @Override
    public Fragment createFragment(int position) {
        return fragmentList.get(position);
    }
​
    @Override
    public int getItemCount() {
        return fragmentList.size();
    }
}

2、主方法

public class MainActivity extends AppCompatActivity {
​
    private ViewPager2 viewPager2;
​
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
​
//        ViewPager2 viewPager2 = findViewById(R.id.view_pager_2);
//        viewPager2.setAdapter(new ViewPager2Adapter());
        initPage();
    }
​
    /**
     * 测试Viewpage2与Fragment结合使用
     */
    private void initPage() {
        viewPager2 = findViewById(R.id.view_pager_2);
        List<Fragment> fragmentList = new ArrayList<>();
        fragmentList.add(BlankFragment.newInstance("微信聊天"));
        fragmentList.add(BlankFragment.newInstance("通讯录"));
        fragmentList.add(BlankFragment.newInstance("发现"));
        fragmentList.add(BlankFragment.newInstance("我"));
        MyFragmentPageAdapter myFragmentPageAdapter = new MyFragmentPageAdapter(getSupportFragmentManager(), getLifecycle(), fragmentList);
        viewPager2.setAdapter(myFragmentPageAdapter);
    }
}

3、Fragment的配置方法

public class BlankFragment extends Fragment {
​
    private View rootView;
​
    private static final String ARG_TEXT = "param1";
    private String mTextString ;
​
    public BlankFragment() {
    }
​
​
    public static BlankFragment newInstance(String param1) {
        BlankFragment fragment = new BlankFragment();
        Bundle args = new Bundle();
        args.putString(ARG_TEXT, param1);
        fragment.setArguments(args);
        return fragment;
    }
​
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mTextString = getArguments().getString(ARG_TEXT);
        }
    }
​
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        if(rootView == null){
            rootView = inflater.inflate(R.layout.fragment_blank, container, false);
        }
        initView();
        return rootView;
    }
​
    private void initView() {
        TextView textView = rootView.findViewById(R.id.fragment_tv);
        textView.setText(mTextString);
    }
}

案例:实现微信主界面跟随底部按钮的切换,或者是滑动切换。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
​
    private ViewPager2 viewPager2;
​
    private LinearLayout llchat,llContacts,llFind,llProfile;
    private ImageView ivChat,ivContacts,ivFind,ivProfile,ivCurrent;
​
​
​
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
​
//        ViewPager2 viewPager2 = findViewById(R.id.view_pager_2);
//        viewPager2.setAdapter(new ViewPager2Adapter());
        initPage();
        initTabView();
    }
​
​
​
    /**
     * 测试Viewpage2与Fragment结合使用
     */
    private void initPage() {
        viewPager2 = findViewById(R.id.view_pager_2);
        List<Fragment> fragmentList = new ArrayList<>();
        //设置fragment,主显示区域的内容
        fragmentList.add(BlankFragment.newInstance("微信聊天"));
        fragmentList.add(BlankFragment.newInstance("通讯录"));
        fragmentList.add(BlankFragment.newInstance("发现"));
        fragmentList.add(BlankFragment.newInstance("我"));
        MyFragmentPageAdapter myFragmentPageAdapter = new MyFragmentPageAdapter(getSupportFragmentManager(), getLifecycle(), fragmentList);
        viewPager2.setAdapter(myFragmentPageAdapter);
        //设置viewPager2的滑动窗口效果
        viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                super.onPageScrolled(position, positionOffset, positionOffsetPixels);
            }
​
            @Override
            public void onPageSelected(int position) {
                super.onPageSelected(position);
                changeTab(position);
            }
​
            @Override
            public void onPageScrollStateChanged(int state) {
                super.onPageScrollStateChanged(state);
            }
        });
    }
​
    //初始化底部边框【四个tab=四个LinearLayout,还有每个tab中的图片】
    private void initTabView() {
        llchat = findViewById(R.id.id_tab_weixin);
        llchat.setOnClickListener(this);
        llContacts = findViewById(R.id.id_tab_contact);
        llContacts.setOnClickListener(this);
        llFind = findViewById(R.id.id_tab_find);
        llFind.setOnClickListener(this);
        llProfile = findViewById(R.id.id_tab_profile);
        llProfile.setOnClickListener(this);
​
        ivChat = findViewById(R.id.id_iv_weixin);
        ivContacts = findViewById(R.id.id_iv_contact);
        ivFind = findViewById(R.id.id_iv_find);
        ivProfile = findViewById(R.id.id_iv_profile);
​
        //设置第一张图片为默认选中,且为当前图片ImageView
        ivChat.setSelected(true);
        ivCurrent = ivChat;
    }
​
​
    public void changeTab(int position){
        //取消图片选中
        ivCurrent.setSelected(false);
        switch (position){
            case R.id.id_tab_weixin:
            case 0:
                //当前图片是选中状态
                ivChat.setSelected(true);
                //当前图片为此图片
                ivCurrent = ivChat;
                //当前fragment为第0个Fragment的内容
                viewPager2.setCurrentItem(0);
                break;
            case R.id.id_tab_contact:
            case 1:
                ivContacts.setSelected(true);
                ivCurrent = ivContacts;
                viewPager2.setCurrentItem(1);
                break;
            case R.id.id_tab_find:
            case 2:
                ivFind.setSelected(true);
                ivCurrent = ivFind;
                viewPager2.setCurrentItem(2);
                break;
            case R.id.id_tab_profile:
            case 3:
                ivProfile.setSelected(true);
                ivCurrent = ivProfile;
                viewPager2.setCurrentItem(3);
                break;
        }
    }
​
    @Override
    public void onClick(View view) {
        changeTab(view.getId());
    }

底部footer的xml,主要被主视图include即可

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="55dp"
    android:background="#ff0000"
    android:orientation="horizontal">
​
<!--    设置四个footer的子组件-->
    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:layout_gravity="center"
        android:gravity="center"
        android:orientation="vertical"
        android:id="@+id/id_tab_weixin">
        <ImageView
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:id="@+id/id_iv_weixin"
            android:background="@drawable/tab_weixin">
        </ImageView>
        <TextView
            android:layout_width="32dp"
            android:layout_height="wrap_content"
            android:id="@+id/text_weixin"
            android:gravity="center"
            android:text="微信"/>
    </LinearLayout>
​
    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:layout_gravity="center"
        android:gravity="center"
        android:orientation="vertical"
        android:id="@+id/id_tab_contact">
        <ImageView
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:id="@+id/id_iv_contact"
            android:background="@drawable/tab_contact">
        </ImageView>
        <TextView
            android:layout_width="32dp"
            android:layout_height="wrap_content"
            android:id="@+id/text_contact"
            android:gravity="center"
            android:text="通讯录"/>
    </LinearLayout>
​
    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:layout_gravity="center"
        android:gravity="center"
        android:orientation="vertical"
        android:id="@+id/id_tab_find">
        <ImageView
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:id="@+id/id_iv_find"
            android:background="@drawable/tab_find">
        </ImageView>
        <TextView
            android:layout_width="32dp"
            android:layout_height="wrap_content"
            android:id="@+id/text_find"
            android:gravity="center"
            android:text="发信"/>
    </LinearLayout>
​
    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:layout_gravity="center"
        android:gravity="center"
        android:orientation="vertical"
        android:id="@+id/id_tab_profile">
        <ImageView
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:id="@+id/id_iv_profile"
            android:background="@drawable/tab_profile">
        </ImageView>
        <TextView
            android:layout_width="32dp"
            android:layout_height="wrap_content"
            android:id="@+id/text_profile"
            android:gravity="center"
            android:text="我"/>
    </LinearLayout>
​
</LinearLayout>

include底部footer视图

<?xml version="1.0" encoding="utf-8"?>
<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">
​
<!--    设置显示区域页面-->
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/view_pager_2"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="#00ff00" />
​
<!--    引入footer的组件-->
    <include layout="@layout/bottom_layout"/>
​
</LinearLayout>

Activity

一个activity对应一个布局文件,一个activity必须要到清单文件中注册。

实例:一个activity跳转到另外一个activity

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
​
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
​
    <activity android:name=".MainActivity2"></activity>
</application>
public void startActivity(){
    startActivity(new Intent(this,MainActivity2.class));
}

Activity的生命周期

Service

service和activity类似,也是一个组件,运行在后台,需要在清单文件中注册使用【注意包名和路径】

<service android:name=".service.MyService01"/>

生命周期:

startService【执行onCreate->onStartCommand->onStart】

stopService【执行onDestory】

bindService【执行onCreate->onBind】

unbindService【执行onUnbind->onDestory】

消息广播

//测试动态广播
public class MyRevicer_Dynamic extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.e("pansd-动态接收者", "onReceive: ");
    }
}

注册到清单中,xml注册可能失效,但是java注册是可以的。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main4);
​
    MyRevicer_Dynamic revicer_dynamic = new MyRevicer_Dynamic();
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction("com.pshdhx.revicer_dynamic");
    registerReceiver(revicer_dynamic,intentFilter);
}
​
​
//动态广播按钮
public void sendDynamicAction(View view) {
    Intent intent = new Intent();
    intent.setAction("com.pshdhx.revicer_dynamic");
    sendBroadcast(intent);
}
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="动态注册广播 发送广播区域"
    android:textSize="20dp"
    android:layout_marginTop="100dp"
    android:layout_gravity="center_horizontal"/>
<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="发送动态广播"
    android:onClick="sendDynamicAction"

android常用框架

热修复

见官方的demo文档。

主要流程是,将app的id注册到腾讯的buglg中,修复bug完成后,将修复包上传到buglg中,然后有bug的app会收到提醒,然后去buglg中下载补丁包,下载完成后,会强制重启app,此时已经完成修复。

官网:https://graph.qq.com/

官方文档:Android SDK 使用指南 - Bugly 文档

github的Demo地址:https://github.com/BuglyDevTeam/Bugly-Android-Demo/tree/master/BuglyHotfixDemo

高德地图SDK

1、搜索高德地图开放平台,注册登录

2、创建应用,获取keytool的秘钥,会生成appid,配置到gradle

3、通过gradle下载高德地图的依赖,或者是通过相关下载获取arr包到lib目录下,在用gradle增加lib目录,并引入arr包,可以避免冲突

4、开启配置{相关权限的读取配置、设置高德key的配置【生成的applicationID】到AndroidManifest.xml清单中}

5、设置layout.xml,引入地图。在Activity中按照文档和demo开始给地图添加功能。

6、POI关键词搜索功能

Glide图片加载库

可以加载本APP下的,手机内存中的,或是网络中的图片资源。

Glide v4 : 快速高效的Android图片加载库

GitHub - bumptech/glide: An image loading and caching library for Android focused on smooth scrolling

implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
ImageView imageView = findViewById(R.id.iv);
Glide.with(this).load("https://img0.baidu.com/it/u=1435639120,2241364006&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500").into(imageView);
​
​
//        Glide.with(this)
//                .load("https://img0.baidu.com/it/u=1435639120,2241364006&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500")
//                .apply(requestOptions)
//                .transition(DrawableTransitionOptions.withCrossFade(fadeFactory))
//                .transform(new CircleCrop())//设置圆
//
//                .into(imageView);
简化操作:

@GlideExtension
public class MyAppGlideExtension extends AppGlideModule {
​
​
    private MyAppGlideExtension(){
​
    }
​
    @GlideOption
    public static BaseRequestOptions<?> defaultImg(BaseRequestOptions<?> options){
        return options.placeholder(R.drawable.ic_launcher_foreground)
                .error(R.drawable.error)
                .fallback(R.drawable.fallback_null);
    }
}
@GlideModule
public class MyAppGlideModule extends AppGlideModule {
}
make project下,然后使用

//使用此类,必须先make project下
GlideApp.with(this).load("xxxx").defaultImg()
.into(imageView);

网络加载框架

OKHttp

Http上传数据的编码格式类型【content-type】

HTTP content-type | 菜鸟教程

  • application/json: JSON数据格式

  • multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式

public class MainActivity extends AppCompatActivity {
​
    private OkHttpClient httpClient;
    private String TAG = "pansd--";
    private TextView textView;
​
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
​
        httpClient = new OkHttpClient();
        textView = findViewById(R.id.reponseText);
        View getSyncBtn = findViewById(R.id.getSync);
        View getASyncBtn = findViewById(R.id.getASync);
        View postSyncBtn = findViewById(R.id.postSync);
        View postASyncBtn = findViewById(R.id.postASync);
        Request request = new Request.Builder().url("https://www.httpbin.org/get?a=1&b=2").build();
​
​
​
        getSyncBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(){
                    @Override
                    public void run() {
                        Call call = httpClient.newCall(request);
                        try {
                            Response response = call.execute();
                            Log.e(TAG, "testOkHttp: "+response.body().string() );
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }.start();
            }
        });
​
        getASyncBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Call call = httpClient.newCall(request);
                call.enqueue(new Callback() {
                    @Override
                    public void onFailure(@NotNull Call call, @NotNull IOException e) {
​
                    }
​
                    @Override
                    public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                        if(response.isSuccessful()){
                            Log.e(TAG, "onResponse: "+response.body().string() );
                        }
                    }
                });
            }
        });
​
        postSyncBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(){
                    @Override
                    public void run() {
                        FormBody formBody = new FormBody.Builder().add("a", "1").add("b", "2").build();
                        Request requestPostSync = new Request.Builder().url("https://www.httpbin.org/post").post(formBody).build();
                        Call call = httpClient.newCall(requestPostSync);
                        try {
                            Response response = call.execute();
                            Log.e(TAG, "run: "+response.body().string() );
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }.start();
            }
        });
​
        postASyncBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                FormBody formBody = new FormBody.Builder().add("a", "1").add("b", "2").build();
                Request requestPostSync = new Request.Builder().url("https://www.httpbin.org/post").post(formBody).build();
                Call call = httpClient.newCall(requestPostSync);
                call.enqueue(new Callback() {
                    @Override
                    public void onFailure(@NotNull Call call, @NotNull IOException e) {
​
                    }
​
                    @Override
                    public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
​
                        if(response.isSuccessful()){
                            Log.e(TAG, "onResponse: "+response.body().string() );
                        }
                    }
                });
            }
        });
​
        Button uploadFileBtn = findViewById(R.id.fileUpload);
        uploadFileBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e(TAG, "onClick: "+ Environment.getExternalStorageDirectory() );
                File file = new File("C:\\Users\\Lenovo\\Desktop\\null.png");
                MultipartBody multipartBody = new MultipartBody.Builder()
                        .addFormDataPart("file", file.getName(), RequestBody.create(file, MediaType.parse("image/png")))
                        .build();
​
                Request fileRequest = new Request.Builder().url("https://www.httpbin.org/post").post(multipartBody).build();
                Call call = httpClient.newCall(fileRequest);
                call.enqueue(new Callback() {
                    @Override
                    public void onFailure(@NotNull Call call, @NotNull IOException e) {
​
                        Log.e(TAG, "onFailure: "+e +"");
                    }
​
                    @Override
                    public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                        if(response.isSuccessful()){
                            Log.e(TAG, "文件上传__onClick: "+response.body().string() );
                        }
                    }
                });
            }
        });
    }

OKHTTP的自定义配置

okhttp新增拦截器+保存cookie

public void testInterceptorAndCookie(View view) {
​
        new Thread() {
            @Override
            public void run() {
                Interceptor interceptor = new Interceptor() {
                    @NotNull
                    @Override
                    public Response intercept(@NotNull Chain chain) throws IOException {
                        Request request = chain.request().newBuilder().addHeader("os", "android")
                                .addHeader("username", "pansd").build();
                        Response response = chain.proceed(request);
                        return response;
                    }
//        Request request = new Request.Builder().url("https://httpbin.org/get?a=1&b=2").build();
//        Call call = okHttpClient.newCall(request);
//
//        call.enqueue(new Callback() {
//            @Override
//            public void onFailure(@NotNull Call call, @NotNull IOException e) {
//                Log.e(TAG, "onFailure: "+"error"+e );
//            }
//
//            @Override
//            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
//
//                if(response.isSuccessful()){
//                    Log.e(TAG, "testInterceptorAndCookie: "+response.body().string() );
//                }
//            }
//        });
                };
​
                OkHttpClient okHttpClient = new OkHttpClient.Builder()
                        .addInterceptor(interceptor)
                        .cache(new Cache(new File("C:\\Users\\Lenovo\\Desktop"), 1024 * 1024))
                        .cookieJar(new CookieJar() {
                            @Override
                            public void saveFromResponse(@NotNull HttpUrl httpUrl, @NotNull List<Cookie> list) {
                                cookieList = list;
                            }
​
                            @NotNull
                            @Override
                            public List<Cookie> loadForRequest(@NotNull HttpUrl httpUrl) {
                                if ("www.wanandroid.com".equals(httpUrl.host())) {
                                    return cookieList;
                                }
                                return cookieList;
                            }
                        })
                        .build();
​
​
                FormBody formBody = new FormBody.Builder()
                        .add("username", "hello_pans")
                        .add("password", "pan123")
                        .build();
                Request request1 = new Request.Builder()
                        .url("https://www.wanandroid.com/user/login")
                        .post(formBody)
                        .build();
​
                Call call1 = okHttpClient.newCall(request1);
                try {
                    Response response = call1.execute();
                    Log.e(TAG, "testInterceptorAndCookie: " + response.body().string());
                } catch (IOException e) {
                    e.printStackTrace();
                }
​
​
//        call1.enqueue(new Callback() {
//            @Override
//            public void onFailure(@NotNull Call call, @NotNull IOException e) {
//                Log.e(TAG, "testInterceptorAndCookie: "+e);
//
//            }
//
//            @Override
//            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
//
//                Log.e(TAG, "testInterceptorAndCookie: "+response.body().string() );
//
//            }
//        });
​
                Request req = new Request.Builder()
                        .url("https://www.wanandroid.com/lg/collect/list/0/json")
                        .build();
​
                Call newCall = okHttpClient.newCall(req);
                newCall.enqueue(new Callback() {
                    @Override
                    public void onFailure(@NotNull Call call, @NotNull IOException e) {
​
                        Log.e(TAG, "onFailure: "+e );
                    }
​
                    @Override
                    public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                        Log.e(TAG, "onResponse: " + response.body().string());
                    }
                });
            }
        }.start();
​
​
    }

Retrofit

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/256211.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GO 的 socks5代理 编写

这里学习一下 socks5 代理的编写 网上有很多 学习一下 go 语言实战入门案例之实现Socks5 - 知乎 滑动验证页面 socks5协议原理学习-腾讯云开发者社区-腾讯云 (tencent.com) 首先我们要了解一下socks5的代理方式 socks5 是基于 认证建立连接转发数据 所形成的代理 我们只…

【前端小点】谷歌地图MarkerClusterer,点分类聚合

谷歌地图点分类聚合 本篇文章记录&#xff0c;如何在谷歌地图中进行点聚合&#xff0c;并分类进行聚合&#xff0c;如何修改聚合后的聚合样式。 之前有一篇博文是记录如何在vue中使用谷歌地图&#xff0c;可参考&#xff0c;传送门&#xff1a; vue中使用谷歌地图绘制一个或多…

Echarts自定义样式实现3D柱状图-长方体-圆柱体,两种样式

Echarts自定义样式实现3D柱状图-长方体-圆柱体&#xff0c;两种样式 效果图代码series配置项目 效果图 长方体 柱状体 代码 <!--此示例下载自 https://echarts.apache.org/examples/zh/editor.html?cbar3d-dataset&gl1 --> <!DOCTYPE html> <html lang…

vp与vs联合开发-通过FrameGrabber连接相机

添加控件 1.CogRecordDisplay 控件 用于显示图像 初始化相机对象方法 //启动窗体时 调用初始化相机方法 //封装相机关闭方法 //窗体关闭时 调用相机关闭方法 拍照 设置采图事件 // 保存图像 设置曝光按钮事件 1.可变参数

C语言——完数难题

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 生命如同寓言&#xff0c;其价值不在于…

智能 GPT 图书馆又重生了

智能 GPT 图书馆又重生了 作者&#xff1a;程序员小白条 1&#xff09;概述 自从大二寒假准备开始筹备这个项目&#xff0c;到现在已经一年了&#xff0c;这个项目能维护一年&#xff0c;不愧是我.jpg。本来这个项目只是想练练手&#xff0c;因为那时候刚学完 Spring Boot2 V…

Qt实现动画的2种方式

由于我之前是写java的所以在学习Qt的时候感觉会有点熟悉&#xff0c;因为Qt就是 用c写&#xff0c;而java底层也是c实现的 先看效果&#xff1a; 一、使用QMovie 这种方式我目前是用来加载gif图的&#xff0c;很简单噢&#xff0c;只不过我是加载的本地的路径&#xff0c;如…

中国1KM分辨率年均降水量数据集(1901-2022)

数据名称&#xff1a;中国1KM分辨率年均降水量数据集&#xff08;1901-2022&#xff09; 数据时间&#xff1a;1901年至今 数据空间位置&#xff1a;全国 数据格式&#xff1a;tiff 数据空间分辨率&#xff1a;1kM 数据坐标系&#xff1a;WGS1984 数据简介&#xff1a;该…

【设计模式--行为型--访问者模式】

设计模式--行为型--访问者模式 访问者模式定义结构案例优缺点使用场景扩展分派动态分派静态分派双分派 访问者模式 定义 封装一些作用于某种数据结构中的各元素的操作&#xff0c;它可以在不改变这个数据结构的前提下定义作用于这些元素的新操作。 结构 抽象访问者角色&…

【Java异常】idea 报错:无效的目标发行版:17 的解决办法

【Java异常】idea 报错&#xff1a;无效的目标发行版&#xff1a;17 的解决办法 一&#xff0c;问题来源 springcloud的第一个demo项目就给我干趴了 二、原因分析 java: 无效的目标发行版: 17 原因就是 JDK 版本不对。从 IDEA 编辑器中可以找到问题的原因所在&#xff0c;…

Linux--fork创建子进程详解

目录 一.初识fork函数 二.fork的返回值 三.fork原理 1.fork是如何创建子进程的&#xff1f; 2.为什么fork会有两个返回值&#xff1f; 3.为什么父进程的返回值是子进程的pid&#xff0c;子进程返回值是0&#xff1f; 4.fork之后&#xff0c;父子进程谁先运行&#xff1f;…

【Python 基础】-- 在 mac OS 中安装 多个 python 版本

目录 1、需求 2、实现 2.1 安装 pyenv 2.2 安装 pyenv-virtualenv 2.3 配置环境变量 2.4 创建 python 3.9.9 的环境 2.5 激活环境&#xff0c;在当前项目目录中使用&#xff0c;即执行 python 1、需求 由于项目所依赖的 python 版本有多个&#xff0c;需要在不同的 pyth…

axios请求封装

http.js // untils / http.js //导入封装好的axios实例 import request from ./requestconst http {get(url, params) {const config {method: get,url: url}if (params) config.params paramsreturn request(config)},post(url, params) {const config {method: post,url…

深入浅出RPC:选取适合自己的RPC

文章目录 1、RPC概念&&背景1.1、RPC背景 1.2、RPC是什么&#xff0c;什么时候需要用到&#xff1f;2、进程间的通信 - IPC与RPC2.1、什么是IPC2.2、IPC与RPC联系 3、RPC的实现3.1、RPC实现的基本思路3.2、RPC实现的扩展方向 4、RPC的选择 1、RPC概念&&背景 1.…

Elasticsearch——快速入门

从零基础的内容开始介绍Elasticsearch&#xff0c;主要包含以下内容&#xff1a; Elasticsearch的定义、优点&#xff0c;以及典型的业务场景。Elasticsearch中重要的概念。Elasticsearch典型的接入方式。安装Elasticsearch。使用Kibana调试Elasticsearch。Elasticsearch节点的…

【LeetCode刷题笔记(8-3)】【Python】【接雨水】【双指针】【困难】

文章目录 引言接雨水题目描述提示 解决方案3&#xff1a;【双指针】结束语 接雨水 【LeetCode刷题笔记&#xff08;8-1&#xff09;】【Python】【接雨水】【动态规划】【困难】 【LeetCode刷题笔记&#xff08;8-2&#xff09;】【Python】【接雨水】【单调栈】【困难】 引言…

从如何使用到如何实现一个Promise

promise是什么&#xff1f;主要用来解决什么问题&#xff1f; Promise是异步编程的一种解决方案&#xff0c;比传统解决方案--回调函数和事件--更合理更强大。 Promise特点&#xff1a; &#xff08;1&#xff09;对象的状态不受外界影响。Promise对象代表一个异步操作&…

ModuleNotFoundError: No module named ‘openai.error‘

ModuleNotFoundError: No module named ‘openai.error’ result self.fn(*self.args, **self.kwargs) File “H:\chatGPTWeb\chatgpt-on-wechat\channel\chat_channel.py”, line 168, in _handle reply self._generate_reply(context) File “H:\chatGPTWeb\chatgpt-on-wec…

2023_Spark_实验二十九:Flume配置KafkaSink

实验目的&#xff1a;掌握Flume采集数据发送到Kafka的方法 实验方法&#xff1a;通过配置Flume的KafkaSink采集数据到Kafka中 实验步骤&#xff1a; 一、明确日志采集方式 一般Flume采集日志source有两种方式&#xff1a; 1.Exec类型的Source 可以将命令产生的输出作为源&…

性能加速包: SpringBoot 2.7JDK 17,你敢尝一尝吗 | 京东物流技术团队

前言 众所周知&#xff0c;SpringBoot3.0迎来了全面支持JDK17的局面&#xff0c;且最低支持版本就是JDK17&#xff0c;这就意味着&#xff0c;Spring社区将完全抛弃JDK8&#xff0c;全面转战JDK17。作为JAVA开源生态里的扛把子&#xff0c;Spring可以说是整个JAVA生态的风向标…