Activity初窥门径

感谢你提到 Activity 初窥门径!作为 Android 开发的四大核心组件之一,Activity 是初学者需要重点掌握的部分。Activity 代表一个用户界面,通常对应一个屏幕,用于展示 UI 和处理用户交互。针对“初窥门径”,本回答将为初学者提供简洁易懂的 Activity 入门指南,重点讲解核心概念、生命周期、基本使用,并结合你之前提到的组件(如 AlertDialogPopupWindowMenuViewPager2DrawerLayoutTextWatcherConfigurationAsyncTaskGestures)以及相关话题(如 HandlerOnTouchListeneronTouchEvent多点触碰),通过一个简单但综合的示例帮助你快速上手。示例将涵盖代码、生命周期管理、优化建议和常见问题处理。如果你的需求涉及特定功能(如复杂交互、数据传递)或有疑问,请提供更多细节,我可以进一步定制答案。


1. Activity 核心概念

定义
Activity 是 Android 应用中负责用户界面的组件,继承自 android.app.Activity(通常使用 AppCompatActivity 以支持旧设备)。它管理 UI 布局、用户交互和生命周期。

核心功能

  • UI 展示:通过 XML 布局(res/layout)或代码动态创建界面。
  • 事件处理:响应用户操作(如点击、输入、手势)。
  • 生命周期管理:处理创建、运行、暂停、销毁等状态。
  • 导航:通过 Intent 跳转到其他 Activity 或触发组件。
  • 配置适配:处理屏幕旋转、语言切换等(Configuration)。

初学者要点

  • 理解生命周期是关键,决定初始化和清理资源的时机。
  • 学会加载布局、绑定控件、处理事件。
  • 注意配置变化(如屏幕旋转)可能导致 Activity 重启。

2. Activity 生命周期

Activity 的生命周期包含以下方法,初学者需重点掌握:

  1. onCreate(Bundle savedInstanceState)
  • 触发Activity 创建时调用。
  • 用途:初始化布局、控件、监听器;恢复状态(savedInstanceState)。
  1. onStart()
  • 触发Activity 变为可见。
  • 用途:准备 UI 显示。
  1. onResume()
  • 触发Activity 可交互。
  • 用途:启动动画、刷新数据。
  1. onPause()
  • 触发Activity 失去焦点(如弹出对话框)。
  • 用途:暂停操作、保存临时数据。
  1. onStop()
  • 触发Activity 不可见。
  • 用途:释放资源、保存状态。
  1. onDestroy()
  • 触发Activity 销毁。
  • 用途:清理资源(如移除监听器)。
  1. onRestart()
  • 触发:从停止状态重新启动。
  • 用途:恢复操作。

生命周期图

onCreate() → onStart() → onResume()
           ↳ onPause() → onStop() → onRestart() → onStart() → onResume()
                          ↳ onDestroy()

初学者注意

  • onCreate 是初始化入口,onDestroy 是清理出口。
  • 配置变化(如屏幕旋转)默认导致 Activity 重启,需处理状态保存。
  • 使用 Toast 或 Log 调试生命周期:
  Log.d("MainActivity", "onCreate called");

3. 初学者综合示例

以下是一个简单但综合的示例,适合初学者快速上手,展示 Activity 的基本使用,结合 DrawerLayoutViewPager2TextWatcherConfigurationAsyncTaskGestures。功能包括:

  • 界面:包含 ToolbarEditText(输入监听)、ImageView(简单手势)、ViewPager2(页面切换)。
  • 手势:单击显示 AlertDialog,双指缩放调整图片。
  • 异步任务:通过侧滑菜单触发模拟网络请求。
  • 配置变化:响应屏幕旋转。
  • 状态保存:保存输入和缩放状态。

3.1 布局文件res/layout/activity_main.xml

包含 DrawerLayoutToolbarEditTextImageViewProgressBarViewPager2

3.2 菜单资源res/menu/nav_menu.xml

侧滑菜单。

3.3 字符串资源res/values/strings.xml

支持多语言。

Activity 初学 Open navigation drawer Close navigation drawer Home Profile Settings Enter text

中文资源res/values-zh/strings.xml):
Activity 初学 打开导航抽屉 关闭导航抽屉 首页 个人中心 设置 请输入文本

3.4 Fragment 页面PageFragment.java

用于 ViewPager2


