安卓移动开发基础知识大作业19145120

步骤

系列文章

提示:转到安卓学习专栏,观看更多内容!
点我直达–>安卓学习专栏


内容关于本学期学习的安卓的基础知识。
MZH-学号19145120个人安卓学习大作业记录,可供参考学习。
期末大作业 音乐播放器源码 https://blog.csdn.net/u011027547/article/details/122376235
仓促整理,如有错误,欢迎指正。

1.Andrdoid应用程序最重要的3个文件是什么?保存在项目的哪个目录下面?如何把1个Activity配置成为启动Activity?(15分)

我理解这题的意思是Andrdoid应用程序最重要的的是main文件夹
路径:项目名\app\src\main\下方的三个文件夹
Main文件夹中最重要的3个文件:
1.java(功能文件,实现业务逻辑功能)
2.res(资源文件,存放图片音乐、多语言版本字符串、drawable文件夹中可放入xml样式文件夹、layout布局文件夹)
3. AndroidManifest(清单文件,存放关于app主题、应用名称、权限管理、活动管理等内容)
在这里插入图片描述


2.Andrdoid应用程序中,外观文件如何关联对应的功能文件?功能文件如何关联对应的外观文件?(10分)

2.1外观文件如何关联对应的功能文件

外观文件中的tools:context=".MainActivity">表示关联了包名路径查找后的MainActivity功能文件.MainActivity中的“.”表示包名路径
在这里插入图片描述

2.2功能文件关联对应的外观文件

功能文件java文件中的R.layout.activity_main表示关联R(res)文件夹中的layout文件中的activity的外观文件

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

3.功能文件如何为1个按钮组件添加监听器的形式有哪些?(15分)

3.1直接通过点击事件的方式监听

捕获组件:
//爱好多选框

private CheckBox cb1 = null;
private CheckBox cb2 = null;
private CheckBox cb3 = null;

//爱好多选框

cb1 = (CheckBox) findViewById(R.id.cb1);
cb2 = (CheckBox) findViewById(R.id.cb2);
cb3 = (CheckBox) findViewById(R.id.cb3);

设置事件函数:

<CheckBox
    android:id="@+id/cb1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:clickable="true"
    android:onClick="CheckAll"
    android:text="音乐"
    android:textSize="15dp" />

编写事件函数:
//爱好多选

public void CheckAll(View v) {
    String allString = "";
    if (cb1.isChecked()) {
        allString = allString + cb1.getText().toString() + "\n";
    }
    if (cb2.isChecked()) {
        allString = allString + cb2.getText().toString() + "\n";
    }
    if (cb3.isChecked()) {
        allString = allString + cb3.getText().toString() + "\n";
    }
    //if (allString.trim().length()>0) 一样的效果
    if (!allString.equals("")) { //避免都不选择时吐司
        Toast tt = Toast.makeText(this, "你选择了:\n" + allString, Toast.LENGTH_SHORT);
        tt.setGravity(Gravity.CENTER, 0, 0);
        ImageView img = new ImageView(this);
        img.setImageResource(R.drawable.hoppy);
        LinearLayout out = (LinearLayout) tt.getView();
        out.setOrientation(LinearLayout.HORIZONTAL);
        out.addView(img, 0);
        tt.show();
    } else {
        Toast.makeText(this, "你什么爱好都没有选,怎么回事", Toast.LENGTH_SHORT).show();
    }
}

3.2通过事件监听器 RadioButton是Button的子类,为了代码方便,我直接用 RadioButton的演示,效果是一样的操作

捕获组件:

private RadioButton rbtn1 = null;
private RadioButton rbtn2 = null;
rbtn1 = (RadioButton) findViewById(R.id.rbtn1);
rbtn2 = (RadioButton) findViewById(R.id.rbtn2);

设置监听:

