【Android实战-03(淘宝类APP)】(实战购物类APP)(用户系统登录注册,fragment,okhttp,Gson工具,相机相册调用)

【小白做项目-03】

本文为爱吃章鱼的熊二原创转载请说明

一、效果展示

二、项目需求

  1. 设计一个淘宝类APP
  2. 包含登陆注册功能
  3. 能够上架商品
  4. 能够购买商品
  5. 能够查看订单信息
  6. 个人用户系统
  7. 更换用户头像,修改

三、项目分析

这个项目涉及到前端和后端两个部分,作为安卓开发人员,我们主要关心前端的操作部分
在后端为我们准备好接口的情况下,这个项目的难点已经被大大简化。
我们的设计思路也显得很简单
在这里插入图片描述
根据接口,登录注册界面就很简单了
商品界面我们用recyclerview加载刷新
个人信息界面用get方法获取并显示。
判断用户登陆状态,我们用sharedPreferences保存登陆状态
相册拍照上传头像方法我们先获得对应的图片路径,再将它上传上去
联网部分我们用okhttp简化我们的联网获取信息的操作
用fragment展示我们的四个界面

四、实战操作

1.项目框架搭建

1.1导入依赖

在这里插入图片描述

1.2 Activity

在这里插入图片描述

1.3 xml文件

在这里插入图片描述

2.注册与登陆功能