package com.example.myapp;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;

public class PageFragment extends Fragment {
private static final String ARG_PAGE = “page”;
private static final String ARG_RESULT = “result”;
private TextView textView;

public static PageFragment newInstance(int page, String result) {
    PageFragment fragment = new PageFragment();
    Bundle args = new Bundle();
    args.putInt(ARG_PAGE, page);
    args.putString(ARG_RESULT, result);
    fragment.setArguments(args);
    return fragment;
}

@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(android.R.layout.simple_list_item_1, container, false);
    textView = view.findViewById(android.R.id.text1);
    updateContent();
    return view;
}

public void updateResult(String result) {
    if (getArguments() != null) {
        getArguments().putString(ARG_RESULT, result);
        updateContent();
    }
}

private void updateContent() {
    int page = getArguments() != null ? getArguments().getInt(ARG_PAGE) : 0;
    String result = getArguments() != null ? getArguments().getString(ARG_RESULT, "") : "";
    textView.setText("页面 " + (page + 1) + "\n结果: " + (result.isEmpty() ? "无" : result));
}

}

3.5 AsyncTask 子类NetworkTask.java

模拟网络请求。


package com.example.myapp;

import android.os.AsyncTask;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import java.lang.ref.WeakReference;

public class NetworkTask extends AsyncTask {
private final WeakReference activityRef;
private final WeakReference progressBarRef;
private final WeakReference resultTextRef;

public NetworkTask(MainActivity activity, ProgressBar progressBar, TextView resultText) {
    activityRef = new WeakReference<>(activity);
    progressBarRef = new WeakReference<>(progressBar);
    resultTextRef = new WeakReference<>(resultText);
}

@Override
protected void onPreExecute() {
    ProgressBar progressBar = progressBarRef.get();
    if (progressBar != null) {
        progressBar.setVisibility(View.VISIBLE);
    }
}

@Override
protected String doInBackground(String... params) {
    try {
        String input = params[0];
        for (int i = 1; i <= 100; i += 20) {
            Thread.sleep(500);
            publishProgress(i);
            if (isCancelled()) {
                return null;
            }
        }
        return "任务完成: " + input;
    } catch (InterruptedException e) {
        return "错误: " + e.getMessage();
    }
}

@Override
protected void onProgressUpdate(Integer... values) {
    ProgressBar progressBar = progressBarRef.get();
    if (progressBar != null) {
        progressBar.setProgress(values[0]);
    }
}

@Override
protected void onPostExecute(String result) {
    ProgressBar progressBar = progressBarRef.get();
    TextView resultText = resultTextRef.get();
    MainActivity activity = activityRef.get();
    if (progressBar != null && resultText != null && activity != null) {
        progressBar.setVisibility(View.GONE);
        resultText.setText(result != null ? result : "任务取消");
        if (result != null) {
            new AlertDialog.Builder(activity)
                    .setTitle("结果")
                    .setMessage(result)
                    .setPositiveButton("确定", null)
                    .show();
            activity.updateViewPagerResult(result);
        }
    }
}

@Override
protected void onCancelled() {
    ProgressBar progressBar = progressBarRef.get();
    TextView resultText = resultTextRef.get();
    MainActivity activity = activityRef.get();
    if (progressBar != null && resultText != null && activity != null) {
        progressBar.setVisibility(View.GONE);
        resultText.setText("任务取消");
        new AlertDialog.Builder(activity)
                .setTitle("取消")
                .setMessage("任务被取消")
                .setPositiveButton("确定", null)
                .show();
    }
}

}

3.6 AndroidManifest.xml

声明支持配置变化。

3.7 Activity 代码MainActivity.java

简单综合示例,适合初学者。


package com.example.myapp;