rbtn1.setOnClickListener(this);
rbtn2.setOnClickListener(this);
调用接口:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
实现接口方法:
public void onClick(View v) {
    String allString = "";
    int id = v.getId(); 
    switch (id) {
        case R.id.btn1: //如果id为btn1进行如下操作
        //函数操作
        break;
}

4.简单描述当A页面启动后,打开B页面的方法?然后B页面关闭,此时刷新A页面的内容都有哪些方法?(10分)

4.1 当A页面启动后,打开B页面的方法:

case R.id.btn1: //隐式启动
    tt = new Intent("aa.bb.cc.dd");
    startActivity(tt);
    Toast.makeText(this, "隐式启动", Toast.LENGTH_LONG);
    break;
case R.id.btn2://显式启动
    Toast.makeText(this, "显式启动", Toast.LENGTH_LONG);
    tt = new Intent(MainActivity.this, Main2Activity.class);
    startActivity(tt);
    break;

4.2 当B页面关闭,此时刷新A页面的内容的方法:

通过finshed()关闭页面

利用Handler刷新界面
实例化一个Handler对象,并重写handleMessage方法调用invalidate()实现界面刷新;而在线程中通过sendMessage发送界面更新消息。

// 在onCreate()中开启线程
new Thread(new GameThread()).start();
// 实例化一个handler

Handler myHandler = new Handler() {

 //接收到消息后处理

 public void handleMessage(Message msg) {

  switch (msg.what) {

  case Activity01.REFRESH:

   mGameView.invalidate();//刷新界面

   break;

  }

  super.handleMessage(msg);

 }                  

};
class GameThread implements Runnable {

 public void run() {

     while (!Thread.currentThread().isInterrupted()) {

         Message message = new Message();

            message.what = Activity01.REFRESH;

            //发送消息

            Activity01.this.myHandler.sendMessage(message);

            try {

             Thread.sleep(100);

            }

            catch (InterruptedException e) {

             Thread.currentThread().interrupt();

            }

  }

 }

}

使用postInvalidate()刷新界面
使用postInvalidate则比较简单,不需要handler,直接在线程中调用postInvalidate即可。

class GameThread implements Runnable {

 public void run() {

  while (!Thread.currentThread().isInterrupted()) {

   try {

    Thread.sleep(100);

   }

            catch (InterruptedException e) {

    Thread.currentThread().interrupt();

   }
   // 使用postInvalidate可以直接在线程中更新界面

   mGameView.postInvalidate();

  }

 }

}

5.当在页面中使用ListView控件时,如何在子项中显示图片?如果每个子项比较复杂,有多项显示内容,应该如何处理?(15分)

在子项中显示图片,样式文件中android:background 或者是java功能文件setBackground()方法

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="80dp"
    android:gravity="center"
    android:background="@drable/img">
linearLayout. setBackground(R.drawable. img);//设置左上角小图标

子项比较复杂,有多项显示内容:新建一个自定义的xml样式文件,类同上述方法调用xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="80dp"
    android:gravity="center"
    android:background="@drable/myitem">
linearLayout. setBackground(R.drawable. myitem);//设置左上角小图标

注意,运用文件时,不需要文件的后缀名,比如文件名可以是img但不能是img.jpg
下图是一个myitem.xml

在这里插入图片描述


6.请说明SQLite中的数据类型和与其它数据库的区别。SQLiteDatabase类和SQLiteOpenHelper类的区别和联系。(15分)

6.1SQLite中的数据类型和与其它数据库的区别:

1、与其它数据库不同,SQLite的数据类型很简单,只有
NULL(空类型)
INTEGER(整型)
REAL(浮点型)
TEXT(字符串型)
BLOB(二进制型)
2、SQLite为动态数据类型(弱引用),当向数据库中插入某个值时,会检查该值的类型,若类型与插入列不匹配,SQLite会尝试将该值转换成相应类型。

大多数 SQL 数据库引擎 (据我们所知,除 SQLite 之外的所有 SQL 数据库引擎)都使用严格的静态类型。使用静态类型,值的类型便由它的容器 – 存储值的特定的列 – 来决定。
SQLite 使用更通用的动态类型系统。在 SQLit 中,值的数据类型与值本身相关,而不是与它的容器。SQLite 的动态类型系统与其它数据库引擎的常用静态类型系统是向后兼容的,在这个意义上,工作在静态类型数据库上的 SQL 语句应该以同样的方式工作在 SQLite 中。然而,SQLite 中的动态类型允许它做传统的严格类型的数据库所不能做的事。
我的理解就是类似与python和C语言和java的区别,动态语言与静态语言的区别。

6.2SQLiteDatabase类和SQLiteOpenHelper类的关联起来访问SQLite中的数据:

MyOpenHelper.java

public MyOpenHelper(@Nullable Context context, @Nullable SQLiteDatabase.CursorFactory factory) {
    super(context, My_DATABASE, factory, My_VERSION);
}
//当数据库文件被创建时,调用该方法,并且只能被调用一次
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
    String sql="create table shiyan3_users(" +
            "id integer primary key autoincrement," +
            "name varchar(50) not null," +
            "sex varchar(50) not null," +
            "age integer not null," +
            "pwd varchar(24) not null," +
            "phone varchar(20) not null)";
    sqLiteDatabase.execSQL(sql);
}