注册和登陆功能只需要对接口发送信号即可
我们利用post方法上传,注意接口对我们传输数据形式的要求,这里我们以Json形式利用okhttppost信息,先建立一个内部类,包含要上传的账号和密码信息
在这里插入图片描述
下面是post的代码

 new Thread(new Runnable() {
                        @Override
                        public void run() {
                            OkHttpClient client = new OkHttpClient();
                            Gson gson = new Gson();
                            user_register use = new user_register();
                            use.account = account;
                            use.password = password;
                            MediaType JSON = MediaType.parse("application/json; charset=utf-8");
                            RequestBody requestBody = RequestBody.create(JSON, gson.toJson(use));
                            Request request = new Request.Builder()
                                    .url("http://49.232.214.94/api/register")
                                    .post(requestBody)
                                    .build();
                            Response response = null;
                            try {
                                response = client.newCall(request).execute();
                                String responseData = response.body().string();
                                user user = gson.fromJson(responseData, com.example.lego.user.class);
                                msg = user.getMsg();
                                int code = user.getCode();
                                if (code == 200) {
                                    finish();
                                    Intent intent = new Intent(register.this, login.class);
                                    startActivity(intent);

                                }
                                Looper.prepare();
                                Toast.makeText(register.this, msg, Toast.LENGTH_SHORT).show();
                                Looper.loop();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }).start();

在这部分中,我们利用gson将user转化成Json形式,在放入requestbody中进行post请求,如果post返回给我们的code是200,则表示我们注册成功,跳转到登陆界面。若不是200,则Toast显示返回给我们的信息以作提示。
同样的登陆部分采用的方法即可

3.主体界面fragment设置

按照程序设计思路,在MainActivity中我们设计了4个fragment,分别对应商城我的商店购物车四部分,我们在商城界面展示商品,在我的商店部分上架和修改商品信息,在购物车部分查看订单,在我部分进行个人用户信息的修改与查看。
新建4个fragment在这里插入图片描述
由于fragment属于activity的碎片,无法独立存在,因此,需要在mainactivity中预留一块布局给fragment以供显示,红线框住的部分即为fragment布局所占的位置,即使mainactivity中的Relativelayout部分
在这里插入图片描述
在这里插入图片描述
在fragment下方,我们设置了四个图标,以供点击不同图标达到切换fragment的目的。

3.1 fragment切换与选中状态

我们可以从这张图中发现,在我们选中商店对应的fragment时,下方对应的图标也变成亮色状态。也就是说,我们再点击下方四个图片的时候,fragment被切换了,同时对应的图片也变换了。下面我们来说一下实现原理

fragment切换
我们为图标设置一个点击事件,点击对应图标即可跳转到对应的fragment
跳转的代码如下

getSupportFragmentManager().beginTransaction().replace(R.id.fragment,centerFragment).commit();

选中状态图片变换
图片变换实际就是换了一张图片
首先找到所需的两张图片资源
在这里插入图片描述
新建drawable resource文件
在这里插入图片描述
在文件中使用selector类进行图片选择

<selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@drawable/center1" android:state_selected="true"/>
        <item android:drawable="@drawable/center2" android:state_selected="false"/>
</selector>

放入两张图片,利用selcted状态来判断选择显示那张图片
在mainactivity中的代码如下
在这里插入图片描述

对应的每一个图标的点击事件,由此达到了切换fragment和判断fragment选中状态改变底部导航栏的目的

4.商店界面

商店界面是四个fragment之一
这部分主要注重与商品的展示与点击商品进入商品详情页进行购买

4.1 商品展示

该部分的内容与《小白做项目-02(仿知乎日报)》中的内容极为相似。唯一区别在与fragment和activity的不同。fragment在依托于Activity。而同一个fragment也可以被多个Activity重复调用。因此在fragment进行操作时要getActivity或者getContext,这是与直接使用Activity比较不同的地方。

在这一部分,我们利用get请求获取所有商品的信息(或者获取一部分商品的信息,之后利用刷新加载),展示部分我们选择以Recyclerview来进行展示。
这里我放上部分代码进行讲解

final Thread thread =new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(100);
                    final OkHttpClient okHttpClient = new OkHttpClient();
                    Gson gson = new Gson();
                    Request request = new Request.Builder()
                            .url("http://49.232.214.94/api/goods")
                            .build();
                    Response response = okHttpClient.newCall(request).execute();
                    String responseData = response.body().string();
                    final good good =gson.fromJson(responseData, com.example.lego.good.class);
                    final com.example.lego.good.DataBean dataBean =good.getData();
                    final List<com.example.lego.good.DataBean.GoodsBean> goodsBeanList = dataBean.getGoods();
                    list.clear();
                    getActivity().runOnUiThread(new Runnable() {
                        @Override
                        public void run() {

                            for( i=0;i<40;i++)
                            {
                                Map<String,Object> map=new HashMap<>();
                                com.example.lego.good.DataBean.GoodsBean goodsBean =goodsBeanList.get(i);
                                String name=goodsBean.getName();
                                int id =goodsBean.getGood_id();
                                String url=goodsBean.getImg();
                                String price=goodsBean.getPrice();
                                map.put("id",id);
                                map.put("name",name);
                                map.put("price",price);
                                map.put("image",url);
                                list.add(map);
                            }
                            count=goodsBeanList.size();
                            goodAdapter =new GoodAdapter(CenterFragment.this,list);
                            recyclerView.setAdapter(goodAdapter);
                            recyclerView.setLayoutManager(new GridLayoutManager(getContext(),2));


                        }
                    });

这是fragment中的代码,可以看到与在Activity中写并无太大差别。无非是将在Activity中的this换成了getActivity。
例外一点值得注意的是,我这里采取了一排两行的展示方法,对应的代码部分是setlayoutManager

recyclerView.setLayoutManager(new GridLayoutManager(getContext(),2));

在这行代码中的第二参数为2。即我选择以一行两个item的形式来展示商品。Recyclerview的具体使用操作可以参考本专栏的第二个项目,有详细的说明。这里我们就不在赘述。最后该页面的效果如下

4.2 商品详情页与购买操作

在商品详情页中,需要一个类似与淘宝界面的商品详情页,既能够看见商品的情况,也可以选择购买商品

在这一夜中,商品详情部分我们只需要在点击商品进入商品详情页的时候,将对应的商品序号post发送到后端,后端就会返回给我们对应商品得到详情信息。我们需要做的就是把商品的信息展示出来即可。
该页下方得到购买栏部分。点击加减号会加减需要购买的商品数量。之后点击加入购物车,系统便会将信息post到后端接口进行购买操作

但是需要注意的几点:
如果是购买自己的商品是不可以的,这部分的逻辑后端已经为我们编写好了,因此我们只需要Toast后端得到返回信息提示即可
如果购买时商品库存不够了显然也是不能购买的。这里我直接这部分的代码奉上。就不做详细讲解了。

package com.example.lego;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.google.gson.Gson;

import java.io.IOException;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
class user_order{
    int good_id;
    int goods_count;
}

public class good_info extends AppCompatActivity {
    ImageView back;
    Button add;
    Button subtract;
    ImageView img;
    TextView name;
    TextView info;
    TextView price;
    TextView restNumber;
    RelativeLayout buy;
    TextView number;
    private int num=1;
    private int length;
    int good_number;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_good_info);
        SharedPreferences sharedPreferences=getSharedPreferences("user",MODE_PRIVATE);
        back =findViewById(R.id.backToMain);
        add=findViewById(R.id.info_add);
        subtract=findViewById(R.id.info_subtract);
        buy=findViewById(R.id.buy);
        number=findViewById(R.id.buy_number);
        restNumber=findViewById(R.id.number);
        img=findViewById(R.id.info_image);
        name=findViewById(R.id.info_name);
        info=findViewById(R.id.info_info);
        price=findViewById(R.id.info_price);
        final String token =sharedPreferences.getString("token",String.valueOf(11));
        number.setText(Integer.valueOf(num).toString());
        Intent it2=getIntent();
        final Bundle bd=it2.getExtras();
         final String id=bd.getString("id");
         final int Id=Integer.parseInt(id);
        buy.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(length>10)
                {
                    Toast.makeText(good_info.this,"商品价格过高,不支持购买",Toast.LENGTH_SHORT).show();
                }
                else{
                Thread thread =new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try{
                            OkHttpClient okHttpClient =new OkHttpClient();
                            user_order order =new user_order();
                            order.good_id=Id;
                            order.goods_count=num;
                            Gson gson =new Gson();
                            MediaType JSON = MediaType.parse("application/json; charset=utf-8");
                            RequestBody requestBody =RequestBody.create(JSON,gson.toJson(order));
                            Request request = new Request.Builder()
                                    .url("*************该部分接口不对外开放*******")
                                    .addHeader("Authorization",token)
                                    .post(requestBody)
                                    .build();
                            Response response = null;
                            response = okHttpClient.newCall(request).execute();
                            String responseData = response.body().string();
                            com.example.lego.order order1 =gson.fromJson(responseData, com.example.lego.order.class);
                            int code=order1.getCode();
                            if(code ==200)
                            {
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        Toast.makeText(good_info.this,"已加入购物车",Toast.LENGTH_SHORT).show();
                                        restNumber.setText(Integer.valueOf(good_number-num).toString());
                                    }
                                });

                            }
                            else if(code==422)
                            {
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        Toast.makeText(good_info.this,"不能购买自己的商品",Toast.LENGTH_SHORT).show();
                                    }
                                });
                            }
                            else
                            {
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        Toast.makeText(good_info.this,"商品存货不够了",Toast.LENGTH_SHORT).show();
                                    }
                                });
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });
                thread.start();}


            }
        });
        subtract.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(num>1)
                {
                    num--;
                    number.setText(Integer.valueOf(num).toString());
                }
                else
                {
                    Toast.makeText(good_info.this,"最少购买一份商品",Toast.LENGTH_SHORT).show();
                }
            }
        });
        add.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                num++;
                number.setText(Integer.valueOf(num).toString());
            }
        });
        back.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
        Thread thread =new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    OkHttpClient okHttpClient =new OkHttpClient();
                    Gson gson =new Gson();
                    Request request = new Request.Builder()
                            .url("url"+id)
                            .build();
                    Response response = okHttpClient.newCall(request).execute();
                    String responseData = response.body().string();
                    final new_detail detail =gson.fromJson(responseData, com.example.lego.new_detail.class);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            new_detail.DataBean dataBean = detail.getData();
                            new_detail.DataBean.GoodBean goodBean=dataBean.getGood();
                            String good_name=goodBean.getName();
                            String good_price=goodBean.getPrice();
                            length =good_price.length();
                            String good_info =goodBean.getInfo();
                            String good_url =goodBean.getImg();
                            good_number=goodBean.getQuantity();
                            restNumber.setText("剩余数量:"+good_number);
                            name.setText(good_name);
                            price.setText(good_price);
                            info.setText(good_info);
                            Glide.with(com.example.lego.good_info.this).load(good_url).into(img);
                        }
                    });
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
    }
}