import android.content.res.Configuration;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.GestureDetectorCompat;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.navigation.NavigationView;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {
private DrawerLayout drawerLayout;
private ViewPager2 viewPager;
private EditText inputEditText;
private TextView resultText;
private ProgressBar progressBar;
private ImageView gestureImage;
private TextWatcher textWatcher;
private ViewPagerAdapter viewPagerAdapter;
private GestureDetectorCompat gestureDetector;
private ScaleGestureDetector scaleDetector;
private NetworkTask asyncTask;
private float scale = 1.0f;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show();

    // 初始化 Toolbar
    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    // 初始化 DrawerLayout
    drawerLayout = findViewById(R.id.drawerLayout);
    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
            this, drawerLayout, toolbar,
            R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawerLayout.addDrawerListener(toggle);
    toggle.syncState();

    // 侧滑菜单
    NavigationView navigationView = findViewById(R.id.navigationView);
    navigationView.setNavigationItemSelectedListener(item -> {
        int itemId = item.getItemId();
        if (itemId == R.id.nav_home) {
            viewPager.setCurrentItem(0);
            Toast.makeText(this, "首页", Toast.LENGTH_SHORT).show();
        } else if (itemId == R.id.nav_profile) {
            viewPager.setCurrentItem(1);
            Toast.makeText(this, "个人中心", Toast.LENGTH_SHORT).show();
        } else if (itemId == R.id.nav_settings) {
            String input = inputEditText.getText().toString();
            if (asyncTask != null && asyncTask.getStatus() == AsyncTask.Status.RUNNING) {
                asyncTask.cancel(true);
            } else {
                asyncTask = new NetworkTask(this, progressBar, resultText);
                asyncTask.execute(input.isEmpty() ? "默认任务" : input);
            }
        }
        drawerLayout.closeDrawers();
        return true;
    });

    // 初始化 ViewPager2
    viewPager = findViewById(R.id.viewPager);
    viewPagerAdapter = new ViewPagerAdapter(this);
    viewPager.setAdapter(viewPagerAdapter);

    // 初始化 UI 组件
    inputEditText = findViewById(R.id.inputEditText);
    resultText = findViewById(R.id.resultText);
    progressBar = findViewById(R.id.progressBar);
    gestureImage = findViewById(R.id.gestureImage);

    // 初始化 TextWatcher
    textWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {}

        @Override
        public void afterTextChanged(Editable s) {
            String input = s.toString();
            if (input.equalsIgnoreCase("english")) {
                setLocale(new Locale("en"));
            } else if (input.equalsIgnoreCase("chinese")) {
                setLocale(new Locale("zh"));
            } else if (input.equalsIgnoreCase("reset")) {
                scale = 1.0f;
                gestureImage.setScaleX(scale);
                gestureImage.setScaleY(scale);
                resultText.setText("结果: 重置");
                viewPagerAdapter.updateResult("重置");
            }
        }
    };
    inputEditText.addTextChangedListener(textWatcher);

    // 初始化手势
    gestureDetector = new GestureDetectorCompat(this, new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            resultText.setText("手势: 单击");
            viewPagerAdapter.updateResult("单击");
            new AlertDialog.Builder(MainActivity.this)
                    .setTitle("单击")
                    .setMessage("触发单击手势")
                    .setPositiveButton("确定", null)
                    .show();
            return true;
        }
    });

    scaleDetector = new ScaleGestureDetector(this, new ScaleGestureDetector.SimpleOnScaleGestureListener() {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            scale *= detector.getScaleFactor();
            scale = Math.max(0.5f, Math.min(scale, 2.0f));
            gestureImage.setScaleX(scale);
            gestureImage.setScaleY(scale);
            resultText.setText("手势: 缩放 (比例: " + String.format("%.2f", scale) + ")");
            viewPagerAdapter.updateResult("缩放 (比例: " + String.format("%.2f", scale) + ")");
            return true;
        }
    });

    gestureImage.setOnTouchListener((v, event) -> {
        viewPager.requestDisallowInterceptTouchEvent(true);
        gestureDetector.onTouchEvent(event);
        scaleDetector.onTouchEvent(event);
        return true;
    });

    // 恢复状态
    if (savedInstanceState != null) {
        scale = savedInstanceState.getFloat("scale", 1.0f);
        gestureImage.setScaleX(scale);
        gestureImage.setScaleY(scale);
        String savedInput = savedInstanceState.getString("input", "");
        inputEditText.setText(savedInput);
        String savedResult = savedInstanceState.getString("result", "结果");
        resultText.setText(savedResult);
        viewPagerAdapter.updateResult(savedResult);
    }
}

@Override
protected void onStart() {
    super.onStart();
    Toast.makeText(this, "onStart", Toast.LENGTH_SHORT).show();
}

@Override
protected void onResume() {
    super.onResume();
    Toast.makeText(this, "onResume", Toast.LENGTH_SHORT).show();
}