Usersdao.java

调用MyOpenHelper,使用获取的SQLiteDatabase对象查询比对密码数据

//密码查询
public String queryPwd(String name) {
    String pwd = null;
    try {
        String whereClause = "name=?";
        String[] whereArgs = {name};
        SQLiteDatabase db = helper.getWritableDatabase();
        Cursor cursor = null;
        cursor = db.query("shiyan3_users", null, whereClause, whereArgs, null, null, null);
        if (cursor.moveToFirst()) {
            for (int i = 0; i < cursor.getCount(); i++) {
                pwd = cursor.getString(4);
                cursor.moveToNext();
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return pwd;
}

7.工作线程与UI线程的区别是什么?工作线程如何与UI线程进行通信?(10分)

7.1工作线程与UI线程区别:

1、UI线程,负责与用户交互;
2、打开播放音乐时,一定启动了工作线程,该线程只负责音乐播放。

7.2工作线程与UI线程进行通信:

Android多线程的Handler—实现工作线程通知Main线程修改界面。Handler是一套 Android 消息传递机制。在多线程的应用场景中,将工作线程中需更新UI的操作信息传递到UI主线程,从而实现工作线程对UI的更新处理,最终实现异步消息的处理。

在这里插入图片描述
在这里插入图片描述


8.有哪些方法可以生成1个MediaPlayer类的对象?使用MediaPlayer类如何才能自动播放音乐?(10分)

生成1个MediaPlayer类的对象
创建MediaPlaer对象有两种方式:
a、直接new出来

MediaPlayer  mp = new   MediaPlayer( );

b、使用create方式

MediaPlayer  mp = MediaPlayer. create( this, R.raw.test );

R.raw.test:资源中的音乐文件,这时就不用调用setDataSource了

使用MediaPlayer类自动播放音乐:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    action=intent.getStringExtra("action");
    index=intent.getIntExtra("index",0);
    progress=intent.getIntExtra("progress",0);
    Ok=intent.getBooleanExtra("ok",true);

    switch (action){
        case "play"://-------启动
            int tt=0;
            if (mp.isPlaying()==false){
                mp.start();
                work.ok=true;
                tt=1;
            }else {
                mp.pause();
                work.ok=false;
                tt=-1;
            }

            Message mm=Message.obtain();
            mm.what=200;
            mm.arg1=tt;
            MainActivity.hh.sendMessage(mm);
            break;
        case "click":
            Goto();
            break;
        case "prev":
            Goto();
            break;
        case "next":
            Goto();
            break;
        case "change":
            mp.seekTo(progress);
            work.ok=Ok;
            break;
    }

    return super.onStartCommand(intent, flags, startId);
}

9. 使用MediaPlayer类如何异步加载音乐文件(源代码说明)?又如何才能自动播放音乐(源代码说明)?(10分)

9.1异步加载音乐文件:
mp.start();// 调用此方法,代表异步准备完成 开始播放
调用setDataSource()方法来设置音频文件的路径;
MediaPlayer的setDataSource一共四个方法:

A、setDataSource (String path) 
B、setDataSource (FileDescriptor fd) 
C、setDataSource (Context context, Uri uri) 
D、setDataSource (FileDescriptor fd, long offset, long length)

9.2自动播放音乐mp.start();// 调用此方法,代表异步准备完成 开始播放

private void Goto(){
    work.ok=false;
    mp.stop();
    mp.reset();

    if (index>=MainActivity.list.size()){
        index=0;
    }
    if (index<0){
        index=MainActivity.list.size()-1;
    }
    try {
        String ss=MainActivity.list.get(index).getUrl();
        Uri uri=Uri.parse(ss);
        mp.setDataSource(this,uri);
        mp.setOnPreparedListener(this);
        mp.prepareAsync();
        mp.start();// 调用此方法,代表异步准备完成 开始播放
        work.ok=true;
    }catch (IOException e){
        e.printStackTrace();
    }
}

10. Service后台程序如何与前台Acvtity进行相互(双向)通信(源代码说明)?(10分)

来自博主https://blog.csdn.net/Gods_magic/article/details/84558169
10.1绑定服务的方式,实现ServiceConnection接口
bindService() - unbindService()

10.1.1进行数据传递
Service中声明一个Binder类,类中声明用来传递数据的方法。比如向Activity返回Service实例/接受或返回数据。
Activity实现ServiceConnection接口,Activity绑定Service调用bindService()方法。此时onServiceConnected()方法就会被调用。此方法中利用获取的Binder实例,可以调用Service中各个用来传递数据的方法。
这就实现了Activity向Service传递数据,Service接收数据进行数据操作后,再返回给Activity。

10.1.2.Activity监听Service数据变化

Service自定义Callback接口,声明监听数据的抽象函数onDataChange(String data),参数data用来向外部暴露data数据,并设置callback实例的setter方法。再onCreat()方法中,Service利用接收来的data数据,进行耗时操作后(例如开启线程进行data的循环递增),用callback.onDataChange(data + “”)暴露data数据。
Activity在onServiceConnected()方法中,利用获取的Service实例调用setCallback()方法,同时实例化Callback接口,进行接口回调实现onDataChange()函数,此时就监听到了Service中data数据的状态,并利用Handler进行更新UI操作。

@Override
public void onCreate() {
    super.onCreate();
    try {
        mp=new MediaPlayer();
        String ss= MainActivity.list.get(index).getUrl();
        Uri uri=Uri.parse(ss);
        mp.setDataSource(this,uri);
        mp.setOnPreparedListener(this);
        mp.setOnCompletionListener(this);
        mp.setOnErrorListener(this);
        mp.prepareAsync();

        work=new Work();
        work.start();
    }catch (IOException e){
        e.printStackTrace();
    }
}

//--------------------------------------------
private void Goto(){
    work.ok=false;
    mp.stop();
    mp.reset();

    if (index>=MainActivity.list.size()){
        index=0;
    }
    if (index<0){
        index=MainActivity.list.size()-1;
    }
    try {
        String ss=MainActivity.list.get(index).getUrl();
        Uri uri=Uri.parse(ss);
        mp.setDataSource(this,uri);
        mp.setOnPreparedListener(this);
        mp.prepareAsync();
        mp.start();
        work.ok=true;
    }catch (IOException e){
        e.printStackTrace();
    }
}

10.2利用广播方式
startService() - stopService()

Activity:动态注册广播 。将data存储到intent中,调用startService(intent)开启服务。
Service:重写onStartCommand()方法,利用intent.getXXExtra()获取Activity传来的数据。对数据进行操作后,将data存到intent中并发送广播。
Activity:接收广播,重写onReceive()函数,开启主线程并从intent中取出data数据,进行更新UI操作。
利用广播和intent实现了数据通信和监听服务数据状态。

MyService.java

public class MyService3 extends Service {
 
    private boolean connecting = false;
    public static final String COUNTER = "data";
    public static final String ACTION_NAME = "com.example.myinterview.service3.COUNTER_ACTION";
 
    private int data;
 
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
 
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //从Activity获取data
        data = intent.getIntExtra(COUNTER, 0);
 
        final Intent mIntent = new Intent();
        mIntent.setAction(ACTION_NAME);
        connecting = true;
        //开启一个线程,对数据进行处理
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    while (connecting) {
                        //耗时操作:数据处理并保存,向Activity发送广播
                        mIntent.putExtra(COUNTER, data);
                        sendBroadcast(mIntent);
                        data++;
                        Thread.sleep(300);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
 
        return START_STICKY;
    }
 
    @Override
    public void onDestroy() {
        super.onDestroy();
        connecting = false;
    }
}

ServiceActivity3.java

public class ServiceActivity3 extends AppCompatActivity implements View.OnClickListener {
 
    private int TransforData;
    private TextView textView;
    private Intent mIntent;
    private MyReceiver myReceiver;
    private boolean bind = false;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_service3);
 
        TransforData = 0;
        textView = (TextView) findViewById(R.id.textView);
        Button startBtn = (Button) findViewById(R.id.mstart);
        Button pauseBtn = (Button) findViewById(R.id.pause);
        Button clearBt = (Button) findViewById(R.id.clear);
        startBtn.setOnClickListener(this);
        pauseBtn.setOnClickListener(this);
        clearBt.setOnClickListener(this);
 
        mIntent = new Intent(this, MyService3.class);
        myReceiver = new MyReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(MyService3.ACTION_NAME);
        //注册广播
        registerReceiver(myReceiver, intentFilter);
    }
 
 
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.mstart:
                if (!bind) {
                    bind = true;
                    //向Service传递data
                    mIntent.putExtra(MyService3.COUNTER, TransforData);
                    startService(mIntent);
                    Toast.makeText(this, "Start!", Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.pause:
                //停止服务
                stopService(mIntent);
                bind = false;
                break;
            case R.id.clear:
                if (!bind) {
                    TransforData = 0;
                    textView.setText("0");
                    Toast.makeText(this, "Pause!", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
                break;
        }
    }
 
    class MyReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, final Intent intent) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    //获取从Service中传来的data
                    TransforData = intent.getIntExtra(MyService3.COUNTER, 0);
                    //更新UI
                    textView.setText(String.valueOf(TransforData));
                }
            });
        }
    }
 
    @Override
    protected void onDestroy() {
        stopService(mIntent);
        unregisterReceiver(myReceiver);
        super.onDestroy();
    }
}