5.我的店铺

在这部分当中,很明显,第一步,我们需要获取我们已经创建的商品信息。第二步,我们能够修改我们已经上架的商品。第三步,我们可以新创建商品的信息。这就涉及到了三个接口的使用。

5.1获取我的商品信息

在这部分中,需要特别获得我的商品,根据后端写得接口。我们需要在get网络请求中的请求头中带上识别用户的token。代码如下:

Thread thread=new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try{
                            Thread.sleep(100);
                            OkHttpClient okHttpClient = new OkHttpClient();
                            Gson gson = new Gson();
                            String token =sharedPreferences.getString("token",String.valueOf(123));
                            Request request = new Request.Builder()
                                    .addHeader("Authorization",token)
                                    .url("************该接口不对外开放******")
                                    .build();
                            Response response = okHttpClient.newCall(request).execute();
                            getActivity().runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    Toast.makeText(getContext(),"没有更多数据了",Toast.LENGTH_SHORT).show();
                                }
                            });
                        } catch (Exception e) {
                            getActivity().runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    list.clear();
                                    Map<String,Object> map=new HashMap<>();
                                    map.put("1",1);
                                    map.put("2",2);
                                    list.add(map);
                                    StoreAdapter storeAdapter =new StoreAdapter(StoreFragment.this,list);
                                    recyclerView.setAdapter(storeAdapter);
                                    recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
                                }
                            });

                            e.printStackTrace();
                        }
                    }
                });
                thread.start();