@Override
protected void onPause() {
    super.onPause();
    Toast.makeText(this, "onPause", Toast.LENGTH_SHORT).show();
}

@Override
protected void onStop() {
    super.onStop();
    Toast.makeText(this, "onStop", Toast.LENGTH_SHORT).show();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show();
    inputEditText.removeTextChangedListener(textWatcher);
    if (asyncTask != null) {
        asyncTask.cancel(true);
    }
}

@Override
protected void onRestart() {
    super.onRestart();
    Toast.makeText(this, "onRestart", Toast.LENGTH_SHORT).show();
}

@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    resultText.setText("配置: " + (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT ? "竖屏" : "横屏"));
    viewPagerAdapter.updateResult(resultText.getText().toString());
    Toast.makeText(this, "配置变化", Toast.LENGTH_SHORT).show();
}

@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putFloat("scale", scale);
    outState.putString("input", inputEditText.getText().toString());
    outState.putString("result", resultText.getText().toString());
}

@Override
public void onBackPressed() {
    if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
        drawerLayout.closeDrawer(GravityCompat.START);
    } else {
        super.onBackPressed();
    }
}

public void updateViewPagerResult(String result) {
    viewPagerAdapter.updateResult(result);
}

private void setLocale(Locale locale) {
    Locale.setDefault(locale);
    Configuration config = new Configuration();
    config.setLocale(locale);
    getResources().updateConfiguration(config, getResources().getDisplayMetrics());
    recreate();
}

private static class ViewPagerAdapter extends FragmentStateAdapter {
    private final List<PageFragment> fragments = new ArrayList<>();
    private String result = "";

    public ViewPagerAdapter(AppCompatActivity activity) {
        super(activity);
        for (int i = 0; i < 2; i++) {
            fragments.add(PageFragment.newInstance(i, result));
        }
    }

    public void updateResult(String result) {
        this.result = result;
        for (PageFragment fragment : fragments) {
            fragment.updateResult(result);
        }
        notifyDataSetChanged();
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        return fragments.get(position);
    }

    @Override
    public int getItemCount() {
        return 2;
    }
}

}

3.8 运行效果

  • 生命周期:通过 Toast 显示每个阶段(onCreateonStart 等),帮助初学者理解。
  • 界面:包含 ToolbarEditText(输入监听)、ImageView(手势处理)、ProgressBar(任务进度)、TextView(结果)、ViewPager2(2 个页面)。
  • 手势
  • 单击:显示 AlertDialog,更新 TextViewViewPager2 显示“单击”。
  • 缩放:调整 ImageView 大小,更新 TextViewViewPager2 显示缩放比例。
  • TextWatcher
  • 输入“english”或“chinese”切换语言,刷新 UI。
  • 输入“reset”重置 ImageView 缩放比例。
  • AsyncTask
  • 点击侧滑菜单“Settings”,执行或取消异步任务(模拟 2.5 秒网络请求)。
  • 显示 ProgressBar,任务完成后更新 TextViewViewPager2,并显示 AlertDialog
  • Configuration
  • 屏幕旋转时,更新 TextViewViewPager2 显示方向。
  • DrawerLayout
  • 菜单切换 ViewPager2 页面或触发/取消异步任务。
  • 状态保存
  • 保存输入、缩放比例和结果,屏幕旋转后恢复。

说明

  • 生命周期:通过 Toast 直观展示每个阶段。
  • 手势:简单处理单击和缩放,适合初学者。
  • TextWatcher:支持语言切换和重置。
  • AsyncTask:使用 WeakReference 防止内存泄漏。
  • Configuration:通过 android:configChanges 处理屏幕旋转。
  • 状态保存:通过 onSaveInstanceState 保存数据。

4. 初学者常见问题及解决

  1. 生命周期不理解
  • 问题:不清楚何时初始化或清理。
  • 解决:在 onCreate 初始化,在 onDestroy 清理:
    java @Override protected void onDestroy() { inputEditText.removeTextChangedListener(textWatcher); super.onDestroy(); }
  1. 屏幕旋转丢失数据
  • 问题:旋转后 UI 重置。
  • 解决:保存状态:
    java @Override protected void onSaveInstanceState(@NonNull Bundle outState) { outState.putString("input", inputEditText.getText().toString()); super.onSaveInstanceState(outState); }
  1. 滑动冲突
  • 问题ViewPager2DrawerLayout 冲突。
  • 解决:禁用父 View 拦截:
    java viewPager.requestDisallowInterceptTouchEvent(true);
  1. UI 无响应
  • 问题:耗时操作阻塞主线程。
  • 解决:使用 AsyncTask
    java asyncTask = new NetworkTask(this, progressBar, resultText); asyncTask.execute(input);
  1. 控件未找到
  • 问题findViewById 返回 null。
  • 解决:确保布局 XML 和 ID 正确:
    xml <EditText android:id="@+id/inputEditText" ... />

