实验1:
1、两个activity,利用intent进行通信。
- 不要返回的结果
startActivity(intent);
- 要返回的结果
原:启动intent的方式改变。同时为了 对返回的结果做处理,要重写某个方法(该方法体第一句先super)。
新:new一个intent(this.,旧类)。先putExtra放数据,再setResult,注意这个方法有两个参数(状态码,intent对象)。
销毁页面用finish()
注意:
- intent设置启动某个类时,一定带上后缀.class
- new一个intent对象不代表启动一个新类,start才会真正的打开
- finish销毁后,原界面上的数据还在。但start后,原界面数据就不在了。涉及launchmode
2、字符串和数字之间的转换
Double num=Double.parseDouble();
String s=String.format(“%.2f”,num);
实验2:
1、列表里实现图片和文字
(1)MainActivity.java
package com.example.test;
public class MainActivity extends AppCompatActivity {
private ListView list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list = findViewById(R.id.ls1);
String[] data = {"数据结构", "计算机网络", "移动开发"}; // 定义要显示的文字
int[] imageIds = {
R.drawable.dsg,
R.drawable.jw,
R.drawable.ydkf
}; // 对应的图片资源(你要把这些图片放到 res/drawable/ 文件夹)
MyAdapter adapter = new MyAdapter(this, data, imageIds); // 创建自定义适配器
list.setAdapter(adapter); // 设置适配器给 ListView
}
}
(2)MyAdapter.java
package com.example.test;
public class MyAdapter extends BaseAdapter {
private Context context; // 上下文,用于加载布局
private String[] titles; // 要显示的文字数组
private int[] images; // 对应的图片资源 ID 数组
public MyAdapter(Context context, String[] titles, int[] images) { // 构造方法,传入文字和图片数组
this.context = context;
this.titles = titles;
this.images = images; }
@Override
public int getCount() { // 返回列表项个数
return titles.length;}
@Override
public Object getItem(int i) { // 返回某一项的文字
return titles[i];}
@Override
public long getItemId(int i) { // 返回某一项的 ID(这里用下标)
return i;}
static class ViewHolder { // 创建一个 ViewHolder 类用于缓存视图,提高性能
ImageView img; // 图片控件
TextView t1; // 文字控件}
@Override
public View getView(int i, View convertView, ViewGroup parent) { // 创建/复用视图,并绑定数据
ViewHolder holder; // 定义 ViewHolder 对象
if (convertView == null) { // 如果没有可复用的视图,就创建一个新的
convertView = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false); // 加载布局
holder = new ViewHolder(); // 创建 ViewHolder
holder.img = convertView.findViewById(R.id.I1); // 获取图片控件
holder.t1 = convertView.findViewById(R.id.t1); // 获取文字控件
convertView.setTag(holder); // 保存 ViewHolder 到 View 中
} else {
holder = (ViewHolder) convertView.getTag(); // 复用旧视图
}
holder.t1.setText(titles[i]); // 设置文字
holder.img.setImageResource(images[i]); // 设置图片
return convertView; // 返回最终的视图
}}
(3)两个布局文件。activity_main例放ListView控件,另一个xml控件代表每一项的布局方式,此处就是一个ImageView和一个TextView。
2、利用fragment实现交互
(1)对于两个fragment,单独去写xml文件。activity_main.xml放两个fragment组件即可,注意一定要写id和name属性(即其所对应的类名)
(2)Mainactivity.java不用写,初始化完布局即可。对于上fragment,列表需要有一个适配器(代码同上)。对于下fragment,初始化后,还要声明一个方法,供上fragment调用,以更新自己的图片和文本。
上
public class UpFragment extends Fragment {
private ListView list;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState){
View view=inflater.inflate(R.layout.up,container,false);
list = view.findViewById(R.id.ls1);(数据来源同上)
MyAdapter adapter = new MyAdapter(getContext(), data, imageIds);
list.setAdapter(adapter);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String name=data[position];
int img=imageIds[position];
BottomFragment f2=(BottomFragment)getActivity().getSupportFragmentManager().findFragmentById(R.id.f2);
f2.updateContent(name,img); // 建一个下侧fragment对象、更新
}
});
return view;
}}
下
public class BottomFragment extends Fragment {
private ImageView fruitImage;
private TextView fruitName;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState){
View view=inflater.inflate(R.layout.bottom,container,false);
fruitImage = view.findViewById(R.id.I1);
fruitName = view.findViewById(R.id.t1);
return view;
}
// 提供公开方法供 UpFragment 调用
public void updateContent(String name, int imageResId) {
// 更新文本和图片
fruitName.setText(name);
fruitImage.setImageResource(imageResId);
}
}
实验3
1、使用MediaPlayer,直接在java代码使用即可,无需在xml中声明。注意stop涉及两个方法。
2、使用VideoView。xml也要声明。java初始化后,String path = "android.resource://" + getPackageName() + "/" + R.raw.video;
videoView.setVideoURI(Uri.parse(path)); videoView.start();
终止和重放:videoView.stopPlayback(); videoView.resume();
3、单选按钮。对group设置监听器,根据id判断选的哪个。可借用布尔型变量。
实验4
1、选择不同的颜色进行绘画。需要自定义一个view作为画布(在xml文件中要声明该组件,包名.类名),还要自定义paint画笔。MainActivity只需初始化组件,想清空时,调用myView.clearCanvas(); 选择不同颜色,用到列表对话框及监听器:
String[] content = {"红色", "绿色", "蓝色", "黑色"};
int[] colorsValue = {Color.RED, Color.GREEN,Color.BLUE, Color.BLACK};
btnTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new AlertDialog.Builder(MainActivity.this).setTitle("选择颜色")
.setItems(content, ((dialog, which) -> {
myView.setCurrentPaintColor(colorsValue[which]);
textView.setText("当前颜色为:" +content[which]);
})).show();}});
MyPaint.java
public class MyPaint {
public Paint paint;
public Path path;
public MyPaint() {
paint = new Paint();
paint.setColor(0xFF000000); // 黑色
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
paint.setAntiAlias(true);
path = new Path(); }
public void resetPath() {
path.reset(); }}
MyView.java
package com.example.test;
public class MyView extends View {
private List<MyPaint> paints = new ArrayList<>();
private MyPaint currentPaint;
private void init() {
currentPaint = new MyPaint();
paints.add(currentPaint);
}
// 设置当前画笔颜色
public void setCurrentPaintColor(int color) {
currentPaint = new MyPaint(); // 新建一个 MyPaint,防止原来画的也变色了
currentPaint.paint.setColor(color);
paints.add(currentPaint);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (MyPaint mp : paints) {
canvas.drawPath(mp.path, mp.paint);} }
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
currentPaint.path.moveTo(x, y);
break;
case MotionEvent.ACTION_MOVE:
currentPaint.path.lineTo(x, y);
invalidate(); // 刷新界面
break; }
return true;}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();// 系统在从 XML 加载 View 时默认调用的构造函数
}
public void clearCanvas() {
for (MyPaint mp : paints) {
mp.resetPath();
} // 清屏方法
invalidate();}}
2、绘制矩形和线条
MyPaint.java
public class MyPaint {
public Paint paint = new Paint();
public Path path = new Path();
public boolean isRect = false;
public float startX, startY, endX, endY;//按下(startX/startY) 和 松开(endX/endY)
public MyPaint() {
paint.setAntiAlias(true);
paint.setStrokeWidth(8);
paint.setStyle(Paint.Style.STROKE); }
public RectF getRectF() {//左上右下四个边界
return new RectF(Math.min(startX, endX), Math.min(startY, endY),
Math.max(startX, endX), Math.max(startY, endY)); }
public void resetPath() {
path.reset();}}
MyView.java
public class MyView extends View {有两个参数,同上初始化。
private boolean drawRectMode = false; // 是否为矩形绘图模式
private int currentColor = 0xFF000000; // 当前颜色,默认黑色
public MyView(Context context, AttributeSet attrs) {
super(context, attrs); }
public void setDrawRectMode(boolean drawRect) { // 设置是否画矩形
this.drawRectMode = drawRect; }
public void setCurrentPaintColor(int color) {// 设置当前颜色,仅记录颜色,不创建画笔
this.currentColor = color;}
public void clearCanvas() {
paints.clear(); // 清空所有绘制内容
invalidate(); }
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (MyPaint mp : paints) {//遍历之前画的每一笔
if (mp.isRect) {
canvas.drawRect(mp.getRectF(), mp.paint); // 画矩形
} else {
canvas.drawPath(mp.path, mp.paint); // 画线条} }}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
if (drawRectMode) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
currentPaint = new MyPaint();
currentPaint.isRect = true;
currentPaint.paint.setColor(currentColor); // 设置颜色
currentPaint.startX = x;
currentPaint.startY = y;
paints.add(currentPaint);
break;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
currentPaint.endX = x;
currentPaint.endY = y;
invalidate();
break;}} else {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
currentPaint = new MyPaint();
currentPaint.paint.setColor(currentColor); // 设置颜色
currentPaint.path.moveTo(x, y);
paints.add(currentPaint);
break;
case MotionEvent.ACTION_MOVE:
currentPaint.path.lineTo(x, y); // 画线到当前位置
invalidate();
break;}}return true; }}
实验7 从网络获取数据并进行JSON解析
MainActivity.java
public class MainActivity extends AppCompatActivity {
EditText mEditWeather;
TextView mTextCityName,mTextTemp,mTextPres,mTextHumidity;
CheckBox TempBox,PresBox,HumiBox;
Button mButtonFresh;
WeatherTask mCurrentTask;
String temp="",pres="",humidity="";
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);(这里省略了组件初始化,考试要写上!)
TempBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (TempBox.isChecked())
mTextTemp.setText(temp+"C");
else
mTextTemp.setText("");
}
});//PresBox,HumiBox同理,但设置文字内容不同。
mButtonFresh.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mCurrentTask=new WeatherTask();
mCurrentTask.execute(mEditWeather.getText().toString()); } }); }
class WeatherTask extends AsyncTask<String,Void,DataGet.WeatherResult> {
@Override//在后台异步获取天气信息
protected DataGet.WeatherResult doInBackground(String... params){
DataGet dataGet =new DataGet();
return dataGet.getWeatherDate(params[0]); }
@Override
protected void onPostExecute(DataGet.WeatherResult weatherResult){
super.onPostExecute(weatherResult);
if(weatherResult.getErrorCode()==0){
DecimalFormat df=new DecimalFormat("00.00");
temp=df.format(weatherResult.getCurTemp());
pres=weatherResult.getCurPres()+" ";
humidity = weatherResult.getCurHumidity()+" ";
mTextCityName.setText("城市:"+weatherResult.getCityName());}}}
protected void onDestroy(){
if(mCurrentTask!=null){
mCurrentTask.cancel(true);
mCurrentTask=null;}
super.onDestroy();}}
DataGet.java
public class DataGet {
public class WeatherResult{
private float curTemp;
private float curPres;
private float curHumidity;
private int errorCode;
private String cityName;
public String getCityName() {return cityName;}
public void setCityName(String cityName) {
this.cityName = cityName;
}
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public float getCurTemp() {
return curTemp;
}
public void setCurTemp(float curTemp) {
this.curTemp = curTemp;
}
public float getCurPres() {
return curPres;
}
public void setCurPres(float curPres) {
this.curPres = curPres;
}
public float getCurHumidity() {
return curHumidity;
}
public void setCurHumidity(float curHumidity) {
this.curHumidity = curHumidity;
}
}
private static final String WEATHER_URL="http://api.openweathermap.org/data/2.5/weather?";
private static final String MyKey="6ca97ce186cc05e94b2ad45ed2a39eea";
private float tranformToC(float abs){
return(abs - 273.15f);
}
public WeatherResult getWeatherDate(String cityName){
WeatherResult weatherResult=new WeatherResult();
try{
String urlString=WEATHER_URL+"q="+cityName+"&APPID="+MyKey;
Log.i("DataGet",urlString);
URL url=new URL(urlString);
HttpURLConnection connection=(HttpURLConnection)url.openConnection();
InputStream in=connection.getInputStream();
StringBuffer stringBuffer=new StringBuffer();
int c=0;
while ((c=in.read())!=-1){
stringBuffer.append((char) c);
}
Log.i("DataGet",stringBuffer.toString());
WeatherParse weatherParse=new WeatherParse();
weatherParse.setData(stringBuffer.toString());
weatherResult.setCurTemp(tranformToC(weatherParse.getCurTemp()));
weatherResult.setCityName(cityName);
weatherResult.setCurPres(weatherParse.getCurPres());
weatherResult.setCurHumidity(weatherParse.getCurHumidity());
weatherResult.setErrorCode(0);
return weatherResult;
}catch (IOException e){
e.printStackTrace();
} return weatherResult;}}
WeatherParse.java
public class WeatherParse {
private float curTemp=0;
private static final String MAIN_KEY="main";
private static final String CUR_TEMP_KEY="temp";
private static final String CUR_PRES_KEY="pressure";
private float curPres=0;
private float curHumidity=0;
private static final String CUR_HUMIDITY_KEY="humidity";
public void setData(String weatherInfo){
try{
JSONObject object=new JSONObject(weatherInfo);
object=object.getJSONObject(MAIN_KEY);
curTemp=(float) object.getDouble(CUR_TEMP_KEY);
curPres=(float) object.getDouble(CUR_PRES_KEY);
curHumidity=(float) object.getDouble(CUR_HUMIDITY_KEY);
}catch (JSONException e){
e.printStackTrace();
}
}
public float getCurTemp() {
return curTemp; }
public float getCurPres() {
return curPres; }
public float getCurHumidity() {
return curHumidity;}}
实验8
- SQLiteDataBase(第13章 数据存储)的增删改查
public class MainActivity extends AppCompatActivity {
String name;String phone;SQLiteDatabase db;ContentValues values;MyHelper myHelper;
@Override(上下省略了组件的变量声明)
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
myHelper=new MyHelper(this);
mButtonAdd.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
name=mEditTextName.getText().toString();
phone=mEditTextPhone.getText().toString();
db=myHelper.getWritableDatabase();
values=new ContentValues();//键值对容器 ContentValues,用于封装要插入的数据
values.put("name",name);
values.put("phone",phone);
db.insert("information",null,values);//增
db.close();}});
mButtonQuery.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
db=myHelper.getReadableDatabase();
Cursor cursor=db.query("information",null,null,null,null,null,null);
if(cursor.getCount()==0){
mTextViewShow.setText("");
}
else{
cursor.moveToFirst();
// 从游标中读取第2列(name)和第3列(phone)的数据。第一列是id,索引从0开始。
mTextViewShow.setText("Name : "+cursor.getString(1)+" ;Tel :"+cursor.getString(2));}
while (cursor.moveToNext()){
mTextViewShow.append("\n"+"Name : "+cursor.getString(1)+" ;Tel : "+cursor.getString(2));}
cursor.close();
db.close();}});
mButtonUpdate.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
db=myHelper.getWritableDatabase();
values=new ContentValues();
values.put("phone",phone=mEditTextPhone.getText().toString());
db.update("information", values, "name=?", new String[]{mEditTextName.getText().toString()});
db.close();}});
mButtonDelete.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
db=myHelper.getWritableDatabase();
db.delete("information",null,null);
mTextViewShow.setText("");
db.close();}});
}
// 创建或者打开数据库itcast,同时在数据库中创建表information
class MyHelper extends SQLiteOpenHelper{
public MyHelper(Context context){
super(context,"itcast.db",null,1);}
public void onCreate(SQLiteDatabase sqLiteDatabase){
sqLiteDatabase.execSQL("CREATE TABLE information(_id INTEGER PRIMARY KEY AUTOINCREMENT,"+"NAME varchar(20),phone VARCHAR(20))");}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}}}
- 拦截指定电话
(1)注意!Manifest.xml文件要新增权限和组件。<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<uses-feature android:name="android.hardware.telephony" android:required="false"/>
<receiver
android:name=".OutCallReceiver"
android:exported="true"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
(2)MainActivty.java
public class MainActivity extends AppCompatActivity {
private EditText mEditTextInputNumber;
private Button mButtonInputNumber;
private SharedPreferences sp;
// 手动定义权限常量(因为高版本 SDK 中已经删除)
private static final String PERMISSION_PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
sp = getSharedPreferences("config",MODE_PRIVATE);
mEditTextInputNumber =findViewById(R.id.edittext_input_number);
mButtonInputNumber =findViewById(R.id.button_input_number);
mButtonInputNumber.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (Build.VERSION.SDK_INT >= 23) {//检查并动态请求"拨出电话监听权限"
if (checkSelfPermission(PERMISSION_PROCESS_OUTGOING_CALLS) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{PERMISSION_PROCESS_OUTGOING_CALLS}, 0);}}
// 获取用户输入的拦截号码
String number = mEditTextInputNumber.getText().toString().trim();
// 保存拦截号码到 SharedPreferences
SharedPreferences.Editor editor = sp.edit();
editor.putString("number", number);
editor.commit();
Toast.makeText(MainActivity.this, "保存成功", Toast.LENGTH_SHORT).show();
} });}}
OutCallReceiver.java
public class OutCallReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 获取拨打的电话号码。getResultData() 是 BroadcastReceiver 提供的方法,用于获取当前广播处理链中传递的数据
String outcallNumber = getResultData();
// 创建 SharedPreferences 对象,获取拦截号码
SharedPreferences sp = context.getSharedPreferences("config", Context.MODE_PRIVATE);
String number = sp.getString("number", "");
// 判断是否是拦截电话号码
if (outcallNumber != null && outcallNumber.equals(number)) {
// 清除拨号操作(即取消拨打电话)
setResultData(null);}}}