5.2 创建商品调用相机相册获得图片

创建商品这部分,和注册用户部分相同,只需要向后端接口我们要上传的商品信息即可。但难点在于图片的选取。如何获取图片的地址并上传到后端呢?这是我们真正要解决的问题所在。

上传图片的关键在于图片绝对路径的获取。我们都知道,有了手机里的绝对路径,我们就可以根据绝对路径将图片上传到服务器。获取绝对路径,我们首先要选定图片 ,这就需要调取相册或者相机。在这里我将代码附上并讲解

第一步,相机相册的调用

 private void selectCamera() {

        //创建file对象,用于存储拍照后的图片,这也是拍照成功后的照片路径
        outputImage = new File(this.getExternalCacheDir(), "camera_photos.jpg");
        try {
            //判断文件是否存在,存在删除,不存在创建
            if (outputImage.exists()) {
                outputImage.delete();
            }
            outputImage.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        photoUri = Uri.fromFile(outputImage);

        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
        startActivityForResult(intent, TAKE_PHOTO);

    }
    public static final String STR_IMAGE = "image/*";
    //选择相册
    private void selectPhoto(){
        Intent intent = new Intent(Intent.ACTION_PICK, null);
        intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, STR_IMAGE);
        startActivityForResult(intent, GET_BACKGROUND_FROM_CAPTURE_RESOULT);

    }

第二步 获取绝对路径

public static String getRealPathFromUri(Context context, Uri uri) {
        if(context == null || uri == null) {
            return null;
        }
        if("file".equalsIgnoreCase(uri.getScheme())) {
            return getRealPathFromUri_Byfile(context,uri);
        } else if("content".equalsIgnoreCase(uri.getScheme())) {
            return getRealPathFromUri_Api11To18(context,uri);
        }
//        int sdkVersion = Build.VERSION.SDK_INT;
//        if (sdkVersion < 11) {
//            // SDK < Api11
//            return getRealPathFromUri_BelowApi11(context, uri);
//        }

//        // SDK > 19
        return getRealPathFromUri_AboveApi19(context, uri);//没用到
    }
    private static String getRealPathFromUri_Byfile(Context context,Uri uri){
        String uri2Str = uri.toString();
        String filePath = uri2Str.substring(uri2Str.indexOf(":") + 3);
        return filePath;
    }
    @SuppressLint("NewApi")
    private static String getRealPathFromUri_AboveApi19(Context context, Uri uri) {
        String filePath = null;
        String wholeID = null;

        wholeID = DocumentsContract.getDocumentId(uri);

        // 使用':'分割
        String id = wholeID.split(":")[1];

        String[] projection = { MediaStore.Images.Media.DATA };
        String selection = MediaStore.Images.Media._ID + "=?";
        String[] selectionArgs = { id };

        Cursor cursor = context.getContentResolver().query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection,
                selection, selectionArgs, null);
        int columnIndex = cursor.getColumnIndex(projection[0]);

        if (cursor.moveToFirst()) {
            filePath = cursor.getString(columnIndex);
        }
        cursor.close();
        return filePath;
    }