5. 初学者进阶功能

以下是适合初学者的简单进阶功能。

5.1 跳转到另一个 Activity

创建第二个 Activity 接收数据。


package com.example.myapp;

import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;

public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(android.R.layout.simple_list_item_1);
TextView textView = findViewById(android.R.id.text1);
String data = getIntent().getStringExtra(“data”);
textView.setText(“收到: ” + (data != null ? data : “无”));
}
}

在 MainActivity 中启动

navigationView.setNavigationItemSelectedListener(item -> {
    if (item.getItemId() == R.id.nav_profile) {
        Intent intent = new Intent(this, SecondActivity.class);
        intent.putExtra("data", inputEditText.getText().toString());
        startActivity(intent);
    }
    return true;
});

AndroidManifest.xml

<activity android:name=".SecondActivity" />

5.2 PopupWindow

单击 ImageView 显示 PopupWindow

@Override
public boolean onSingleTapUp(MotionEvent e) {
    resultText.setText("手势: 单击");
    viewPagerAdapter.updateResult("单击");
    PopupWindow popupWindow = new PopupWindow(new TextView(this), 200, 100, true);
    ((TextView) popupWindow.getContentView()).setText("单击触发");
    popupWindow.showAsDropDown(gestureImage);
    return true;
}

5.3 简单 Handler

延迟显示 Toast。

Handler handler = new Handler(Looper.getMainLooper());
@Override
public boolean onSingleTapUp(MotionEvent e) {
    handler.postDelayed(() -> {
        Toast.makeText(MainActivity.this, "单击延迟提示", Toast.LENGTH_SHORT).show();
    }, 500);
    return true;
}

6. 初学者优化建议

  1. 生命周期管理
  • 初始化在 onCreate,清理在 onDestroy
    java @Override protected void onDestroy() { if (asyncTask != null) { asyncTask.cancel(true); } super.onDestroy(); }
  1. 状态保存
  • 保存关键数据:
    java @Override protected void onSaveInstanceState(@NonNull Bundle outState) { outState.putFloat("scale", scale); super.onSaveInstanceState(outState); }
  1. 简单 UI
  • 使用 XML 布局,保持代码清晰:
    xml <TextView android:id="@+id/resultText" ... />
  1. 用户反馈
  • 添加 Toast 或动画:
    java resultText.animate().alpha(0).setDuration(200).withEndAction(() -> { resultText.setText("新结果"); resultText.animate().alpha(1).setDuration(200).start(); }).start();
  1. 调试
  • 使用 Log 跟踪:
    java Log.d("MainActivity", "输入: " + inputEditText.getText().toString());

7. 结合之前组件

  • AlertDialog:单击 ImageView 显示。
  • PopupWindow:可选替换 AlertDialog
  • Menu:侧滑菜单触发任务或切换页面。
  • ViewPager2:显示手势或任务结果。
  • DrawerLayout:导航页面或任务。
  • TextWatcher:语言切换或重置。
  • Configuration:屏幕旋转处理。
  • AsyncTask:模拟网络请求。
  • Gestures:简单单击和缩放。

8. 可能的其他意图

  • 复杂功能:如需添加 RecyclerView、复杂手势,请说明。
  • 数据传递:如需多 Activity 交互,请提供细节。
  • 问题调试:如有崩溃、UI 未更新等问题,请描述。
  • 跨平台:如需 Web 或 iOS 方案,请说明。

下一步

请提供更多细节,例如:

  • 你想实现的 Activity 功能(UI、交互、导航)?
  • 是否需要特定组件(如 RecyclerView)?
  • 是否有生命周期或性能问题?
  • 需要更简单或更复杂的示例?

如果没有进一步信息,我可以提供更详细的 Activity 教程或进阶功能(如多 Activity 导航)。

文章已创建 2371

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部