总结

大家喜欢的话,给个👍,点个关注!继续跟大家分享敲代码过程中遇到的问题!


  • 5
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
android开发期末大作业(项目源码,任务书,实验大报告,apk文件) 大作业的要求和内容:(包括题目选择范围、技术要求、递交时间、考核方法等) 一、实验项目名称 Android手机应用开发课程大作业 二、实验目的 1.通过本课程设计的实践及其前后的准备与总结,复习、领会、巩固和运用课堂上所学的Android手机应用开发知识。 2.为学生综合应用本专业所学习的多门课程知识(例如,软件工程、数据库、Java语言、Java Web开发等)创造实践机会。为学生提供主动学习、积极探索与大胆创新的机会。 3.掌握Android手机应用设计的方法与技巧。 三、实验内容及要求 1、设计内容 题目、设计内容自拟,工作量适中,要求学生应用课程所学知识,采用JAVA语言和Android手机应用开发技术实现一个完整的系统。 ①完成大作业报告。 ②实现各系统功能,并完成调试运行。 2、主要技术 采用Java语言并不仅限于Java语言实现系统。 开发环境与工具:Android Studio 3.2以上版本; 操作系统:Win7/Win10或其他; 4、设计成果: 材料上交:电子文档(大作业任务书+大作业报告+源代码,电子稿请刻在光盘上)、打印稿(大作业任务书+大作业报告)。 四、成绩评定: 考核标准包括: 1、选题的工作量,难度和新颖程度 2、系统架构设计是否良好,运行过程是否报错 3、界面设计的合理性和美观程度 4、基本功能的实现 分值60 (包括布局、组件、Activity、Intent等使用) 数据存储的使用 分值10 网络功能 分值10 Service、ContentProvider或BroadCastReceiver等的使用 分值10 附加分: 图形图像处理、多媒体处理等 分值10 5、考核方式为面对面答辩,在课程的后两周内集中进行。
### 回答1: 很高兴听到你正在进行Android移动应用开发期末大作业。这是一个非常有挑战性的任务,需要你具备扎实的编程技能和创新思维。在开发过程中,你需要考虑用户需求、界面设计、功能实现等方面,同时还要注意代码的可读性和可维护性。希望你能够认真对待这个项目,不断学习和提高自己的技能,最终开发出一个优秀的移动应用。祝你成功! ### 回答2: 这门移动应用开发课程的期末大作业要求我们使用Android平台开发一个完整的移动应用,并且要求从需求分析、UI设计、代码编写到测试上线全部自主完成。在这个过程中,我收获了很多。 首先在需求分析方面,我明白了在开发一款移动应用之前,一定需要先对用户需求进行深入的了解和分析,明确应用的定位和目标用户。只有在掌握了用户的需求和期望后,才能开发出真正实用且符合用户体验的应用。 其次在UI设计方面,我深刻体验到设计对于产品吸引用户和提高用户体验的重要性。一个简洁美观、符合人体工程学的UI设计不仅可以吸引用户使用,也能够让用户使用起来更加顺手,更加舒适。在设计过程中,我学习到了更多的配色搭配技巧和界面设计规范,不仅让我在这份大作业中的UI更加美观,也为我今后的设计工作积累了宝贵的经验。 最后在代码编写和测试过程中,我收获了更多的实践经验。从Java语言基础到Android实践技能,我逐渐领会到了应用程序设计的一些基本概念,并且掌握了更多的开发技巧和调试工具。同时,我也学会了怎样在测试环节中进行错误排除和性能优化,将应用的品质提升到更高的层次。 总的来说,这门移动应用开发课程的期末大作业对于我的成长和未来的职业发展都有着非常重要的意义。我相信,在今后的学习和工作生涯中,我一定会更好地应用课程中的知识和技能,不断提升自己的创新和实践能力。 ### 回答3: Android移动应用开发期末大作业是一项很有挑战性的任务,因为它需要我们综合应用所有学到的知识和技能,创建一款功能完善、易于使用、界面美观的应用。 在开始开发应用之前,我们需要先确定应用的主题和目标用户群体。一些常见的应用主题包括:娱乐类、社交类、教育类、商务类等。根据主题和目标用户群体的需求,我们可以选择使用哪些技术和开发工具来实现应用功能,如:UI设计、HTTP请求、数据库管理、音视频播放等。此外,我们还需要考虑应用的性能和可靠性方面的问题,如:内存管理、网络连接不稳定等。 在开发过程中,我们要按照以下步骤进行: 1.需求分析:确定应用的功能需求和用户需求。 2.设计:设计应用的UI界面、交互设计和数据库结构等。 3.编码:按照设计文档进行编程实现。 4.测试:对应用进行测试和回归测试,确保应用功能的正确性和稳定性。 5.发布:将应用上架到各大应用商店,让更多用户使用和下载。 除了以上步骤,我们还需要注重以下方面: 1.考虑应用的用户体验,保证应用的易用性和用户友好性。 2.优化应用的性能,保证应用的流畅度和响应速度。 3.考虑应用的隐私和安全性,保护用户的个人信息和隐私。 总之,Android移动应用开发期末大作业需要我们从多个方面综合应用所学知识和技术,设计和完成一款高质量、用户满意的应用。这不仅是一次学习和实践的机会,也是对我们技术能力和设计能力的考验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发现你走远了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值