第三步 裁剪获取的图片

public void cropRawPhoto(Uri uri) {
        //创建file文件,用于存储剪裁后的照片
        File cropImage = new File(Environment.getExternalStorageDirectory(), "crop_image.jpg");
        String path = cropImage.getAbsolutePath();
        try {
            if (cropImage.exists()) {
                cropImage.delete();
            }
            cropImage.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        cropImgUri = Uri.fromFile(cropImage);
        Intent intent = new Intent("com.android.camera.action.CROP");
//设置源地址uri
        intent.setDataAndType(photoUri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        intent.putExtra("outputX", 200);
        intent.putExtra("outputY", 200);
        intent.putExtra("scale", true);
//设置目的地址uri
        intent.putExtra(MediaStore.EXTRA_OUTPUT, cropImgUri);
//设置图片格式
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.putExtra("return-data", false);
        intent.putExtra("noFaceDetection", true); // no face detection
        startActivityForResult(intent, RESULT_REQUEST_CODE);
    }
5.3 AlerDialog的使用

当我点击上传图片时,会弹出一个小的对话框选择相册或者拍照。这种小对话框我们可以使用AlerDialog表示

final String sex[]=new String[]{"        相册","        取消"};
                AlertDialog.Builder builder1 =new AlertDialog.Builder(Create_good.this);
                builder1.setIcon(R.drawable.ic_launcher_foreground);
                builder1.setTitle("选择:");
                builder1.setItems(sex, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        if(which==1)
                        {



                        }
                        else
                        {
                            selectPhoto();
                            final String hash=sharedPreferences.getString("hash", String.valueOf(111));
                            Log.v("tag",hash);
                            final Thread thread =new Thread(new Runnable() {
                                @Override
                                public void run() {
                                    try{
                                        do {
                                            Thread.sleep(1000);
                                            final SharedPreferences sharedPreferences = getSharedPreferences("user", MODE_PRIVATE);
                                             image_hash =sharedPreferences.getString("hash",String.valueOf(111));
                                             Log.v("tag",image_hash);
                                        }
                                        while (image_hash.equals(hash));
                                        runOnUiThread(new Runnable() {
                                            @Override
                                            public void run() {
                                                Glide.with(Create_good.this).load(image_hash).into(img);

                                            }
                                        });
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                }
                            });
                            thread.start();

                        }
                    }
                });
                builder1.create().show();
5.4 创建商品

创建商品时我们只需将商品信息post到后端即可
方法与注册大同小异,代码就不放了。大家可以尝试自己写一下。

5.5 修改商品信息

修改商品和创建商品最本质的区别在于与后端接口方式的不同。修改商品我们所用的方法为put。
这是因为虽然post和put都可以用于修改和创建信息。但是post的每一次都相当于创建一次新的信息,而不会覆盖原来的信息。而put请求是可以覆盖掉原来的信息。因此我们用put方法修改商品信息。
代码如下

  final String name =get_name.getText().toString();
                String jiage=get_price.getText().toString();
                String shuliang=get_quantity.getText().toString();
                final String info =get_quantity.getText().toString();
                if(name==null || name.length()==0)
                {
                        Toast.makeText(Create_good.this,"商品未命名",Toast.LENGTH_SHORT).show();
                }
                else if(jiage==null || jiage.length()==0)
                {
                    Toast.makeText(Create_good.this,"价格不能为空",Toast.LENGTH_SHORT).show();
                }
                else if(shuliang==null || shuliang.length()==0)
                {
                    Toast.makeText(Create_good.this,"数量不能为空",Toast.LENGTH_SHORT).show();
                }
                else if(Integer.parseInt(shuliang)>99)
                {
                    Toast.makeText(Create_good.this,"商品数量不能超过99",Toast.LENGTH_SHORT).show();
                }
                else if (Integer.parseInt(jiage)>10000000)
                {
                    Toast.makeText(Create_good.this,"商品价格不合理",Toast.LENGTH_SHORT).show();
                }
                else
                {
                Thread thread =new Thread(new Runnable() {
                    @Override
                    public void run() {
                       try{
                           final int price=Integer.parseInt(get_price.getText().toString());
                           final int quantity =Integer.parseInt(get_quantity.getText().toString());
                           String hash=sharedPreferences.getString("hash",null);
                        OkHttpClient client = new OkHttpClient();
                        Gson gson = new Gson();
                        good_create good=new good_create();
                        good.name=name;
                        good.price=price;
                        good.quantity=quantity;
                        good.info=info;
                        if(hash==null)
                        {
                            good.img=null;
                        }
                        else
                        {
                            good.img=hash;
                        }
                        MediaType JSON = MediaType.parse("application/json; charset=utf-8");
                        String token=sharedPreferences.getString("token",null);
                        RequestBody requestBody =RequestBody.create(JSON,gson.toJson(good));
                        Request request = new Request.Builder()
                                .addHeader("Authorization",token)
                                .url("http://49.232.214.94/api/good")
                                .post(requestBody)
                                .build();
                        Response response = null;
                        response = client.newCall(request).execute();
                        String responseData = response.body().string();
                        good_creat good_creat=gson.fromJson(responseData, com.example.lego.good_creat.class);
                                String msg=good_creat.getMsg();
                           Looper.prepare();
                           Toast.makeText(Create_good.this,msg,Toast.LENGTH_SHORT).show();
                           Looper.loop();
                       } catch (IOException e) {
                           runOnUiThread(new Runnable() {
                               @Override
                               public void run() {
                                   Toast.makeText(Create_good.this,"网络连接已断开",Toast.LENGTH_SHORT).show();
                               }
                           });
                           e.printStackTrace();
                       }
                    }
                });
                thread.start();
                finish();}

6.购物车

购物车部分类似与商城部分,只需展示自己已经购买的商品,从接口后端返回即可。效果如图

7.用户系统(sharedPreferences)判断登录状态

个人信息部分同样是从后端获取信息并显示,如需修改只需把修改后的信息put上去即可。
这里讲解sharedPreferences的用法
sharedPreferences相当于内置于APP中存储信息轻量级文件使用。
使用方法也非常简单

第一步 建立

  SharedPreferences sharedPreferences=getActivity().getSharedPreferences("user", Context.MODE_PRIVATE);

第二步 写入信息

 SharedPreferences.Editor editor=sharedPreferences.edit();
                editor.putBoolean("islogin",false);
                editor.commit();

第三步 读取信息

String islogin=sharedPreferences.getBoolean("islogin",false);

这三部分可以位于app中的不同Activity。我们判断登录状态时,如果用户登录,我们设置islogin参数为真。在下次启动app时在欢迎界面读取sharedPreferences中的islogin信息,如果为真,则跳过登陆部分。反之则需要登陆。

8.异常处理

同样,由于该软件需要联网。我们也要为app设置断网处理。具体操作可以在我的第二个项目(仿知乎日报)中查看,这里不做赘述
小白做项目-02
为了提高用户体验,我还做了一些提示处理

思路与断网处理都是一样的

9. 总结

该项目具有一定难度,非常能够提升Android开发的技术,尤其是全局考虑,设计软件思维等方面的能力。当然关于该项目,由于是前后端相接,而这里只讲解了前段部分的内容,后端接口是作者学长已经写好的部分,所以在这里感谢学长!
当然,本篇教程还存在许多不足,关于安卓生命周期,thread线程跳跃等部分我没有讲解。是因为这些问题是在真正做项目遇到的难点,也就是真正去做了才会思考和想办法解决。如果你是试着去做类似项目,遇到了这样的问题,我可以为你提供我的思路!私信我即可。
由于一些原因,接口部分不能透露。

如果想要源码的可以私信我,仅供学习使用

  • 8
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值